-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
354 additions
and
265 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,259 @@ | ||
module TestKrausNoiseHelpers | ||
|
||
using Test | ||
using Logging | ||
|
||
using BPGates: get_mixed_transition_probs, select_rand_state | ||
|
||
export test_bell_basis_probs, test_nonoise_bell_basis, test_almost_all_noise, | ||
test_random_lambdas, test_equal_mixed_probs_2, test_equal_mixed_probs_4, | ||
test_random_mixed_states, test_random_mixed_states_random_lambdas | ||
|
||
# using QuantumClifford: apply! | ||
|
||
# Get the bell states used for testing | ||
function get_bell_states() | ||
return (1 / sqrt(2)) * [ | ||
[1.0; 0.0; 0.0; 1.0], | ||
[0.0; 1.0; 1.0; 0.0], | ||
[1.0; 0.0; 0.0; -1.0], | ||
[0.0; 1.0; -1.0; 0.0] | ||
] | ||
end | ||
|
||
# Returns an index selected from the indices of a list, weighted by the probability at that index | ||
function get_weighted_index(prob_dist::Vector{Float64}) | ||
if !isapprox(sum(prob_dist), 1.0, atol=1e-9) | ||
@error "get_weighted_index: prob_dist sums to $(sum(prob_dist)) and not 1" | ||
end | ||
rand_num = rand() | ||
cur_sum = 0.0 | ||
for (idx, prob_val) in enumerate(prob_dist) | ||
if rand_num < cur_sum + prob_val | ||
return idx | ||
end | ||
cur_sum += prob_val | ||
end | ||
end | ||
|
||
# Converts a bit to an int from left to right (LSB is the rightmost bit) | ||
function bit_to_int_testing(bits) | ||
reduce(⊻,(bit<<(length(bits) - index) for (index,bit) in enumerate(bits))) + 1 # +1 so that we use julia indexing convenctions | ||
end | ||
|
||
# Returns the tensor product of a set of Kraus operators | ||
function get_tensored_kraus_ops(kraus_ops::Vector{Matrix{Complex}}) | ||
tensored_kraus_ops = [] | ||
for op1 in kraus_ops | ||
for op2 in kraus_ops | ||
push!(tensored_kraus_ops, kron(op1, op2)) | ||
end | ||
end | ||
return tensored_kraus_ops | ||
end | ||
|
||
# Returns the diagonal of a matrix | ||
function get_diagonal(matrix::Matrix{ComplexF64})::Vector{Float64} | ||
diagonal_length = min(size(matrix)[1], size(matrix)[2]) | ||
if size(matrix)[1] != size(matrix)[2] | ||
@error("get_diagonal: matrix is not square, rows: $(size(matrix)[1]) != cols: $(size(matrix)[2])") | ||
end | ||
diag_elements = [] | ||
for idx in 1:diagonal_length | ||
push!(diag_elements, matrix[idx, idx]) | ||
end | ||
return diag_elements | ||
end | ||
|
||
# Returns the bell state corresponding to the input phases | ||
function get_bell_state(phases::BitVector) | ||
state_idx = bit_to_int_testing(phases) | ||
bell_states = get_bell_states() | ||
return bell_states[state_idx] | ||
end | ||
|
||
# Numerically computes the transition probabilities of one state to another, | ||
# given a mixed probability distribution of states and a set of kraus operators | ||
function get_numerical_trans_probs(mixed_state_probs::Vector{Float64}, kraus_ops::Vector{Matrix{Complex}}) | ||
bell_states = get_bell_states() | ||
ρ_bell = zeros(ComplexF64, length(bell_states), length(bell_states)) | ||
for (bell_idx, bell_prob) in enumerate(mixed_state_probs) | ||
ρ_bell += bell_prob * bell_states[bell_idx] * bell_states[bell_idx]' | ||
end | ||
@debug("get_numerical_trans_probs: ρ_bell: $ρ_bell") | ||
tensored_ops = get_tensored_kraus_ops(kraus_ops) | ||
# Apply the Kraus operators to the Bell state | ||
ρ_new = zeros(ComplexF64, size(ρ_bell)[1], size(ρ_bell)[2]) | ||
for K in tensored_ops | ||
ρ_new += K * ρ_bell * adjoint(K) | ||
end | ||
U_bell = hcat(get_bell_states()...) | ||
@debug("get_numerical_trans_probs: ρ_new: $ρ_new") | ||
@debug("get_numerical_trans_probs: U_bell: $U_bell") | ||
ρ_Bell_basis = adjoint(U_bell) * ρ_new * U_bell | ||
@debug("get_numerical_trans_probs: ρ_Bell_basis: $ρ_Bell_basis") | ||
@debug("get_numerical_trans_probs: size(ρ_Bell_basis): $(size(ρ_Bell_basis))") | ||
return get_diagonal(ρ_Bell_basis) | ||
end | ||
|
||
# Testing functions | ||
|
||
# Test our simulated noise for the pure states in the bell basis | ||
function test_bell_basis_probs(kraus_ops_factory::Function, get_simulated_trans_probs::Function) | ||
statedist_list = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]] | ||
lambda = 1 - exp(-500e-9 / 260e-6) | ||
num_samples = 1000000 | ||
kraus_ops = kraus_ops_factory(lambda) | ||
for state_dist in statedist_list | ||
@info "test_bell_basis_probs: state_dist: $state_dist" | ||
numerical_trans_probs = get_numerical_trans_probs(state_dist, kraus_ops) | ||
simulated_trans_probs = get_simulated_trans_probs(state_dist, lambda, num_samples) | ||
# @info("test_A_state_probs: numerical_trans_probs: $numerical_trans_probs") | ||
# @info("test_A_state_probs: simulated_trans_probs: $simulated_trans_probs") | ||
@test all(isapprox.(numerical_trans_probs, simulated_trans_probs, atol=(2 / sqrt(num_samples)))) | ||
end | ||
end | ||
|
||
# Test our simulated noise when there should be no noise applied for states in the bell basis | ||
function test_nonoise_bell_basis(kraus_ops_factory::Function, get_simulated_trans_probs::Function) | ||
statedist_list = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]] | ||
lambda = 0.0 | ||
num_samples = 1000000 | ||
kraus_ops = kraus_ops_factory(lambda) | ||
for state_dist in statedist_list | ||
@info "test_nonoise_bell_basis: state_dist: $state_dist" | ||
numerical_trans_probs = get_numerical_trans_probs(state_dist, kraus_ops) | ||
simulated_trans_probs = get_simulated_trans_probs(state_dist, lambda, num_samples) | ||
# @info("test_A_state_probs: numerical_trans_probs: $numerical_trans_probs") | ||
# @info("test_A_state_probs: simulated_trans_probs: $simulated_trans_probs") | ||
@test all(isapprox.(numerical_trans_probs, simulated_trans_probs, atol=(2 / sqrt(num_samples)))) | ||
end | ||
end | ||
|
||
# Test our simulated noise with a noise factor close to 1 for states in the bell basis | ||
function test_almost_all_noise(kraus_ops_factory::Function, get_simulated_trans_probs::Function) | ||
statedist_list = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]] | ||
lambda = 0.999999999 | ||
num_samples = 1000000 | ||
kraus_ops = kraus_ops_factory(lambda) | ||
for state_dist in statedist_list | ||
@info "test_almost_all_noise: state_dist: $state_dist" | ||
numerical_trans_probs = get_numerical_trans_probs(state_dist, kraus_ops) | ||
simulated_trans_probs = get_simulated_trans_probs(state_dist, lambda, num_samples) | ||
@info("test_almost_all_noise: numerical_trans_probs: $numerical_trans_probs") | ||
@info("test_almost_all_noise: simulated_trans_probs: $simulated_trans_probs") | ||
@test all(isapprox.(numerical_trans_probs, simulated_trans_probs, atol=(2 / sqrt(num_samples)))) | ||
end | ||
end | ||
|
||
# Test random noise factors for states in the bell basis | ||
function test_random_lambdas(kraus_ops_factory::Function, get_simulated_trans_probs::Function) | ||
statedist_list = [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]] | ||
num_samples = 1000000 | ||
num_random_lambdas = 5 | ||
for _ in 1:num_random_lambdas | ||
lambda = rand() | ||
num_samples = 1000000 | ||
kraus_ops = kraus_ops_factory(lambda) | ||
for state_dist in statedist_list | ||
@info "test_random_lambdas: state_dist: $state_dist" | ||
@info "test_random_lambdas: lambda: $lambda" | ||
numerical_trans_probs = get_numerical_trans_probs(state_dist, kraus_ops) | ||
simulated_trans_probs = get_simulated_trans_probs(state_dist, lambda, num_samples) | ||
@info("test_random_lambdas: numerical_trans_probs: $numerical_trans_probs") | ||
@info("test_random_lambdas: simulated_trans_probs: $simulated_trans_probs") | ||
@test all(isapprox.(numerical_trans_probs, simulated_trans_probs, atol=(2 / sqrt(num_samples)))) | ||
end | ||
end | ||
end | ||
|
||
# Test all mixed states composed of two states in the Bell basis with equal probability | ||
function test_equal_mixed_probs_2(kraus_ops_factory::Function, get_simulated_trans_probs::Function) | ||
bell_states = get_bell_states() | ||
lambda = 1 - exp(-500e-9 / 260e-6) | ||
kraus_ops = kraus_ops_factory(lambda) | ||
num_samples = 1000000 | ||
for first_phases_idx in 1:length(bell_states) | ||
for second_phases_idx in 1:length(bell_states) | ||
if first_phases_idx == second_phases_idx | ||
continue | ||
end | ||
state_dist = [0.0 for _ in 1:length(bell_states)] | ||
for basis_idx in 1:length(bell_states) | ||
if basis_idx == first_phases_idx || basis_idx == second_phases_idx | ||
state_dist[basis_idx] = 0.5 | ||
end | ||
end | ||
numerical_trans_probs = get_numerical_trans_probs(state_dist, kraus_ops) | ||
simulated_trans_probs = get_simulated_trans_probs(state_dist, lambda, num_samples) | ||
@info("test_equal_mixed_probs_2: numerical_trans_probs: $numerical_trans_probs") | ||
@info("test_equal_mixed_probs_2: simulated_trans_probs: $simulated_trans_probs") | ||
@test all(isapprox.(numerical_trans_probs, simulated_trans_probs, atol=(2 / sqrt(num_samples)))) | ||
end | ||
end | ||
end | ||
|
||
# Test a mixed state composed of all 4 bell basis states with equal probability | ||
function test_equal_mixed_probs_4(kraus_ops_factory::Function, get_simulated_trans_probs::Function) | ||
state_dist = [0.25 for _ in 1:length(get_bell_states())] | ||
lambda = 1 - exp(-500e-9 / 260e-6) | ||
num_samples = 1000000 | ||
kraus_ops = kraus_ops_factory(lambda) | ||
@info "test_equal_mixed_probs_4: state_dist: $state_dist" | ||
numerical_trans_probs = get_numerical_trans_probs(state_dist, kraus_ops) | ||
simulated_trans_probs = get_simulated_trans_probs(state_dist, lambda, num_samples) | ||
@info("test_equal_mixed_probs_4: numerical_trans_probs: $numerical_trans_probs") | ||
@info("test_equal_mixed_probs_4: simulated_trans_probs: $simulated_trans_probs") | ||
@test all(isapprox.(numerical_trans_probs, simulated_trans_probs, atol=(2 / sqrt(num_samples)))) | ||
end | ||
|
||
# Test random mixed states in the bell basis | ||
function test_random_mixed_states(kraus_ops_factory::Function, get_simulated_trans_probs::Function) | ||
num_random_states = 20 | ||
statedist_list = [] | ||
for _ in 1:num_random_states | ||
state_dist = [rand() for _ in 1:length(get_bell_states())] | ||
state_dist = state_dist / sum(state_dist) | ||
push!(statedist_list, state_dist) | ||
end | ||
@debug "length(statedist_list): $(length(statedist_list))" | ||
lambda = 1 - exp(-500e-9 / 260e-6) | ||
num_samples = 1000000 | ||
kraus_ops = kraus_ops_factory(lambda) | ||
for state_dist in statedist_list | ||
@info "test_random_mixed_states: state_dist: $state_dist" | ||
numerical_trans_probs = get_numerical_trans_probs(state_dist, kraus_ops) | ||
simulated_trans_probs = get_simulated_trans_probs(state_dist, lambda, num_samples) | ||
@info("test_random_mixed_states: numerical_trans_probs: $numerical_trans_probs") | ||
@info("test_random_mixed_states: simulated_trans_probs: $simulated_trans_probs") | ||
@test all(isapprox.(numerical_trans_probs, simulated_trans_probs, atol=(2 / sqrt(num_samples)))) | ||
end | ||
end | ||
|
||
# Test random mixed states with random noise parameters in the Bell basis | ||
function test_random_mixed_states_random_lambdas(kraus_ops_factory::Function, get_simulated_trans_probs::Function) | ||
num_random_states = 20 | ||
statedist_list = [] | ||
for _ in 1:num_random_states | ||
state_dist = [rand() for _ in 1:length(get_bell_states())] | ||
state_dist = state_dist / sum(state_dist) | ||
push!(statedist_list, state_dist) | ||
end | ||
num_random_lambdas = 20 | ||
num_samples = 1000000 | ||
for _ in 1:num_random_lambdas | ||
lambda = rand() | ||
@info "test_random_mixed_states_random_lambdas: lambda: $lambda" | ||
kraus_ops = kraus_ops_factory(lambda) | ||
for state_dist in statedist_list | ||
@info "test_random_mixed_states_random_lambdas: state_dist: $state_dist" | ||
numerical_trans_probs = get_numerical_trans_probs(state_dist, kraus_ops) | ||
simulated_trans_probs = get_simulated_trans_probs(state_dist, lambda, num_samples) | ||
@info("test_random_mixed_states_random_lambdas: numerical_trans_probs: $numerical_trans_probs") | ||
@info("test_random_mixed_states_random_lambdas: simulated_trans_probs: $simulated_trans_probs") | ||
@test all(isapprox.(numerical_trans_probs, simulated_trans_probs, atol=(2 / sqrt(num_samples)))) | ||
end | ||
end | ||
end | ||
|
||
end |
Oops, something went wrong.