diff --git a/CHANGELOG.md b/CHANGELOG.md index aba782e..c9a8926 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ QuantumAnnealing.jl Change Log ### Staged - Add tools for working with classical Ising models (#8) +- Add data processing tools (#6) ### v0.0.1 - Initial release diff --git a/README.md b/README.md index a59c257..76b486e 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Increase the annealing time to approach the adiabatic limit, print_z_state_probabilities(ρ) ``` -Change the annealing schedule and observer different state probabilities, +Change the annealing schedule and observe different state probabilities, ``` ρ = simulate(ising_model, 10.0, AS_QUADRATIC) print_z_state_probabilities(ρ) diff --git a/src/base.jl b/src/base.jl index 082228b..7188588 100644 --- a/src/base.jl +++ b/src/base.jl @@ -68,7 +68,7 @@ converts a integer id into a binary state vector following the package conventio valid ints are from 0-to-2^n-1 pad should be the total number qubits in the system """ -function int2binary(x; pad=0) +function int2binary(x::Int; pad=0) return digits(x, base=2, pad=pad) end @@ -87,6 +87,30 @@ function binary2spin(states::Vector) return [v == 0 ? 1 : -1 for v in states] end +""" +converts a spin state vector into an integer id following the package conventions +valid ints are from 0-to-2^n-1 +""" +function spin2int(spin::Vector) + return binary2int(spin2binary(spin)) +end + +""" +converts a integer id into a spin state vector following the package conventions +valid ints are from 0-to-2^n-1 +pad should be the total number qubits in the system +""" +function int2spin(x::Int; pad=0) + return binary2spin(int2binary(x, pad=pad)) +end + +""" +converts a spin state vector (-1/1) into an binary state vector (0/1) +""" +function spin2binary(spin::Vector) + return [i == 1 ? 0 : 1 for i in spin] +end + """ converts a binary state vector into a bra-ket notation string @@ -116,15 +140,29 @@ end """ given a 2^n vector of probably values, prints each value and its associated -state vector. +state vector. `limit` is used to limit the total number of states that are +printed. `sort` is used to re-order the states by most likely instead of the +default which is numerical order from 0-to-(2^n-1) """ -function print_z_state_probabilities(density::Matrix) +function print_z_state_probabilities(density::Matrix; limit=50, sort=false) probs = z_measure_probabilities(density) n = ceil(Int, log2(length(probs))) - for (i,pr) in enumerate(probs) - state = binary2spin(int2binary(i-1, pad=n)) + + prob_order = enumerate(probs) + if sort + prob_order = Base.sort(collect(prob_order), by=(x) -> x[2], rev=true) + end + + i = 0 + for (state_id,pr) in prob_order + state = int2spin(state_id-1, pad=n) state_string = spin2braket(state) prob_string = rpad(round(pr, digits=6),8, " ") println("$(prob_string) $(state_string)") + i += 1 + if limit > 0 && i >= limit + println("first $(limit) of $(length(probs)) states shown") + break + end end end diff --git a/src/dwave.jl b/src/dwave.jl index d464fcb..0a8aea9 100644 --- a/src/dwave.jl +++ b/src/dwave.jl @@ -66,7 +66,7 @@ function _calc_linear_pwp(x_values, y_values) end -# construct a spline based piecewise quadratic function +# construct a spline-based piecewise quadratic function function _calc_quadratic_pwp(x_values, y_values) @assert(length(x_values) == length(y_values)) @@ -154,7 +154,7 @@ function parse_dwave_annealing_schedule(infile; header=1, delim=',', interpolati push!(b_values, row[3]) end - # rescale based on D-Wave hamiltonian convention + # rescale and swap sign based on D-Wave hamiltonian convention # https://docs.dwavesys.com/docs/latest/c_qpu_annealing.html a_values = a_values ./ -2.0 b_values = b_values ./ 2.0 @@ -289,7 +289,7 @@ function write_dwisc(outfile::String, ρ, ising_model, qubit_ids; simulated_num_ for state_int in 0:(2^n-1) prob = probs[state_int+1] - spin_vector = binary2spin(int2binary(state_int, pad=n)) + spin_vector = int2spin(state_int, pad=n) energy = eval_ising_state_energy(spin_vector, ising_model) sol_data = Dict( @@ -328,6 +328,7 @@ function dwave_annealing_protocol(annealing_schedule::AnnealingSchedule; asch=[( s1,s_eff_1 = asch[i+1] asch_slopes[i] = (s_eff_1 - s_eff_0)/(s1 - s0) end + #branchless piecewise function using linear interpolation from y = m*(x-x0) + y0 function asch_func(s) return sum([(asch_slopes[i]*(s-asch[i][1]) + asch[i][2]) * (asch[i][1] <= s < asch[i+1][1]) for i = 1:(length(asch)-1)]) + ((s == asch[end][1])*asch[end][2]) diff --git a/src/simulate.jl b/src/simulate.jl index 5df8a50..e2f1b2f 100644 --- a/src/simulate.jl +++ b/src/simulate.jl @@ -202,7 +202,6 @@ function simulate(ising_model::Dict, annealing_time::Real, annealing_schedule::A Ω2Const = integ2A * constant_bracket_x + integ2B * constant_bracket_z Ω2 = (Ω2Sched + Ω2Const)/2 - #display(Ω2) U_next = exp(Matrix(-im * (annealing_time*Ω1 + (annealing_time^2)*Ω2))) U = U_next * U diff --git a/test/base.jl b/test/base.jl index 8b18d57..3fb51cb 100644 --- a/test/base.jl +++ b/test/base.jl @@ -2,6 +2,10 @@ @testset "state encoding and transformation" begin @testset "int2binary" begin + @test int2binary(0) == [] + @test int2binary(1) == [1] + @test int2binary(2) == [0,1] + @test int2binary(0, pad=3) == [0, 0, 0] @test int2binary(1, pad=3) == [1, 0, 0] @test int2binary(2, pad=3) == [0, 1, 0] @@ -10,12 +14,31 @@ @test int2binary(4, pad=4) == [0, 0, 1, 0] end - @testset "binary2int" begin + @testset "int2spin" begin + @test int2spin(0) == [] + @test int2spin(1) == [-1] + @test int2spin(2) == [1,-1] + + @test int2spin(0, pad=3) == [ 1, 1, 1] + @test int2spin(1, pad=3) == [-1, 1, 1] + @test int2spin(2, pad=3) == [ 1, -1, 1] + @test int2spin(4, pad=3) == [ 1, 1, -1] + + @test int2spin(4, pad=4) == [1, 1, -1, 1] + end + + @testset "int2binary/binary2int" begin for i in 0:16 @test binary2int(int2binary(i, pad=10)) == i end end + @testset "int2spin/spin2int" begin + for i in 0:16 + @test spin2int(int2spin(i, pad=10)) == i + end + end + @testset "binary2spin" begin @test binary2spin([0, 0, 0]) == [ 1, 1, 1] @test binary2spin([1, 0, 0]) == [-1, 1, 1] @@ -23,6 +46,13 @@ @test binary2spin([0, 0, 1]) == [ 1, 1, -1] end + @testset "spin2binary" begin + @test spin2binary([ 1, 1, 1]) == [0, 0, 0] + @test spin2binary([-1, 1, 1]) == [1, 0, 0] + @test spin2binary([ 1, -1, 1]) == [0, 1, 0] + @test spin2binary([ 1, 1, -1]) == [0, 0, 1] + end + @testset "binary2braket" begin @test binary2braket(int2binary(0, pad=3)) == "|000⟩" @test binary2braket(int2binary(1, pad=3)) == "|001⟩" @@ -31,10 +61,10 @@ end @testset "binary2braket" begin - @test spin2braket(binary2spin(int2binary(0, pad=3))) == "|↑↑↑⟩" - @test spin2braket(binary2spin(int2binary(1, pad=3))) == "|↑↑↓⟩" - @test spin2braket(binary2spin(int2binary(2, pad=3))) == "|↑↓↑⟩" - @test spin2braket(binary2spin(int2binary(4, pad=3))) == "|↓↑↑⟩" + @test spin2braket(int2spin(0, pad=3)) == "|↑↑↑⟩" + @test spin2braket(int2spin(1, pad=3)) == "|↑↑↓⟩" + @test spin2braket(int2spin(2, pad=3)) == "|↑↓↑⟩" + @test spin2braket(int2spin(4, pad=3)) == "|↓↑↑⟩" end end diff --git a/test/data/generate_schedule_csvs.jl b/test/data/generate_schedule_csvs.jl index bb17286..1f7c322 100644 --- a/test/data/generate_schedule_csvs.jl +++ b/test/data/generate_schedule_csvs.jl @@ -1,6 +1,6 @@ using DelimitedFiles -# add a factor of 2x based on D-Wave hamiltonian convention +# add a factor of 2x and sign inversion based on D-Wave Hamiltonian convention # https://docs.dwavesys.com/docs/latest/c_qpu_annealing.html A = (s) -> -2.0*cos(π/2*s) B = (s) -> 2.0*sin(π/2*s)