Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change: Remove PythonCall dep and extension #51

Merged
merged 3 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a"
Expand All @@ -21,12 +22,9 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[weakdeps]
Braket = "19504a0f-b47d-4348-9127-acc6cc69ef67"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"

[extensions]
BraketSimulatorBraketExt = "Braket"
BraketSimulatorPythonExt = ["JSON3", "PythonCall"]

[compat]
AbstractTrees = "=0.4.5"
Expand All @@ -43,7 +41,7 @@ LinearAlgebra = "1.6"
Logging = "1.6"
OrderedCollections = "=1.6.3"
PrecompileTools = "=1.2.1"
PythonCall = "=0.9.22"
PythonCall = "=0.9.23"
Random = "1.6"
StaticArrays = "1.9"
StatsBase = "0.34"
Expand All @@ -62,4 +60,4 @@ PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Aqua", "Braket", "JSON3", "Test", "Logging", "PythonCall"]
test = ["Aqua", "Braket", "JSON3", "PythonCall", "Test", "Logging"]
6 changes: 5 additions & 1 deletion coverage.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Coverage
# process '*.cov' files
coverage = process_folder()
coverage = append!(coverage, process_folder("ext/BraketSimulatorPythonExt/"))
coverage = append!(coverage, process_folder("ext/BraketSimulatorBraketExt/"))
coverage = merge_coverage_counts(coverage)
# Get total coverage for all Julia files
Expand All @@ -17,6 +16,11 @@ for fi in readdir("src")
println("Coverage for file $fi: $(get_summary(process_file(joinpath("src", fi))))")
end
end
for fi in readdir("ext/BraketSimulatorBraketExt")
if endswith(fi, ".jl")
println("Coverage for file $fi: $(get_summary(process_file(joinpath("ext/BraketSimulatorBraketExt", fi))))")
end
end

# uncomment this if you have `genhtml` installed
# to generate HTML coverage info
Expand Down
1 change: 0 additions & 1 deletion docs/src/circuits.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ BraketSimulator.FreeParameter
BraketSimulator.Measure
BraketSimulator.Instruction
BraketSimulator.QubitSet
BraketSimulator.Qubit
BraketSimulator.qubit_count
BraketSimulator.qubits
BraketSimulator.basis_rotation_instructions!
Expand Down
48 changes: 0 additions & 48 deletions ext/BraketSimulatorPythonExt/BraketSimulatorPythonExt.jl

This file was deleted.

104 changes: 88 additions & 16 deletions src/BraketSimulator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ using
Dates,
Combinatorics,
LinearAlgebra,
JSON3,
StaticArrays,
StatsBase,
UUIDs,
Expand Down Expand Up @@ -145,11 +146,7 @@ function _generate_results(
) where {D<:AbstractSimulator}
result_values = map(result_type -> calculate(result_type, simulator), result_types)
ir_results = map(StructTypes.lower, result_types)
results = map(zip(ir_results, result_values)) do (ir, val)
ir_val = complex_matrix_to_ir(val)
return ResultTypeValue(ir, ir_val)
end
return results
return [ResultTypeValue(ir_results[r_ix], complex_matrix_to_ir(result_values[r_ix])) for r_ix in 1:length(result_values)]
end

_translate_result_type(r::IR.Amplitude) = Amplitude(r.states)
Expand Down Expand Up @@ -202,8 +199,10 @@ parsing and the qubit count of the circuit.
"""
function _prepare_program(circuit_ir::OpenQasmProgram, inputs::Dict{String, <:Any}, shots::Int)
ir_inputs = isnothing(circuit_ir.inputs) ? Dict{String, Float64}() : circuit_ir.inputs
circuit = Circuit(circuit_ir.source, merge(ir_inputs, inputs))
n_qubits = qubit_count(circuit)
merged_inputs = merge(ir_inputs, inputs)
src = circuit_ir.source::String
circuit = Quasar.to_circuit(src, merged_inputs)
n_qubits = qubit_count(circuit)
if shots > 0
_verify_openqasm_shots_observables(circuit, n_qubits)
basis_rotation_instructions!(circuit)
Expand Down Expand Up @@ -381,6 +380,68 @@ function simulate(simulator::AbstractSimulator,
return results
end

# these functions are for calls from an "external" language
# like Python or Rust, when we're calling this package from a
# separate process and thus don't want to have to IPC large
# blobs of data back and forth/deal with having to serialize
# Julia objects
function create_sim(simulator_id::String, shots::Int)
return if simulator_id == "braket_sv_v2"
StateVectorSimulator(0, shots)
elseif simulator_id == "braket_dm_v2"
DensityMatrixSimulator(0, shots)
end
end

function _mmap_large_result_values(results)
to_mmap = findall(rt->sizeof(rt.value) > 2^20, results.resultTypes)
isempty(to_mmap) && return nothing, nothing
mmap_files = String[]
obj_lengths = Int[]
for r_ix in to_mmap
push!(obj_lengths, length(results.resultTypes[r_ix].value))
tmp_path, io = mktemp()
write(io, results.resultTypes[r_ix].value)
empty!(results.resultTypes[r_ix].value)
close(io)
push!(mmap_files, tmp_path)
end
Comment on lines +399 to +408
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my own understanding: you're using the variable name mmap_files, but actually these are just temp files on disk, is that correct? Or is there something else happening here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mmap_files is the path to each file where the big array is mmap-ed. These files are in /tmp and are deleted when the Julia process exits.

py_paths = tuple(mmap_files...)
py_lens = tuple(obj_lengths...)
mmap_files = nothing
obj_lengths = nothing
return py_paths, py_lens
end

function BraketSimulator.simulate(simulator_id::String, task_spec::String, py_inputs::String, shots::Int; kwargs...)
inputs = JSON3.read(py_inputs, Dict{String, Any})
jl_spec = BraketSimulator.OpenQasmProgram(BraketSimulator.braketSchemaHeader("braket.ir.openqasm.program", "1"), task_spec, inputs)
simulator = create_sim(simulator_id, shots)
jl_results = simulate(simulator, jl_spec, shots; kwargs...)
py_paths, py_lens = _mmap_large_result_values(jl_results)
py_results = JSON3.write(jl_results)
simulator = nothing
inputs = nothing
jl_spec = nothing
jl_results = nothing
return py_results, py_paths, py_lens
end
function BraketSimulator.simulate(simulator_id::String, task_specs::AbstractVector, py_inputs::String, shots::Int; kwargs...)
inputs = JSON3.read(py_inputs, Vector{Dict{String, Any}})
jl_specs = map(zip(task_specs, inputs)) do (task_spec, input)
BraketSimulator.OpenQasmProgram(BraketSimulator.braketSchemaHeader("braket.ir.openqasm.program", "1"), task_spec, input)
end
simulator = create_sim(simulator_id, shots)
jl_results = simulate(simulator, jl_specs, shots; kwargs...)
paths_and_lens = JSON3.write(map(_mmap_large_result_values, jl_results))
jsons = JSON3.write(jl_results)
simulator = nothing
jl_results = nothing
inputs = nothing
jl_specs = nothing
return jsons, paths_and_lens
end

include("result_types.jl")
include("properties.jl")
include("sv_simulator.jl")
Expand Down Expand Up @@ -699,6 +760,7 @@ include("dm_simulator.jl")
#pragma braket result probability
#pragma braket result expectation x(q[0])
#pragma braket result variance x(q[0]) @ y(q[1])
#pragma braket result variance y(q[0])
"""
shots_results_qasm = """
OPENQASM 3.0;
Expand All @@ -714,48 +776,58 @@ include("dm_simulator.jl")
simulator = StateVectorSimulator(5, 0)
oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), custom_qasm, nothing)
simulate(simulator, oq3_program, 100)
simulate("braket_sv_v2", custom_qasm, "{}", 100)

simulator = DensityMatrixSimulator(2, 0)
oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), noise_qasm, nothing)
simulate(simulator, oq3_program, 100)
simulate(simulator, [oq3_program, oq3_program], 100)
simulate("braket_dm_v2", noise_qasm, "{}", 100)
simulate("braket_dm_v2", [noise_qasm, noise_qasm], "[{}, {}]", 100)

simulator = StateVectorSimulator(3, 0)
oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), unitary_qasm, nothing)
simulate(simulator, oq3_program, 100)
simulate(simulator, [oq3_program, oq3_program], 100)
simulate("braket_sv_v2", unitary_qasm, "{}", 100)
simulate("braket_sv_v2", [unitary_qasm, unitary_qasm], "[{}, {}]", 100)

simulator = StateVectorSimulator(6, 0)
oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), sv_adder_qasm, Dict("a_in"=>3, "b_in"=>7))
simulate(simulator, oq3_program, 0)

simulate("braket_sv_v2", sv_adder_qasm, "{\"a_in\":3,\"b_in\":7}", 100)

simulator = StateVectorSimulator(16, 0)
oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), grcs_16_qasm, nothing)
simulate(simulator, oq3_program, 0)
simulate("braket_sv_v2", grcs_16_qasm, "{}", 0)

simulator = StateVectorSimulator(2, 0)
oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), vqe_qasm, nothing)
simulate(simulator, oq3_program, 100)
simulate("braket_sv_v2", vqe_qasm, "{}", 100)

sv_simulator = StateVectorSimulator(3, 0)
dm_simulator = DensityMatrixSimulator(3, 0)
oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), all_gates_qasm, Dict("theta"=>0.665))
simulate(sv_simulator, oq3_program, 100)
simulate(dm_simulator, oq3_program, 100)
simulate("braket_sv_v2", all_gates_qasm, "{\"theta\":0.665}", 100)
simulate("braket_dm_v2", all_gates_qasm, "{\"theta\":0.665}", 100)

sv_simulator = StateVectorSimulator(2, 0)
dm_simulator = DensityMatrixSimulator(2, 0)
sv_oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), sv_exact_results_qasm, nothing)
dm_oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), dm_exact_results_qasm, nothing)
results = simulate(sv_simulator, sv_oq3_program, 0)
map(StructTypes.lower, results.resultTypes)
results = simulate(dm_simulator, dm_oq3_program, 0)
map(StructTypes.lower, results.resultTypes)
simulate(sv_simulator, sv_oq3_program, 0)
simulate("braket_sv_v2", sv_exact_results_qasm, "{}", 0)
simulate(dm_simulator, dm_oq3_program, 0)
simulate("braket_dm_v2", dm_exact_results_qasm, "{}", 0)
oq3_program = OpenQasmProgram(braketSchemaHeader("braket.ir.openqasm.program", "1"), shots_results_qasm, nothing)
results = simulate(sv_simulator, oq3_program, 10)
map(StructTypes.lower, results.resultTypes)
results = simulate(dm_simulator, oq3_program, 10)
map(StructTypes.lower, results.resultTypes)
simulate(sv_simulator, oq3_program, 10)
simulate(dm_simulator, oq3_program, 10)
simulate("braket_sv_v2", shots_results_qasm, "{}", 10)
simulate("braket_dm_v2", shots_results_qasm, "{}", 10)
end
end
end # module BraketSimulator
Loading
Loading