Download src/bob_measurement.f90 from Snapkitty/sov-kernel-monster: direct link, hf CLI and curl.
- Browser
- Download file 19.2 kB
-
https://huggingface.co/Snapkitty/sov-kernel-monster/resolve/main/src/bob_measurement.f90
- Command line
-
hf download hf://Snapkitty/sov-kernel-monster/src/bob_measurement.f90
-
curl -L -o bob_measurement.f90 https://huggingface.co/Snapkitty/sov-kernel-monster/resolve/main/src/bob_measurement.f90
19.2 kB
| ! BOB Quantum Civilization Engine - Quantum Measurement | |
| ! Module: bob_measurement | |
| ! Purpose: Basis measurement, probability distributions, state collapse | |
| ! Standard: Fortran 2018 | |
| module bob_measurement | |
| use bob_kinds | |
| use bob_errors | |
| use bob_state | |
| use bob_rng | |
| implicit none | |
| private | |
| !> Measurement result | |
| type, public :: bob_measurement_result | |
| integer(i8) :: num_qubits ! Number of qubits measured | |
| integer(i8), allocatable :: outcomes(:) ! Measurement outcomes (0 or 1) | |
| real(wp), allocatable :: probabilities(:) ! Probability of each outcome | |
| integer(i8) :: num_shots ! Number of measurement shots | |
| integer(i8), allocatable :: counts(:) ! Count of each outcome | |
| real(wp) :: measurement_time ! When measurement occurred | |
| logical(lk) :: collapsed ! Whether state collapsed | |
| contains | |
| procedure :: init => measurement_result_init | |
| procedure :: destroy => measurement_result_destroy | |
| procedure :: get_outcome => measurement_result_get_outcome | |
| procedure :: get_probability => measurement_result_get_probability | |
| procedure :: get_count => measurement_result_get_count | |
| end type bob_measurement_result | |
| public :: measure_state | |
| public :: measure_qubit | |
| public :: measure_basis | |
| public :: measure_shots | |
| public :: calculate_probabilities | |
| public :: collapse_state | |
| contains | |
| !> Initialize measurement result | |
| subroutine measurement_result_init(this, num_qubits, num_shots) | |
| class(bob_measurement_result), intent(inout) :: this | |
| integer(i8), intent(in) :: num_qubits, num_shots | |
| integer :: stat | |
| integer(i8) :: num_outcomes | |
| this%num_qubits = num_qubits | |
| this%num_shots = num_shots | |
| this%collapsed = .false. | |
| this%measurement_time = ZERO | |
| ! Number of possible outcomes: 2^num_qubits | |
| num_outcomes = ishft(1_i8, int(num_qubits)) | |
| ! Allocate arrays | |
| if (allocated(this%outcomes)) deallocate(this%outcomes) | |
| if (allocated(this%probabilities)) deallocate(this%probabilities) | |
| if (allocated(this%counts)) deallocate(this%counts) | |
| allocate(this%outcomes(num_outcomes), stat=stat) | |
| if (stat /= 0) then | |
| call bob_set_error(BOB_ERROR_ALLOCATION, & | |
| "Failed to allocate outcomes", "measurement_result_init") | |
| return | |
| end if | |
| allocate(this%probabilities(num_outcomes), stat=stat) | |
| if (stat /= 0) then | |
| call bob_set_error(BOB_ERROR_ALLOCATION, & | |
| "Failed to allocate probabilities", "measurement_result_init") | |
| return | |
| end if | |
| allocate(this%counts(num_outcomes), stat=stat) | |
| if (stat /= 0) then | |
| call bob_set_error(BOB_ERROR_ALLOCATION, & | |
| "Failed to allocate counts", "measurement_result_init") | |
| return | |
| end if | |
| ! Initialize to zero | |
| this%outcomes = 0 | |
| this%probabilities = ZERO | |
| this%counts = 0 | |
| call bob_clear_error() | |
| end subroutine measurement_result_init | |
| !> Destroy measurement result | |
| subroutine measurement_result_destroy(this) | |
| class(bob_measurement_result), intent(inout) :: this | |
| if (allocated(this%outcomes)) deallocate(this%outcomes) | |
| if (allocated(this%probabilities)) deallocate(this%probabilities) | |
| if (allocated(this%counts)) deallocate(this%counts) | |
| this%num_qubits = 0 | |
| this%num_shots = 0 | |
| end subroutine measurement_result_destroy | |
| !> Get measurement outcome | |
| function measurement_result_get_outcome(this, index) result(outcome) | |
| class(bob_measurement_result), intent(in) :: this | |
| integer(i8), intent(in) :: index | |
| integer(i8) :: outcome | |
| if (index < 1 .or. index > size(this%outcomes, kind=i8)) then | |
| call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, & | |
| "Outcome index out of range", "measurement_result_get_outcome") | |
| outcome = 0 | |
| return | |
| end if | |
| outcome = this%outcomes(index) | |
| call bob_clear_error() | |
| end function measurement_result_get_outcome | |
| !> Get outcome probability | |
| function measurement_result_get_probability(this, index) result(prob) | |
| class(bob_measurement_result), intent(in) :: this | |
| integer(i8), intent(in) :: index | |
| real(wp) :: prob | |
| if (index < 1 .or. index > size(this%probabilities, kind=i8)) then | |
| call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, & | |
| "Probability index out of range", "measurement_result_get_probability") | |
| prob = ZERO | |
| return | |
| end if | |
| prob = this%probabilities(index) | |
| call bob_clear_error() | |
| end function measurement_result_get_probability | |
| !> Get outcome count | |
| function measurement_result_get_count(this, index) result(count) | |
| class(bob_measurement_result), intent(in) :: this | |
| integer(i8), intent(in) :: index | |
| integer(i8) :: count | |
| if (index < 1 .or. index > size(this%counts, kind=i8)) then | |
| call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, & | |
| "Count index out of range", "measurement_result_get_count") | |
| count = 0 | |
| return | |
| end if | |
| count = this%counts(index) | |
| call bob_clear_error() | |
| end function measurement_result_get_count | |
| !> Measure entire quantum state | |
| subroutine measure_state(state, rng, result, collapse) | |
| type(bob_quantum_state), intent(inout) :: state | |
| type(bob_rng_state), intent(inout) :: rng | |
| type(bob_measurement_result), intent(out) :: result | |
| logical(lk), intent(in), optional :: collapse | |
| integer(i8) :: num_qubits, i | |
| real(wp) :: cumulative_prob, random_val | |
| integer(i8) :: measured_outcome | |
| logical(lk) :: do_collapse | |
| if (.not. state%is_valid) then | |
| call bob_set_error(BOB_ERROR_INVALID_STATE, & | |
| "Cannot measure invalid state", "measure_state") | |
| return | |
| end if | |
| do_collapse = .true. | |
| if (present(collapse)) do_collapse = collapse | |
| ! Calculate number of qubits | |
| num_qubits = int(log(real(state%dim, wp)) / log(TWO), i8) | |
| ! Initialize result | |
| call result%init(num_qubits, 1_i8) | |
| ! Calculate probabilities | |
| call calculate_probabilities(state, result) | |
| ! Sample from probability distribution | |
| random_val = rng%uniform() | |
| cumulative_prob = ZERO | |
| measured_outcome = 0 | |
| do i = 1, state%dim | |
| cumulative_prob = cumulative_prob + result%probabilities(i) | |
| if (random_val <= cumulative_prob) then | |
| measured_outcome = i - 1 | |
| exit | |
| end if | |
| end do | |
| ! Store outcome | |
| result%outcomes(measured_outcome + 1) = measured_outcome | |
| result%counts(measured_outcome + 1) = 1 | |
| result%collapsed = do_collapse | |
| ! Collapse state if requested | |
| if (do_collapse) then | |
| call collapse_state(state, measured_outcome) | |
| end if | |
| call bob_clear_error() | |
| end subroutine measure_state | |
| !> Measure single qubit | |
| subroutine measure_qubit(state, qubit_index, rng, result, collapse) | |
| type(bob_quantum_state), intent(inout) :: state | |
| integer(i8), intent(in) :: qubit_index | |
| type(bob_rng_state), intent(inout) :: rng | |
| integer(i8), intent(out) :: result | |
| logical(lk), intent(in), optional :: collapse | |
| integer(i8) :: num_qubits, i, bit_mask, qubit_bit | |
| real(wp) :: prob_0, prob_1, random_val | |
| logical(lk) :: do_collapse | |
| if (.not. state%is_valid) then | |
| call bob_set_error(BOB_ERROR_INVALID_STATE, & | |
| "Cannot measure invalid state", "measure_qubit") | |
| result = 0 | |
| 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", "measure_qubit") | |
| result = 0 | |
| return | |
| end if | |
| do_collapse = .true. | |
| if (present(collapse)) do_collapse = collapse | |
| ! Calculate probabilities for |0⟩ and |1⟩ | |
| bit_mask = ishft(1_i8, int(qubit_index)) | |
| prob_0 = ZERO | |
| prob_1 = ZERO | |
| do i = 0, state%dim - 1 | |
| qubit_bit = iand(i, bit_mask) | |
| if (qubit_bit == 0) then | |
| prob_0 = prob_0 + real(state%amplitudes(i + 1) * conjg(state%amplitudes(i + 1))) | |
| else | |
| prob_1 = prob_1 + real(state%amplitudes(i + 1) * conjg(state%amplitudes(i + 1))) | |
| end if | |
| end do | |
| ! Sample measurement outcome | |
| random_val = rng%uniform() | |
| if (random_val < prob_0) then | |
| result = 0 | |
| else | |
| result = 1 | |
| end if | |
| ! Collapse state if requested | |
| if (do_collapse) then | |
| call collapse_qubit(state, qubit_index, result) | |
| end if | |
| call bob_clear_error() | |
| end subroutine measure_qubit | |
| !> Measure in arbitrary basis | |
| subroutine measure_basis(state, basis_vectors, rng, result, collapse) | |
| type(bob_quantum_state), intent(inout) :: state | |
| complex(cwp), intent(in) :: basis_vectors(:,:) | |
| type(bob_rng_state), intent(inout) :: rng | |
| integer(i8), intent(out) :: result | |
| logical(lk), intent(in), optional :: collapse | |
| integer(i8) :: num_basis, i, j | |
| real(wp), allocatable :: probabilities(:) | |
| real(wp) :: cumulative_prob, random_val | |
| complex(cwp) :: inner_prod | |
| logical(lk) :: do_collapse | |
| integer :: stat | |
| if (.not. state%is_valid) then | |
| call bob_set_error(BOB_ERROR_INVALID_STATE, & | |
| "Cannot measure invalid state", "measure_basis") | |
| result = 0 | |
| return | |
| end if | |
| num_basis = size(basis_vectors, 2, kind=i8) | |
| if (size(basis_vectors, 1, kind=i8) /= state%dim) then | |
| call bob_set_error(BOB_ERROR_DIMENSION_MISMATCH, & | |
| "Basis vectors dimension mismatch", "measure_basis") | |
| result = 0 | |
| return | |
| end if | |
| do_collapse = .true. | |
| if (present(collapse)) do_collapse = collapse | |
| ! Allocate probabilities | |
| allocate(probabilities(num_basis), stat=stat) | |
| if (stat /= 0) then | |
| call bob_set_error(BOB_ERROR_ALLOCATION, & | |
| "Failed to allocate probabilities", "measure_basis") | |
| result = 0 | |
| return | |
| end if | |
| ! Calculate probabilities: P(i) = |⟨basis_i|ψ⟩|² | |
| do i = 1, num_basis | |
| inner_prod = CZERO | |
| do j = 1, state%dim | |
| inner_prod = inner_prod + conjg(basis_vectors(j, i)) * state%amplitudes(j) | |
| end do | |
| probabilities(i) = real(inner_prod * conjg(inner_prod)) | |
| end do | |
| ! Sample from probability distribution | |
| random_val = rng%uniform() | |
| cumulative_prob = ZERO | |
| result = 0 | |
| do i = 1, num_basis | |
| cumulative_prob = cumulative_prob + probabilities(i) | |
| if (random_val <= cumulative_prob) then | |
| result = i - 1 | |
| exit | |
| end if | |
| end do | |
| ! Collapse to measured basis state if requested | |
| if (do_collapse) then | |
| state%amplitudes = basis_vectors(:, result + 1) | |
| call state%normalize() | |
| end if | |
| deallocate(probabilities) | |
| call bob_clear_error() | |
| end subroutine measure_basis | |
| !> Perform multiple measurement shots | |
| subroutine measure_shots(state, num_shots, rng, result) | |
| type(bob_quantum_state), intent(in) :: state | |
| integer(i8), intent(in) :: num_shots | |
| type(bob_rng_state), intent(inout) :: rng | |
| type(bob_measurement_result), intent(out) :: result | |
| integer(i8) :: num_qubits, shot, i | |
| real(wp) :: cumulative_prob, random_val | |
| integer(i8) :: measured_outcome | |
| type(bob_quantum_state) :: temp_state | |
| if (.not. state%is_valid) then | |
| call bob_set_error(BOB_ERROR_INVALID_STATE, & | |
| "Cannot measure invalid state", "measure_shots") | |
| return | |
| end if | |
| if (num_shots <= 0) then | |
| call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, & | |
| "Number of shots must be positive", "measure_shots") | |
| return | |
| end if | |
| num_qubits = int(log(real(state%dim, wp)) / log(TWO), i8) | |
| ! Initialize result | |
| call result%init(num_qubits, num_shots) | |
| ! Calculate probabilities (once) | |
| call calculate_probabilities(state, result) | |
| ! Perform shots | |
| do shot = 1, num_shots | |
| random_val = rng%uniform() | |
| cumulative_prob = ZERO | |
| measured_outcome = 0 | |
| do i = 1, state%dim | |
| cumulative_prob = cumulative_prob + result%probabilities(i) | |
| if (random_val <= cumulative_prob) then | |
| measured_outcome = i - 1 | |
| exit | |
| end if | |
| end do | |
| ! Increment count for this outcome | |
| result%counts(measured_outcome + 1) = result%counts(measured_outcome + 1) + 1 | |
| end do | |
| result%collapsed = .false. | |
| call bob_clear_error() | |
| end subroutine measure_shots | |
| !> Calculate measurement probabilities | |
| subroutine calculate_probabilities(state, result) | |
| type(bob_quantum_state), intent(in) :: state | |
| type(bob_measurement_result), intent(inout) :: result | |
| integer(i8) :: i | |
| real(wp) :: total_prob | |
| if (.not. state%is_valid) then | |
| call bob_set_error(BOB_ERROR_INVALID_STATE, & | |
| "Cannot calculate probabilities for invalid state", & | |
| "calculate_probabilities") | |
| return | |
| end if | |
| ! Calculate P(i) = |ψᵢ|² | |
| total_prob = ZERO | |
| do i = 1, state%dim | |
| result%probabilities(i) = real(state%amplitudes(i) * conjg(state%amplitudes(i))) | |
| total_prob = total_prob + result%probabilities(i) | |
| end do | |
| ! Verify normalization | |
| if (abs(total_prob - ONE) > TOL_NORM) then | |
| call bob_set_error(BOB_ERROR_NOT_NORMALIZED, & | |
| "State probabilities do not sum to 1", "calculate_probabilities") | |
| return | |
| end if | |
| call bob_clear_error() | |
| end subroutine calculate_probabilities | |
| !> Collapse state to measured outcome | |
| subroutine collapse_state(state, outcome) | |
| type(bob_quantum_state), intent(inout) :: state | |
| integer(i8), intent(in) :: outcome | |
| if (.not. state%is_valid) then | |
| call bob_set_error(BOB_ERROR_INVALID_STATE, & | |
| "Cannot collapse invalid state", "collapse_state") | |
| return | |
| end if | |
| if (outcome < 0 .or. outcome >= state%dim) then | |
| call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, & | |
| "Outcome out of range", "collapse_state") | |
| return | |
| end if | |
| ! Set all amplitudes to zero except measured outcome | |
| state%amplitudes = CZERO | |
| state%amplitudes(outcome + 1) = CONE | |
| state%is_normalized = .true. | |
| call bob_clear_error() | |
| end subroutine collapse_state | |
| !> Collapse single qubit | |
| subroutine collapse_qubit(state, qubit_index, outcome) | |
| type(bob_quantum_state), intent(inout) :: state | |
| integer(i8), intent(in) :: qubit_index, outcome | |
| integer(i8) :: i, bit_mask, qubit_bit | |
| real(wp) :: norm_factor | |
| if (.not. state%is_valid) then | |
| call bob_set_error(BOB_ERROR_INVALID_STATE, & | |
| "Cannot collapse invalid state", "collapse_qubit") | |
| return | |
| end if | |
| if (outcome /= 0 .and. outcome /= 1) then | |
| call bob_set_error(BOB_ERROR_INVALID_ARGUMENT, & | |
| "Qubit outcome must be 0 or 1", "collapse_qubit") | |
| return | |
| end if | |
| bit_mask = ishft(1_i8, int(qubit_index)) | |
| ! Zero out amplitudes inconsistent with measurement | |
| do i = 0, state%dim - 1 | |
| qubit_bit = iand(i, bit_mask) | |
| if ((outcome == 0 .and. qubit_bit /= 0) .or. & | |
| (outcome == 1 .and. qubit_bit == 0)) then | |
| state%amplitudes(i + 1) = CZERO | |
| end if | |
| end do | |
| ! Renormalize | |
| call state%normalize() | |
| call bob_clear_error() | |
| end subroutine collapse_qubit | |
| !> C ABI: Measure state | |
| function bob_state_measure(state_ptr, rng_ptr, outcome) result(status) & | |
| bind(C, name="bob_state_measure") | |
| use, intrinsic :: iso_c_binding | |
| type(c_ptr), value :: state_ptr, rng_ptr | |
| integer(c_int64_t), intent(out) :: outcome | |
| integer(c_int) :: status | |
| type(bob_quantum_state), pointer :: state | |
| type(bob_rng_state), pointer :: rng | |
| type(bob_measurement_result) :: result | |
| if (.not. c_associated(state_ptr) .or. .not. c_associated(rng_ptr)) then | |
| status = BOB_ERROR_INVALID_ARGUMENT | |
| return | |
| end if | |
| call c_f_pointer(state_ptr, state) | |
| call c_f_pointer(rng_ptr, rng) | |
| call measure_state(state, rng, result, collapse=.true._lk) | |
| if (bob_get_last_error() == BOB_SUCCESS) then | |
| outcome = result%outcomes(1) | |
| else | |
| outcome = 0 | |
| end if | |
| call result%destroy() | |
| status = bob_get_last_error() | |
| end function bob_state_measure | |
| end module bob_measurement | |
| ! Made with Bob | |