Skip to content

Commit

Permalink
Ising Model Tools (#10)
Browse files Browse the repository at this point in the history
* add Ising state analysis tools, closes #8
* make noisy tests more robust
* add note to changelog

Co-authored-by: zmorrell <zmorrell7@gmail.com>
  • Loading branch information
ccoffrin and zmorrell committed Feb 13, 2022
1 parent bfad91f commit 97e5cc1
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ QuantumAnnealing.jl Change Log
==============================

### Staged
- Add tools for working with classical Ising models (#8)
- Add data processing tools (#6)

### v0.0.1
Expand Down
8 changes: 8 additions & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ AS_CIRCULAR
AS_DW_QUADRATIC
```

## Ising Functions
```@autodocs
Modules = [QuantumAnnealing]
Pages = ["ising.jl"]
Order = [:function]
Private = true
```

# D-Wave Functions
```@autodocs
Modules = [QuantumAnnealing]
Expand Down
1 change: 1 addition & 0 deletions src/QuantumAnnealing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module QuantumAnnealing
import DifferentialEquations

include("base.jl")
include("ising.jl")

include("simulate.jl")
include("simulate_de.jl")
Expand Down
15 changes: 1 addition & 14 deletions src/dwave.jl
Original file line number Diff line number Diff line change
Expand Up @@ -274,19 +274,6 @@ function read_bqpjson(bqpjson_file::String)
end


function _eval_state_energy(state, ising_model)
energy = 0.0
for (ids,v) in ising_model
val = v
for qid in ids
val *= state[qid]
end
energy += val
end
return energy
end


function write_dwisc(outfile::String, ρ, ising_model, qubit_ids; simulated_num_reads=1e17, annealing_time=1000)
dwisc_data = Dict()
dwisc_data["variable_ids"] = qubit_ids
Expand All @@ -303,7 +290,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 = int2spin(state_int, pad=n)
energy = _eval_state_energy(spin_vector, ising_model)
energy = eval_ising_state_energy(spin_vector, ising_model)

sol_data = Dict(
"energy" => energy,
Expand Down
79 changes: 79 additions & 0 deletions src/ising.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
### Helper Functions for Classical Ising Models ###

"""
given a state vector of spin values and an Ising model
computes the energy of that spin configuration
"""
function eval_ising_state_energy(spin_state::Vector, ising_model::Dict)
energy = 0.0
for (ids,v) in ising_model
val = v
for qid in ids
val *= spin_state[qid]
end
energy += val
end
return energy
end

"""
given an Ising model computes a mapping from state integers to energy values
"""
function compute_ising_state_energies(ising_model::Dict)
n = _check_ising_model_ids(ising_model)

state_energy = Dict{Int,Float64}()
for state_int in 0:(2^n-1)
spin_vector = binary2spin(int2binary(state_int, pad=n))
energy = eval_ising_state_energy(spin_vector, ising_model)
state_energy[state_int] = energy
end

return state_energy
end

"""
given an Ising model computes a mapping from energy values to collections of state integers
"""
function compute_ising_energy_levels(ising_model::Dict)
state_energies = compute_ising_state_energies(ising_model)

energy_levels = Dict{Float64,Set{Int}}()
for (state_id, energy) in state_energies
if !haskey(energy_levels, energy)
energy_levels[energy] = Set{Int}()
end
push!(energy_levels[energy], state_id)
end

return energy_levels
end

"""
given an Ising model prints state strings by ascending energy levels.
`limit` is used the stop the printing after a number of energy levels have been
presented (`limit` <= 0 will print all states).
"""
function print_ising_energy_levels(ising_model::Dict; limit=3)
n = maximum(max(k...) for (k,v) in ising_model)

energy_levels = compute_ising_energy_levels(ising_model)

energies = sort(collect(keys(energy_levels)))

for (i,energy) in enumerate(energies)
state_ids = energy_levels[energy]

println("\033[1menergy: $(energy)\033[0m")
for state_id in sort(collect(state_ids))
state = binary2spin(int2binary(state_id, pad=n))
state_string = spin2braket(state)
println(" $(state_string)")
end

if limit > 0 && i >= limit
println("first $(i) of $(length(energy_levels)) energy levels shown")
break
end
end
end
36 changes: 36 additions & 0 deletions test/base.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,42 @@

end

@testset "ising energy computations" begin

@testset "single qubit, single state" begin
@test isapprox(eval_ising_state_energy([1],Dict((1,) => 1)), 1)
@test isapprox(eval_ising_state_energy([-1],Dict((1,) => 1)), -1)
end

@testset "single qubit, all states" begin
energies = compute_ising_state_energies(Dict((1,) => 1))
@test isapprox(energies[0], 1)
@test isapprox(energies[1], -1)
end

@testset "two qubit, single state" begin
ising_model = Dict((1,) => 1, (2,) => 1, (1,2) => -1)
@test isapprox(eval_ising_state_energy([1, 1], ising_model), 1)
@test isapprox(eval_ising_state_energy([1, -1], ising_model), 1)
@test isapprox(eval_ising_state_energy([-1, 1], ising_model), 1)
@test isapprox(eval_ising_state_energy([-1, -1], ising_model), -3)
end

@testset "two qubit, all state energies" begin
energies = compute_ising_state_energies(Dict((1,) => 1, (1,2) => -1))
@test isapprox(energies[0], 0)
@test isapprox(energies[1], 0)
@test isapprox(energies[2], 2)
@test isapprox(energies[3], -2)
end

@testset "two qubit, energy levels" begin
energy_levels = compute_ising_energy_levels(Dict((1,2) => -1))
@test energy_levels[-1.0] == Set([0,3])
@test energy_levels[1.0] == Set([1,2])
end

end

@testset "csv annealing schedules" begin
s_100 = range(0, 1, length=100)
Expand Down
10 changes: 5 additions & 5 deletions test/simulate.jl
Original file line number Diff line number Diff line change
Expand Up @@ -446,8 +446,8 @@ end
steps = 100
numshots = 10

#random numbers between -1.0 and 1.0
z_bias = (Random.rand(numshots) .- 0.5)*2
# random numbers between -0.75 and 0.75
z_bias = (Random.rand(numshots) .- 0.5)*1.5

bqpjson_file = "data/bqpjson_1q.json"
dwisc_file = "tmp.json"
Expand All @@ -467,9 +467,9 @@ end
steps = 100
numshots = 10

#random numbers between -1.0 and 1.0
x_bias = (Random.rand(numshots) .- 0.5)*2
z_bias = (Random.rand(numshots) .- 0.5)*2
# random numbers between -0.75 and 0.75
x_bias = (Random.rand(numshots) .- 0.5)*1.5
z_bias = (Random.rand(numshots) .- 0.5)*1.5

bqpjson_file = "data/bqpjson_1q.json"
dwisc_file = "tmp.json"
Expand Down

0 comments on commit 97e5cc1

Please sign in to comment.