sov-kernel-monster / src /bob_circuit.f90
SNAPKITTYWEST's picture
chore: push full sov-kernel-monster content from local build
9425aed verified
Raw
History Blame Contribute Delete
30.5 kB
!=====================================================================
! bob_circuit.f90
! Quantum circuit IR: Gate, Qubit, Circuit, Measurement
! QFT, Grover, Shor, QPE algorithms compiled to flat circuit IR.
! Matches utqc-core/src/lib.rs + utqc-quantum/src/lib.rs exactly.
! Standard: Fortran 2018
!
! PHASE 1 HARDENING (Correctness First)
! ─────────────────────────────────────
! This module implements critical bug fixes and scaffolding documentation:
!
! 1. Circuit Depth Fixes (Tasks 1.2, 2.1):
! - Renamed: circuit_depth() β†’ gate_count() [counts gates, not depth]
! - Added: logical_depth() [computes proper critical-path depth]
! - Deprecated: circuit_depth() β†’ now calls logical_depth() for backwards compat
!
! 2. New Gate Types (Task 2.3):
! - GATE_RX, GATE_RY, GATE_RZ: explicit rotation axes (not ambiguous)
! - Documentation: semantics and decomposition formulas
!
! 3. Exact Inverse QFT (Task 2.2):
! - New function: circuit_exact_inverse_qft() [full controlled-phase gates]
! - Status: IN_PROGRESS_SCAFFOLD [proper QFT† with 2Ο€/2^k phases]
! - Reference: Nielsen & Chuang Β§5.1
!
! 4. Scaffold Documentation:
! - circuit_qft(): Simplified (not full QFT, angle factor off by 2Ο€)
! - circuit_grover(): Hardcoded oracle (not programmable)
! - circuit_qpe(): Uses H layer, not inverse QFT
! - circuit_shor(): Period-finding only (no modular exponentiation)
! - Details: see SCAFFOLDS_IN_PROGRESS.md
!
! 5. Phase 1B TODO (Classical Control IR):
! - GATE_MEASURE_STORE, GATE_COND_GATE type codes defined
! - Semantic issue: measurement results cannot be distinguished from quantum controls
! - Workaround: see circuit_teleportation comments
! - Fix: Phase 1B will add separate classical control IR
!
! See: SCAFFOLDS_IN_PROGRESS.md for full documentation of known gaps
!=====================================================================
module bob_circuit
use, intrinsic :: iso_c_binding, only: c_int32_t, c_int64_t, c_double, &
c_ptr, c_f_pointer, c_loc, c_size_t, c_associated
use, intrinsic :: iso_fortran_env, only: int64, real64, int32
use bob_kinds
use bob_errors
implicit none
private
!──────────────────────────────────────────────────────────────────
! Gate type codes (matches utqc-core SingleGate + DoubleGate enums)
!──────────────────────────────────────────────────────────────────
integer(i4), parameter, public :: GATE_PAULI_X = 0
integer(i4), parameter, public :: GATE_PAULI_Y = 1
integer(i4), parameter, public :: GATE_PAULI_Z = 2
integer(i4), parameter, public :: GATE_HADAMARD = 3
integer(i4), parameter, public :: GATE_T = 4
integer(i4), parameter, public :: GATE_S = 5
! Explicit rotation gates (single-qubit, angle in radians)
integer(i4), parameter, public :: GATE_RX = 10 ! Rotation around X axis: Rx(ΞΈ) = [[cos(ΞΈ/2), -iΒ·sin(ΞΈ/2)], [...]]
integer(i4), parameter, public :: GATE_RY = 11 ! Rotation around Y axis: Ry(ΞΈ) = [[cos(ΞΈ/2), -sin(ΞΈ/2)], [...]]
integer(i4), parameter, public :: GATE_RZ = 12 ! Rotation around Z axis: Rz(ΞΈ) = [[exp(-iΒ·ΞΈ/2), 0], [0, exp(iΒ·ΞΈ/2)]]
! Parameterized gate (deprecated - use explicit RX/RY/RZ instead)
integer(i4), parameter, public :: GATE_ROTATION = 200 ! Generic rotation (DEPRECATED - prefer RX/RY/RZ)
! Two-qubit gates
integer(i4), parameter, public :: GATE_CNOT = 100
integer(i4), parameter, public :: GATE_CZ = 101
integer(i4), parameter, public :: GATE_SWAP = 102
! Measurement gates
integer(i4), parameter, public :: GATE_MEASURE = 300
! Classical control gates (Phase 1B TODO)
integer(i4), parameter, public :: GATE_MEASURE_STORE = 301 ! Measure qubit to classical bit (Phase 1B)
integer(i4), parameter, public :: GATE_COND_GATE = 302 ! Conditional quantum gate (Phase 1B)
!> Maximum gates in one circuit
integer(i4), parameter, public :: MAX_CIRCUIT_GATES = 65536
!> Maximum qubits
integer(i4), parameter, public :: MAX_QUBITS = 64
!> A single gate operation
type, public :: bob_gate_t
integer(i4) :: gate_type = 0 ! GATE_* constant
integer(i4) :: target = -1 ! target qubit (0-indexed)
integer(i4) :: control = -1 ! control qubit (-1 = none)
real(wp) :: angle = ZERO ! rotation angle (radians)
integer(i4) :: classical = -1 ! classical bit for measurement
end type bob_gate_t
!> Flat quantum circuit IR (non-recursive β€” matches utqc-core Circuit)
type, public :: bob_circuit_t
integer(i4) :: num_qubits = 0
integer(i4) :: num_classical = 0
integer(i4) :: num_gates = 0
integer(i4) :: num_measurements= 0
type(bob_gate_t) :: gates(MAX_CIRCUIT_GATES)
logical(lk) :: is_valid = .false.
contains
procedure :: add_gate => circuit_add_gate
procedure :: add_measure => circuit_add_measure
procedure :: gate_count => circuit_gate_count
procedure :: logical_depth => circuit_logical_depth
procedure :: depth => circuit_depth ! Deprecated: use logical_depth()
procedure :: validate => circuit_validate
procedure :: reset => circuit_reset
end type bob_circuit_t
public :: circuit_new
public :: circuit_qft
public :: circuit_grover
public :: circuit_qpe
public :: circuit_shor
public :: circuit_bell_pair
public :: circuit_teleportation
public :: circuit_exact_inverse_qft ! New: Task 2.2
public :: grover_optimal_iterations
! C ABI
public :: bob_circuit_new
public :: bob_circuit_qft
public :: bob_circuit_grover
public :: bob_circuit_gate_count ! New: Task 1.2
public :: bob_circuit_logical_depth ! New: Task 2.1
public :: bob_circuit_depth ! Deprecated wrapper for backwards compat
public :: bob_circuit_free
contains
!──────────────────────────────────────────────────────────────────
! Constructor
!──────────────────────────────────────────────────────────────────
pure function circuit_new(num_qubits, num_classical) result(c)
integer(i4), intent(in) :: num_qubits, num_classical
type(bob_circuit_t) :: c
c%num_qubits = num_qubits
c%num_classical = num_classical
c%num_gates = 0
c%is_valid = .true.
end function circuit_new
subroutine circuit_reset(this)
class(bob_circuit_t), intent(inout) :: this
this%num_gates = 0
this%num_measurements= 0
this%is_valid = .true.
end subroutine circuit_reset
!──────────────────────────────────────────────────────────────────
! Add a gate
!──────────────────────────────────────────────────────────────────
subroutine circuit_add_gate(this, gate_type, target, control, angle, status)
class(bob_circuit_t), intent(inout) :: this
integer(i4), intent(in) :: gate_type, target
integer(i4), intent(in), optional :: control
real(wp), intent(in), optional :: angle
integer(i4), intent(out), optional :: status
integer(i4) :: st
st = BOB_SUCCESS
if (.not. this%is_valid) then; st = BOB_ERROR_INVALID_STATE; goto 99; end if
if (this%num_gates >= MAX_CIRCUIT_GATES) then
call bob_set_error(BOB_ERROR_ALLOCATION, "circuit full", "circuit_add_gate")
st = BOB_ERROR_ALLOCATION; goto 99
end if
if (target < 0 .or. target >= this%num_qubits) then
st = BOB_ERROR_INVALID_ARGUMENT; goto 99
end if
this%num_gates = this%num_gates + 1
this%gates(this%num_gates)%gate_type = gate_type
this%gates(this%num_gates)%target = target
this%gates(this%num_gates)%control = -1
this%gates(this%num_gates)%angle = ZERO
this%gates(this%num_gates)%classical = -1
if (present(control)) this%gates(this%num_gates)%control = control
if (present(angle)) this%gates(this%num_gates)%angle = angle
99 if (present(status)) status = st
end subroutine circuit_add_gate
subroutine circuit_add_measure(this, qubit, classical_bit, status)
class(bob_circuit_t), intent(inout) :: this
integer(i4), intent(in) :: qubit, classical_bit
integer(i4), intent(out), optional :: status
integer(i4) :: st
st = BOB_SUCCESS
if (qubit < 0 .or. qubit >= this%num_qubits) then
st = BOB_ERROR_INVALID_ARGUMENT; goto 99
end if
this%num_gates = this%num_gates + 1
this%gates(this%num_gates)%gate_type = GATE_MEASURE
this%gates(this%num_gates)%target = qubit
this%gates(this%num_gates)%classical = classical_bit
this%num_measurements = this%num_measurements + 1
99 if (present(status)) status = st
end subroutine circuit_add_measure
!> Gate count (total number of gates, not depth)
pure function circuit_gate_count(this) result(d)
class(bob_circuit_t), intent(in) :: this
integer(i4) :: d
d = this%num_gates
end function circuit_gate_count
!> Logical circuit depth: longest critical path accounting for parallelism
!> Algorithm: Track activation layer for each qubit, layer(gate) = 1 + max(layers of involved qubits)
pure function circuit_logical_depth(this) result(d)
class(bob_circuit_t), intent(in) :: this
integer(i4) :: d
integer(i4) :: i, q, layer, max_layer
integer(i4) :: qubit_layer(MAX_QUBITS)
if (this%num_gates == 0) then
d = 0
return
end if
! Initialize all qubit layers to 0
qubit_layer(1:MAX_QUBITS) = 0
max_layer = 0
! Process each gate in order
do i = 1, this%num_gates
layer = 1 ! Each gate starts at layer 1 (after dependencies)
! Find max layer of target qubit
if (this%gates(i)%target >= 0 .and. this%gates(i)%target < this%num_qubits) then
layer = max(layer, qubit_layer(this%gates(i)%target + 1) + 1)
end if
! Find max layer of control qubit (if present and quantum control, not classical)
! Note: classical control (measurement) does not create dependency
if (this%gates(i)%control >= 0 .and. this%gates(i)%control < this%num_qubits) then
! Only create dependency if control is a qubit (control >= 0 and < num_qubits)
! Measurement gates have classical destination, not qubit dependency
if (this%gates(i)%gate_type /= GATE_MEASURE) then
layer = max(layer, qubit_layer(this%gates(i)%control + 1) + 1)
end if
end if
! Update qubit layers
if (this%gates(i)%target >= 0 .and. this%gates(i)%target < this%num_qubits) then
qubit_layer(this%gates(i)%target + 1) = layer
end if
if (this%gates(i)%control >= 0 .and. this%gates(i)%control < this%num_qubits .and. &
this%gates(i)%gate_type /= GATE_MEASURE) then
qubit_layer(this%gates(i)%control + 1) = layer
end if
max_layer = max(max_layer, layer)
end do
d = max_layer
end function circuit_logical_depth
!> Deprecated: Use logical_depth() or gate_count()
pure function circuit_depth(this) result(d)
class(bob_circuit_t), intent(in) :: this
integer(i4) :: d
! For backwards compatibility with C ABI, call logical_depth
d = this%logical_depth()
end function circuit_depth
pure function circuit_validate(this) result(ok)
class(bob_circuit_t), intent(in) :: this
logical :: ok
ok = this%is_valid .and. this%num_gates > 0 .and. this%num_qubits > 0
end function circuit_validate
!══════════════════════════════════════════════════════════════════
! EXACT INVERSE QUANTUM FOURIER TRANSFORM (Phase 1B)
! Implements QFT† = QFT^(-1) with proper controlled-phase gates
! Uses full 2Ο€/2^k phase accumulation (not simplified)
! Reference: Nielsen & Chuang Β§5.1
!
! Circuit structure:
! For each qubit j from 0 to n-1:
! For each qubit k from j+1 to n-1:
! Apply controlled-phase with angle 2Ο€/2^(k-j) (controlled by j, target k)
! Apply Hadamard to qubit j
! (Optional: Apply SWAPs to reverse bit order for standard convention)
!
! Status: IN_PROGRESS_SCAFFOLD
! Known limitation: This is the inverse QFT; compositions with QPE require
! proper modular exponentiation in the forward QFT.
!══════════════════════════════════════════════════════════════════
function circuit_exact_inverse_qft(num_qubits, start) result(c)
integer(i4), intent(in) :: num_qubits, start
type(bob_circuit_t) :: c
integer(i4) :: i, j, st, k_exp
real(wp) :: angle
c = circuit_new(num_qubits, num_qubits)
! Inverse QFT: Process qubits from 0 to n-1
! (Inverse because controlled-phases are in reverse order vs. forward QFT)
do i = 0, num_qubits - 1
! Controlled-phase rotations from higher-index qubits to this qubit
do j = i + 1, num_qubits - 1
! Phase angle: 2Ο€ / 2^(j-i) = 2Ο€ * 2^(-(j-i))
k_exp = j - i
! angle = 2Ο€ / 2^k_exp (computed via bit shift for accuracy)
angle = TWO * PI / real(ishft(1_i4, k_exp), wp)
! Apply controlled-phase: CPhase(angle) controlled by qubit (start+i), target (start+j)
! Implementation: Use RZ gate with proper control
! Note: CPhase(θ) controlled by |1⟩ on control qubit
! For now, use GATE_RZ with control field (Phase 1 limitation)
! TODO: Implement proper controlled-phase gate in Phase 1B
call c%add_gate(GATE_RZ, start + j, control=start + i, angle=angle, status=st)
end do
! Hadamard on this qubit
call c%add_gate(GATE_HADAMARD, start + i, status=st)
end do
! Optional: SWAP qubits to reverse bit order (standard QFT convention)
! This makes the QFT match textbook form where qubit 0 is most significant
do i = 0, (num_qubits - 1) / 2
if (i /= num_qubits - 1 - i) then
call c%add_gate(GATE_SWAP, start + i, &
control=start + num_qubits - 1 - i, status=st)
end if
end do
end function circuit_exact_inverse_qft
!══════════════════════════════════════════════════════════════════
! QUANTUM FOURIER TRANSFORM (Phase 1 Scaffold)
! QFT on num_qubits starting at qubit 'start'
! Matches utqc-quantum Qft::circuit exactly
!
! Status: IN_PROGRESS_SCAFFOLD (see SCAFFOLDS_IN_PROGRESS.md)
! Known limitations:
! 1. Uses simplified Hadamard layer + phase rotations (not standard QFT†)
! 2. Angle = Ο€/2^(j-i), NOT 2Ο€/2^(j-i) (missing factor of 2)
! 3. Uses CNOT+ROTATION instead of proper CPhase gate
! 4. Includes measurements (makes circuit non-composable)
! 5. Not suitable for use within QPE (see circuit_exact_inverse_qft instead)
!
! This circuit is adequate for demonstrating compiler pipeline.
! Phase 2 will implement full QFT with proper controlled-phase gates.
!══════════════════════════════════════════════════════════════════
function circuit_qft(num_qubits, start) result(c)
integer(i4), intent(in) :: num_qubits, start
type(bob_circuit_t) :: c
integer(i4) :: i, j, st
real(wp) :: angle
c = circuit_new(num_qubits, num_qubits)
do i = 0, num_qubits - 1
! Hadamard on qubit i
call c%add_gate(GATE_HADAMARD, start + i, status=st)
! Controlled phase rotations (SCAFFOLD: simplified, uses CNOT+ROTATION)
do j = i + 1, num_qubits - 1
angle = PI / real(ishft(1_i4, j - i), wp) ! SCAFFOLD: Should be 2Ο€/2^(j-i)
call c%add_gate(GATE_CNOT, start + j, control=start + i, status=st)
call c%add_gate(GATE_ROTATION, start + i, angle=angle, status=st)
end do
end do
! Swap qubits for standard bit ordering
do i = 0, num_qubits / 2 - 1
call c%add_gate(GATE_SWAP, start + i, &
control=start + num_qubits - 1 - i, status=st)
end do
! Measure all (SCAFFOLD: makes circuit non-composable)
do i = 0, num_qubits - 1
call c%add_measure(start + i, i, status=st)
end do
end function circuit_qft
!══════════════════════════════════════════════════════════════════
! GROVER'S SEARCH ALGORITHM (Phase 1 Scaffold)
! Matches utqc-quantum Grover::circuit exactly
!
! Status: IN_PROGRESS_SCAFFOLD (see SCAFFOLDS_IN_PROGRESS.md)
! Known limitations:
! 1. Oracle is HARDCODED: CZ(q_last, control=q_0) only
! 2. Cannot search for arbitrary marked states
! 3. Only demonstrates amplitude amplification structure
! 4. Iteration count formula is correct (grover_optimal_iterations)
! 5. Future: Accept programmable oracle parameter
!
! This circuit demonstrates the iteration structure and counts optimal
! iterations. Phase 2 will allow programmable oracles.
!══════════════════════════════════════════════════════════════════
!> Optimal number of Grover iterations: floor(pi/4 * sqrt(N/M))
pure function grover_optimal_iterations(num_qubits, num_solutions) result(k)
integer(i4), intent(in) :: num_qubits, num_solutions
integer(i4) :: k
real(wp) :: n_states, theta
real(wp), parameter :: QUART = 0.25_wp ! Ο€/4 = Ο€ * 0.25
n_states = real(ishft(1_i4, num_qubits), wp)
theta = asin(sqrt(real(num_solutions, wp) / n_states))
k = max(1, int(PI * QUART / theta, i4))
end function grover_optimal_iterations
function circuit_grover(num_qubits, num_solutions) result(c)
integer(i4), intent(in) :: num_qubits, num_solutions
type(bob_circuit_t) :: c
integer(i4) :: i, iter, iters, st
c = circuit_new(num_qubits, num_qubits)
! Initialize: H on all
do i = 0, num_qubits - 1
call c%add_gate(GATE_HADAMARD, i, status=st)
end do
iters = grover_optimal_iterations(num_qubits, num_solutions)
do iter = 1, iters
! Oracle: CZ on qubit 0 and last qubit (SCAFFOLD: hardcoded, not programmable)
if (num_qubits >= 2) then
call c%add_gate(GATE_CZ, num_qubits - 1, control=0, status=st)
end if
! Diffusion operator: H X CZ X H on all
do i = 0, num_qubits - 1
call c%add_gate(GATE_HADAMARD, i, status=st)
call c%add_gate(GATE_PAULI_X, i, status=st)
end do
if (num_qubits >= 2) then
call c%add_gate(GATE_CZ, num_qubits - 1, control=0, status=st)
end if
do i = 0, num_qubits - 1
call c%add_gate(GATE_PAULI_X, i, status=st)
call c%add_gate(GATE_HADAMARD, i, status=st)
end do
end do
! Measure
do i = 0, num_qubits - 1
call c%add_measure(i, i, status=st)
end do
end function circuit_grover
!══════════════════════════════════════════════════════════════════
! QUANTUM PHASE ESTIMATION (Phase 1 Scaffold)
! num_counting: counting qubits (precision = 2^-num_counting)
! target: index of the eigenstate qubit
! Matches utqc-quantum Qpe::circuit
!
! Status: IN_PROGRESS_SCAFFOLD (see SCAFFOLDS_IN_PROGRESS.md)
! Known limitations:
! 1. Inverse QFT replaced with just Hadamard layer (simplified)
! 2. Correct inverse QFT uses controlled-phase gates (2Ο€/2^k)
! 3. Phase information is not properly extracted into counting register
! 4. Eigenvalue estimation will be inaccurate
! 5. Controlled unitary is simulated with repeated CNOT (not general U)
!
! This circuit demonstrates the phase estimation structure: superposition
! initialization, controlled powers, and measurement. Phase 2 will use
! the exact inverse QFT (circuit_exact_inverse_qft) for correctness.
!══════════════════════════════════════════════════════════════════
function circuit_qpe(num_counting, target_qubit) result(c)
integer(i4), intent(in) :: num_counting, target_qubit
type(bob_circuit_t) :: c
integer(i4) :: total, i, power, p, st
type(bob_circuit_t) :: qft_c
total = num_counting + 1
c = circuit_new(total, num_counting)
! H on counting qubits
do i = 0, num_counting - 1
call c%add_gate(GATE_HADAMARD, i, status=st)
end do
! Controlled U^(2^i) on target (SCAFFOLD: simulated as repeated CNOT)
do i = 0, num_counting - 1
power = ishft(1_i4, i)
do p = 1, power
call c%add_gate(GATE_CNOT, target_qubit, control=i, status=st)
end do
end do
! Inverse QFT on counting qubits (SCAFFOLD: simplified - just H layer, not full QFT†)
! Phase 2: Replace with circuit_exact_inverse_qft() call
do i = 0, num_counting - 1
call c%add_gate(GATE_HADAMARD, i, status=st)
end do
! Measure counting qubits
do i = 0, num_counting - 1
call c%add_measure(i, i, status=st)
end do
end function circuit_qpe
!══════════════════════════════════════════════════════════════════
! SHOR'S ALGORITHM (Phase 1 Scaffold β€” Period Finding Only)
! Builds QPE substructure for period finding
! Matches utqc-quantum Shor::circuit
!
! Status: IN_PROGRESS_SCAFFOLD (see SCAFFOLDS_IN_PROGRESS.md)
! What's implemented:
! - Period-finding subroutine via QPE
! - Qubit allocation (counting qubits = num_qubits/2)
!
! What's stubbed (nearly everything):
! 1. Modular exponentiation circuit (reversible a^x mod N)
! 2. Quantum order-finding (currently just delegates to QPE)
! 3. Classical reduction via Euclidean algorithm
! 4. Integer factorization (extracting factors from period)
!
! This circuit is only the quantum period-finding part. The full
! Shor algorithm requires classical post-processing to convert
! the period r into factors of N via gcd(a^(r/2) Β± 1, N).
!
! Phase 2 will implement:
! - Reversible modular exponentiation
! - Full factorization loop
! - Classical reduction phase
!══════════════════════════════════════════════════════════════════
function circuit_shor(num_qubits) result(c)
integer(i4), intent(in) :: num_qubits
type(bob_circuit_t) :: c
integer(i4) :: counting
counting = max(1, num_qubits / 2)
! Shor's algorithm = Period finding via QPE
! (Full algorithm requires classical post-processing and modular exponentiation)
c = circuit_qpe(counting, counting)
end function circuit_shor
!══════════════════════════════════════════════════════════════════
! BELL PAIR (2-qubit entangled state)
! |Φ+⟩ = (|00⟩ + |11⟩)/√2
!══════════════════════════════════════════════════════════════════
function circuit_bell_pair() result(c)
type(bob_circuit_t) :: c
integer(i4) :: st
c = circuit_new(2, 2)
call c%add_gate(GATE_HADAMARD, 0, status=st)
call c%add_gate(GATE_CNOT, 1, control=0, status=st)
call c%add_measure(0, 0, status=st)
call c%add_measure(1, 1, status=st)
end function circuit_bell_pair
!══════════════════════════════════════════════════════════════════
! QUANTUM TELEPORTATION (3 qubits) β€” Known Semantic Issue
! |ψ⟩ on qubit 0 teleported to qubit 2 via entangled pair (1,2)
!
! SEMANTIC BUG (Phase 1B TODO):
! Lines with control=0 and control=1 after measurements are INCORRECT.
! The IR conflates:
! - Quantum control: gate applied if control qubit is |1⟩
! - Classical control: gate applied if measurement result == 1
!
! Current code:
! call c%add_measure(0, 0, status=st) ! Measure q0 β†’ c0 (classical bit)
! call c%add_gate(GATE_PAULI_Z, 2, control=0, status=st) ! control=0 is qubit 0, not bit!
!
! This is interpreted as: "if qubit 0 is in |1⟩, apply Z to qubit 2"
! But measurement already collapsed qubit 0. The intent is:
! "if measurement result of bit c0 is 1, apply Z to qubit 2"
!
! WORKAROUND (Phase 1):
! For now, interpret control field on post-measurement gates as classical
! (requires runtime to enforce measurement-before-use).
! The circuit logic is correct; only the IR semantics are ambiguous.
!
! FIX (Phase 1B):
! Use GATE_COND_GATE with separate classical condition specification:
! call c%add_gate(GATE_MEASURE_STORE, 0, classical=0, status=st)
! call c%add_gate(GATE_COND_GATE, 2, gate_type=GATE_PAULI_Z, &
! classical_condition=0, status=st)
!
! See: SCAFFOLDS_IN_PROGRESS.md Β§ "Teleportation Semantic Bug"
!══════════════════════════════════════════════════════════════════
function circuit_teleportation() result(c)
type(bob_circuit_t) :: c
integer(i4) :: st
c = circuit_new(3, 3)
! Prepare Bell pair on qubits 1,2
call c%add_gate(GATE_HADAMARD, 1, status=st)
call c%add_gate(GATE_CNOT, 2, control=1, status=st)
! Alice's operations on qubits 0,1
call c%add_gate(GATE_CNOT, 1, control=0, status=st)
call c%add_gate(GATE_HADAMARD, 0, status=st)
! Measure Alice's qubits
call c%add_measure(0, 0, status=st)
call c%add_measure(1, 1, status=st)
! Bob's corrections (conditional X and Z)
! NOTE: These control fields should be interpreted as classical conditions
! (see semantic bug above). Phase 1B will clarify with separate IR types.
call c%add_gate(GATE_PAULI_X, 2, control=1, status=st)
call c%add_gate(GATE_PAULI_Z, 2, control=0, status=st)
call c%add_measure(2, 2, status=st)
end function circuit_teleportation
!══════════════════════════════════════════════════════════════════
! C ABI
!══════════════════════════════════════════════════════════════════
function bob_circuit_new(num_qubits, num_classical) result(ptr) &
bind(C, name="bob_circuit_new")
integer(c_int32_t), value :: num_qubits, num_classical
type(c_ptr) :: ptr
type(bob_circuit_t), pointer :: c
allocate(c)
c = circuit_new(int(num_qubits,i4), int(num_classical,i4))
ptr = c_loc(c)
end function bob_circuit_new
function bob_circuit_qft(num_qubits, start) result(ptr) &
bind(C, name="bob_circuit_qft")
integer(c_int32_t), value :: num_qubits, start
type(c_ptr) :: ptr
type(bob_circuit_t), pointer :: c
allocate(c)
c = circuit_qft(int(num_qubits,i4), int(start,i4))
ptr = c_loc(c)
end function bob_circuit_qft
function bob_circuit_grover(num_qubits, num_solutions) result(ptr) &
bind(C, name="bob_circuit_grover")
integer(c_int32_t), value :: num_qubits, num_solutions
type(c_ptr) :: ptr
type(bob_circuit_t), pointer :: c
allocate(c)
c = circuit_grover(int(num_qubits,i4), int(num_solutions,i4))
ptr = c_loc(c)
end function bob_circuit_grover
function bob_circuit_gate_count(circ_ptr) result(d) bind(C, name="bob_circuit_gate_count")
type(c_ptr), value :: circ_ptr
integer(c_int32_t) :: d
type(bob_circuit_t), pointer :: c
if (.not. c_associated(circ_ptr)) then; d = 0; return; end if
call c_f_pointer(circ_ptr, c)
d = c%gate_count()
end function bob_circuit_gate_count
function bob_circuit_logical_depth(circ_ptr) result(d) bind(C, name="bob_circuit_logical_depth")
type(c_ptr), value :: circ_ptr
integer(c_int32_t) :: d
type(bob_circuit_t), pointer :: c
if (.not. c_associated(circ_ptr)) then; d = 0; return; end if
call c_f_pointer(circ_ptr, c)
d = c%logical_depth()
end function bob_circuit_logical_depth
function bob_circuit_depth(circ_ptr) result(d) bind(C, name="bob_circuit_depth")
type(c_ptr), value :: circ_ptr
integer(c_int32_t) :: d
type(bob_circuit_t), pointer :: c
if (.not. c_associated(circ_ptr)) then; d = 0; return; end if
call c_f_pointer(circ_ptr, c)
! Deprecated: Now calls logical_depth() for correctness
d = c%logical_depth()
end function bob_circuit_depth
subroutine bob_circuit_free(circ_ptr) bind(C, name="bob_circuit_free")
type(c_ptr), value :: circ_ptr
type(bob_circuit_t), pointer :: c
if (.not. c_associated(circ_ptr)) return
call c_f_pointer(circ_ptr, c)
deallocate(c)
end subroutine bob_circuit_free
end module bob_circuit
! Made with Bob