| !===================================================================== | |
| ! 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 | |