File size: 18,432 Bytes
9425aed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
! BOB Quantum Civilization Engine - Quantum Gates
! Module: bob_gates
! Purpose: Complete quantum gate operations (Pauli, Hadamard, T, controlled gates)
! Standard: Fortran 2018

module bob_gates
    use bob_kinds
    use bob_errors
    use bob_state
    implicit none
    private
    
    ! Gate types
    integer(i4), parameter, public :: GATE_I = 0      ! Identity
    integer(i4), parameter, public :: GATE_X = 1      ! Pauli X (NOT)
    integer(i4), parameter, public :: GATE_Y = 2      ! Pauli Y
    integer(i4), parameter, public :: GATE_Z = 3      ! Pauli Z
    integer(i4), parameter, public :: GATE_H = 4      ! Hadamard
    integer(i4), parameter, public :: GATE_S = 5      ! S gate (phase)
    integer(i4), parameter, public :: GATE_T = 6      ! T gate (π/8)
    integer(i4), parameter, public :: GATE_CNOT = 7   ! Controlled-NOT
    integer(i4), parameter, public :: GATE_CZ = 8     ! Controlled-Z
    integer(i4), parameter, public :: GATE_SWAP = 9   ! SWAP
    integer(i4), parameter, public :: GATE_RX = 10    ! Rotation X
    integer(i4), parameter, public :: GATE_RY = 11    ! Rotation Y
    integer(i4), parameter, public :: GATE_RZ = 12    ! Rotation Z
    
    ! Pauli matrices
    complex(cwp), parameter :: PAULI_I(2,2) = reshape([ &
        CONE, CZERO, &
        CZERO, CONE], [2,2])
    
    complex(cwp), parameter :: PAULI_X(2,2) = reshape([ &
        CZERO, CONE, &
        CONE, CZERO], [2,2])
    
    complex(cwp), parameter :: PAULI_Y(2,2) = reshape([ &
        CZERO, -CI, &
        CI, CZERO], [2,2])
    
    complex(cwp), parameter :: PAULI_Z(2,2) = reshape([ &
        CONE, CZERO, &
        CZERO, -CONE], [2,2])
    
    public :: apply_single_qubit_gate
    public :: apply_two_qubit_gate
    public :: apply_rotation_gate
    public :: apply_controlled_gate
    public :: apply_arbitrary_unitary
    public :: verify_unitary
    
contains

    !> Apply single-qubit gate to state
    subroutine apply_single_qubit_gate(state, gate_type, qubit_index)
        type(bob_quantum_state), intent(inout) :: state
        integer(i4), intent(in) :: gate_type
        integer(i8), intent(in) :: qubit_index
        
        complex(cwp) :: gate_matrix(2,2)
        complex(cwp) :: new_amplitudes(state%dim)
        integer(i8) :: i, j, k, bit_mask, qubit_bit
        integer(i8) :: num_qubits, state_0, state_1
        complex(cwp) :: amp_0, amp_1
        
        if (.not. state%is_valid) then
            call bob_set_error(BOB_ERROR_INVALID_STATE, &
                "Cannot apply gate to invalid state", "apply_single_qubit_gate")
            return
        end if
        
        ! Get gate matrix
        select case (gate_type)
        case (GATE_I)
            gate_matrix = PAULI_I
        case (GATE_X)
            gate_matrix = PAULI_X
        case (GATE_Y)
            gate_matrix = PAULI_Y
        case (GATE_Z)
            gate_matrix = PAULI_Z
        case (GATE_H)
            ! Hadamard: (1/√2) * [[1, 1], [1, -1]]
            gate_matrix(1,1) = CONE / sqrt(TWO)
            gate_matrix(1,2) = CONE / sqrt(TWO)
            gate_matrix(2,1) = CONE / sqrt(TWO)
            gate_matrix(2,2) = -CONE / sqrt(TWO)
        case (GATE_S)
            ! S gate: [[1, 0], [0, i]]
            gate_matrix(1,1) = CONE
            gate_matrix(1,2) = CZERO
            gate_matrix(2,1) = CZERO
            gate_matrix(2,2) = CI
        case (GATE_T)
            ! T gate: [[1, 0], [0, exp(iπ/4)]]
            gate_matrix(1,1) = CONE
            gate_matrix(1,2) = CZERO
            gate_matrix(2,1) = CZERO
            gate_matrix(2,2) = exp(CI * PI / 4.0_wp)
        case default
            call bob_set_error(BOB_ERROR_INVALID_GATE, &
                "Unknown gate type", "apply_single_qubit_gate")
            return
        end select
        
        ! Calculate number of qubits
        num_qubits = int(log(real(state%dim, wp)) / log(TWO), i8)
        
        if (qubit_index < 0 .or. qubit_index >= num_qubits) then
            call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, &
                "Qubit index out of range", "apply_single_qubit_gate")
            return
        end if
        
        ! Apply gate to each basis state
        bit_mask = ishft(1_i8, int(qubit_index))
        
        do i = 0, state%dim - 1
            qubit_bit = iand(i, bit_mask)
            
            if (qubit_bit == 0) then
                ! This basis state has qubit in |0⟩
                state_0 = i
                state_1 = ior(i, bit_mask)
                
                amp_0 = state%amplitudes(state_0 + 1)
                amp_1 = state%amplitudes(state_1 + 1)
                
                ! Apply gate matrix
                new_amplitudes(state_0 + 1) = gate_matrix(1,1) * amp_0 + gate_matrix(1,2) * amp_1
                new_amplitudes(state_1 + 1) = gate_matrix(2,1) * amp_0 + gate_matrix(2,2) * amp_1
            end if
        end do
        
        state%amplitudes = new_amplitudes
        state%is_normalized = .false.
        
        call bob_clear_error()
    end subroutine apply_single_qubit_gate
    
    !> Apply two-qubit gate
    subroutine apply_two_qubit_gate(state, gate_type, control_qubit, target_qubit)
        type(bob_quantum_state), intent(inout) :: state
        integer(i4), intent(in) :: gate_type
        integer(i8), intent(in) :: control_qubit, target_qubit
        
        complex(cwp) :: new_amplitudes(state%dim)
        integer(i8) :: i, control_mask, target_mask
        integer(i8) :: num_qubits, control_bit, target_bit
        integer(i8) :: state_00, state_01, state_10, state_11
        complex(cwp) :: amp_00, amp_01, amp_10, amp_11
        
        if (.not. state%is_valid) then
            call bob_set_error(BOB_ERROR_INVALID_STATE, &
                "Cannot apply gate to invalid state", "apply_two_qubit_gate")
            return
        end if
        
        num_qubits = int(log(real(state%dim, wp)) / log(TWO), i8)
        
        if (control_qubit < 0 .or. control_qubit >= num_qubits .or. &
            target_qubit < 0 .or. target_qubit >= num_qubits .or. &
            control_qubit == target_qubit) then
            call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, &
                "Invalid qubit indices", "apply_two_qubit_gate")
            return
        end if
        
        control_mask = ishft(1_i8, int(control_qubit))
        target_mask = ishft(1_i8, int(target_qubit))
        
        new_amplitudes = state%amplitudes
        
        select case (gate_type)
        case (GATE_CNOT)
            ! CNOT: flip target if control is |1⟩
            do i = 0, state%dim - 1
                control_bit = iand(i, control_mask)
                
                if (control_bit /= 0) then
                    ! Control is |1⟩, flip target
                    target_bit = iand(i, target_mask)
                    
                    if (target_bit == 0) then
                        state_01 = i
                        state_11 = ior(i, target_mask)
                    else
                        state_11 = i
                        state_01 = iand(i, not(target_mask))
                    end if
                    
                    ! Swap amplitudes
                    amp_01 = state%amplitudes(state_01 + 1)
                    amp_11 = state%amplitudes(state_11 + 1)
                    new_amplitudes(state_01 + 1) = amp_11
                    new_amplitudes(state_11 + 1) = amp_01
                end if
            end do
            
        case (GATE_CZ)
            ! CZ: apply Z to target if control is |1⟩
            do i = 0, state%dim - 1
                control_bit = iand(i, control_mask)
                target_bit = iand(i, target_mask)
                
                if (control_bit /= 0 .and. target_bit /= 0) then
                    ! Both qubits are |1⟩, apply phase flip
                    new_amplitudes(i + 1) = -state%amplitudes(i + 1)
                end if
            end do
            
        case (GATE_SWAP)
            ! SWAP: exchange control and target qubits
            do i = 0, state%dim - 1
                control_bit = iand(i, control_mask)
                target_bit = iand(i, target_mask)
                
                ! Only process each pair once
                if (control_bit == 0 .and. target_bit /= 0) then
                    state_01 = i
                    state_10 = ior(iand(i, not(target_mask)), control_mask)
                    
                    amp_01 = state%amplitudes(state_01 + 1)
                    amp_10 = state%amplitudes(state_10 + 1)
                    new_amplitudes(state_01 + 1) = amp_10
                    new_amplitudes(state_10 + 1) = amp_01
                end if
            end do
            
        case default
            call bob_set_error(BOB_ERROR_INVALID_GATE, &
                "Unknown two-qubit gate type", "apply_two_qubit_gate")
            return
        end select
        
        state%amplitudes = new_amplitudes
        state%is_normalized = .false.
        
        call bob_clear_error()
    end subroutine apply_two_qubit_gate
    
    !> Apply rotation gate
    subroutine apply_rotation_gate(state, gate_type, qubit_index, angle)
        type(bob_quantum_state), intent(inout) :: state
        integer(i4), intent(in) :: gate_type
        integer(i8), intent(in) :: qubit_index
        real(wp), intent(in) :: angle
        
        complex(cwp) :: gate_matrix(2,2)
        real(wp) :: half_angle, cos_half, sin_half
        
        if (.not. state%is_valid) then
            call bob_set_error(BOB_ERROR_INVALID_STATE, &
                "Cannot apply gate to invalid state", "apply_rotation_gate")
            return
        end if
        
        half_angle = angle / TWO
        cos_half = cos(half_angle)
        sin_half = sin(half_angle)
        
        select case (gate_type)
        case (GATE_RX)
            ! RX(θ) = exp(-iθX/2) = [[cos(θ/2), -i*sin(θ/2)], [-i*sin(θ/2), cos(θ/2)]]
            gate_matrix(1,1) = cmplx(cos_half, ZERO, cwp)
            gate_matrix(1,2) = cmplx(ZERO, -sin_half, cwp)
            gate_matrix(2,1) = cmplx(ZERO, -sin_half, cwp)
            gate_matrix(2,2) = cmplx(cos_half, ZERO, cwp)
            
        case (GATE_RY)
            ! RY(θ) = exp(-iθY/2) = [[cos(θ/2), -sin(θ/2)], [sin(θ/2), cos(θ/2)]]
            gate_matrix(1,1) = cmplx(cos_half, ZERO, cwp)
            gate_matrix(1,2) = cmplx(-sin_half, ZERO, cwp)
            gate_matrix(2,1) = cmplx(sin_half, ZERO, cwp)
            gate_matrix(2,2) = cmplx(cos_half, ZERO, cwp)
            
        case (GATE_RZ)
            ! RZ(θ) = exp(-iθZ/2) = [[exp(-iθ/2), 0], [0, exp(iθ/2)]]
            gate_matrix(1,1) = exp(-CI * half_angle)
            gate_matrix(1,2) = CZERO
            gate_matrix(2,1) = CZERO
            gate_matrix(2,2) = exp(CI * half_angle)
            
        case default
            call bob_set_error(BOB_ERROR_INVALID_GATE, &
                "Unknown rotation gate type", "apply_rotation_gate")
            return
        end select
        
        ! Apply as single-qubit gate with custom matrix
        call apply_arbitrary_unitary(state, gate_matrix, qubit_index)
        
        call bob_clear_error()
    end subroutine apply_rotation_gate
    
    !> Apply controlled gate
    subroutine apply_controlled_gate(state, gate_matrix, control_qubit, target_qubit)
        type(bob_quantum_state), intent(inout) :: state
        complex(cwp), intent(in) :: gate_matrix(2,2)
        integer(i8), intent(in) :: control_qubit, target_qubit
        
        complex(cwp) :: new_amplitudes(state%dim)
        integer(i8) :: i, control_mask, target_mask
        integer(i8) :: num_qubits, control_bit, target_bit
        integer(i8) :: state_0, state_1
        complex(cwp) :: amp_0, amp_1
        
        if (.not. state%is_valid) then
            call bob_set_error(BOB_ERROR_INVALID_STATE, &
                "Cannot apply gate to invalid state", "apply_controlled_gate")
            return
        end if
        
        ! Verify gate is unitary
        if (.not. verify_unitary(gate_matrix, 2_i8)) then
            call bob_set_error(BOB_ERROR_NOT_UNITARY, &
                "Gate matrix is not unitary", "apply_controlled_gate")
            return
        end if
        
        num_qubits = int(log(real(state%dim, wp)) / log(TWO), i8)
        
        if (control_qubit < 0 .or. control_qubit >= num_qubits .or. &
            target_qubit < 0 .or. target_qubit >= num_qubits .or. &
            control_qubit == target_qubit) then
            call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, &
                "Invalid qubit indices", "apply_controlled_gate")
            return
        end if
        
        control_mask = ishft(1_i8, int(control_qubit))
        target_mask = ishft(1_i8, int(target_qubit))
        
        new_amplitudes = state%amplitudes
        
        ! Apply gate only when control qubit is |1⟩
        do i = 0, state%dim - 1
            control_bit = iand(i, control_mask)
            
            if (control_bit /= 0) then
                ! Control is |1⟩, apply gate to target
                target_bit = iand(i, target_mask)
                
                if (target_bit == 0) then
                    state_0 = i
                    state_1 = ior(i, target_mask)
                    
                    amp_0 = state%amplitudes(state_0 + 1)
                    amp_1 = state%amplitudes(state_1 + 1)
                    
                    new_amplitudes(state_0 + 1) = gate_matrix(1,1) * amp_0 + gate_matrix(1,2) * amp_1
                    new_amplitudes(state_1 + 1) = gate_matrix(2,1) * amp_0 + gate_matrix(2,2) * amp_1
                end if
            end if
        end do
        
        state%amplitudes = new_amplitudes
        state%is_normalized = .false.
        
        call bob_clear_error()
    end subroutine apply_controlled_gate
    
    !> Apply arbitrary unitary matrix to single qubit
    subroutine apply_arbitrary_unitary(state, gate_matrix, qubit_index)
        type(bob_quantum_state), intent(inout) :: state
        complex(cwp), intent(in) :: gate_matrix(2,2)
        integer(i8), intent(in) :: qubit_index
        
        complex(cwp) :: new_amplitudes(state%dim)
        integer(i8) :: i, bit_mask, qubit_bit
        integer(i8) :: num_qubits, state_0, state_1
        complex(cwp) :: amp_0, amp_1
        
        if (.not. state%is_valid) then
            call bob_set_error(BOB_ERROR_INVALID_STATE, &
                "Cannot apply gate to invalid state", "apply_arbitrary_unitary")
            return
        end if
        
        ! Verify gate is unitary
        if (.not. verify_unitary(gate_matrix, 2_i8)) then
            call bob_set_error(BOB_ERROR_NOT_UNITARY, &
                "Gate matrix is not unitary", "apply_arbitrary_unitary")
            return
        end if
        
        num_qubits = int(log(real(state%dim, wp)) / log(TWO), i8)
        
        if (qubit_index < 0 .or. qubit_index >= num_qubits) then
            call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, &
                "Qubit index out of range", "apply_arbitrary_unitary")
            return
        end if
        
        bit_mask = ishft(1_i8, int(qubit_index))
        
        do i = 0, state%dim - 1
            qubit_bit = iand(i, bit_mask)
            
            if (qubit_bit == 0) then
                state_0 = i
                state_1 = ior(i, bit_mask)
                
                amp_0 = state%amplitudes(state_0 + 1)
                amp_1 = state%amplitudes(state_1 + 1)
                
                new_amplitudes(state_0 + 1) = gate_matrix(1,1) * amp_0 + gate_matrix(1,2) * amp_1
                new_amplitudes(state_1 + 1) = gate_matrix(2,1) * amp_0 + gate_matrix(2,2) * amp_1
            end if
        end do
        
        state%amplitudes = new_amplitudes
        state%is_normalized = .false.
        
        call bob_clear_error()
    end subroutine apply_arbitrary_unitary
    
    !> Verify matrix is unitary: U†U = I
    function verify_unitary(matrix, dim) result(is_unitary)
        integer(i8), intent(in) :: dim
        complex(cwp), intent(in) :: matrix(dim, dim)
        logical(lk) :: is_unitary
        
        complex(cwp) :: product(dim, dim)
        complex(cwp) :: identity(dim, dim)
        integer(i8) :: i, j, k
        real(wp) :: max_error
        
        is_unitary = .false.
        
        ! Compute U†U
        product = CZERO
        do i = 1, dim
            do j = 1, dim
                do k = 1, dim
                    product(i,j) = product(i,j) + conjg(matrix(k,i)) * matrix(k,j)
                end do
            end do
        end do
        
        ! Create identity matrix
        identity = CZERO
        do i = 1, dim
            identity(i,i) = CONE
        end do
        
        ! Check if product equals identity
        max_error = ZERO
        do i = 1, dim
            do j = 1, dim
                max_error = max(max_error, abs(product(i,j) - identity(i,j)))
            end do
        end do
        
        is_unitary = (max_error < TOL_UNITARY)
    end function verify_unitary
    
    !> C ABI: Apply gate to state
    function bob_gate_apply(state_ptr, gate_type, qubit_index) result(status) &
        bind(C, name="bob_gate_apply")
        use, intrinsic :: iso_c_binding
        type(c_ptr), value :: state_ptr
        integer(c_int), value :: gate_type
        integer(c_int64_t), value :: qubit_index
        integer(c_int) :: status
        
        type(bob_quantum_state), pointer :: state
        
        if (.not. c_associated(state_ptr)) then
            status = BOB_ERROR_INVALID_ARGUMENT
            return
        end if
        
        call c_f_pointer(state_ptr, state)
        call apply_single_qubit_gate(state, gate_type, qubit_index)
        status = bob_get_last_error()
    end function bob_gate_apply

end module bob_gates

! Made with Bob