Quantum Circuit
Snowflurry.QuantumCircuit
— TypeQuantumCircuit(
qubit_count::Int,
bit_count::Int,
instructions::Vector{AbstractInstruction},
name::String = "default"
)
QuantumCircuit(circuit::QuantumCircuit)
A data structure which describes a quantum circuit.
Fields
qubit_count::Int
– Largest qubit index (e.g., specifyingqubit_count=n
enables the use of qubits 1 to n).bit_count::Int
– Optional: Number of classical bits (i.e., result register size). Defaults toqubit_count
if unspecified.instructions::Vector{AbstractInstruction}
– Optional: Sequence ofAbstractInstructions
(Gates
andReadouts
) that operate on the qubits. Defaults to an empty Vector.name::String
– Optional: Name of the circuit and the corresponding job. It is used to identify the job when it is sent to a hardware or virtual QPU.
Examples
julia> c = QuantumCircuit(qubit_count = 2)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:
q[2]:
A QuantumCircuit
can be initialized with Gate
and Readout
structs:
julia> c = QuantumCircuit(
qubit_count = 2,
instructions = [
hadamard(1),
sigma_x(2),
control_x(1, 2),
readout(1, 1),
readout(2, 2)
])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H─────────*────✲───────
|
q[2]:───────X────X─────────✲──
A deep copy of a QuantumCircuit
can be obtained with the following function:
julia> c_copy = QuantumCircuit(c)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H─────────*────✲───────
|
q[2]:───────X────X─────────✲──
Snowflurry.get_num_qubits
— Functionget_num_qubits(x::AbstractOperator)
Returns the number of qubits associated with an Operator
.
Examples
julia> ρ = DenseOperator([1. 0.
0. 0.])
(2, 2)-element Snowflurry.DenseOperator:
Underlying data ComplexF64:
1.0 + 0.0im 0.0 + 0.0im
0.0 + 0.0im 0.0 + 0.0im
julia> get_num_qubits(ρ)
1
get_num_qubits(x::Union{Ket, Bra})
Returns the number of qubits associated with a Ket
or a Bra
.
Examples
julia> ψ = Ket([1., 0., 0., 0.])
4-element Ket{ComplexF64}:
1.0 + 0.0im
0.0 + 0.0im
0.0 + 0.0im
0.0 + 0.0im
julia> get_num_qubits(ψ)
2
get_num_qubits(circuit::QuantumCircuit)::Int
Returns the number of qubits in a circuit
.
Examples
julia> c = QuantumCircuit(qubit_count = 2);
julia> get_num_qubits(c)
2
Snowflurry.get_num_bits
— Functionget_num_bits(circuit::QuantumCircuit)::Int
Returns the number of classical bits in a circuit
.
Examples
julia> c = QuantumCircuit(qubit_count = 2, bit_count=3);
julia> get_num_bits(c)
3
Snowflurry.get_name
— Functionget_name(circuit::QuantumCircuit)::String
Returns the name of the circuit
and the corresponding job.
Examples
julia> c = QuantumCircuit(qubit_count = 2, name = "my_circuit");
julia> get_name(c)
"my_circuit"
Snowflurry.get_circuit_instructions
— Functionget_circuit_instructions(circuit::QuantumCircuit)::Vector{AbstractInstruction}
Returns the list of instructions in the circuit
.
Examples
julia> c = QuantumCircuit(qubit_count = 2, instructions = [hadamard(1), control_z(1, 2)]);
julia> get_circuit_instructions(c)
2-element Vector{AbstractInstruction}:
Gate Object: Snowflurry.Hadamard
Connected_qubits : [1]
Operator:
(2, 2)-element Snowflurry.DenseOperator:
Underlying data ComplexF64:
0.7071067811865475 + 0.0im 0.7071067811865475 + 0.0im
0.7071067811865475 + 0.0im -0.7071067811865475 + 0.0im
Gate Object: Snowflurry.ControlZ
Connected_qubits : [1, 2]
Operator:
(4, 4)-element Snowflurry.DenseOperator:
Underlying data ComplexF64:
1.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im
0.0 + 0.0im 1.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im
0.0 + 0.0im 0.0 + 0.0im 1.0 + 0.0im 0.0 + 0.0im
0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im -1.0 + 0.0im
Base.push!
— Functionpush!(circuit::QuantumCircuit, gates::AbstractGateSymbol...)
Inserts one or more gates
at the end of a circuit
.
A Vector
of AbstractGateSymbol
objects can be passed to this function by using splatting. More details about splatting are provided here.
Examples
julia> c = QuantumCircuit(qubit_count = 2);
julia> push!(c, hadamard(1), sigma_x(2))
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H───────
q[2]:───────X──
julia> push!(c, control_x(1,2))
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H─────────*──
|
q[2]:───────X────X──
julia> gate_list = [sigma_x(1), hadamard(2)];
julia> push!(c, gate_list...)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H─────────*────X───────
|
q[2]:───────X────X─────────H──
Base.pop!
— Functionpop!(circuit::QuantumCircuit)
Removes the last instruction from circuit.instructions
, and returns it.
Examples
julia> c = QuantumCircuit(qubit_count = 2);
julia> push!(c, hadamard(1), sigma_x(2))
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H───────
q[2]:───────X──
julia> push!(c, control_x(1, 2))
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H─────────*──
|
q[2]:───────X────X──
julia> pop!(c)
Gate Object: Snowflurry.ControlX
Connected_qubits : [1, 2]
Operator:
(4, 4)-element Snowflurry.DenseOperator:
Underlying data ComplexF64:
1.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im
0.0 + 0.0im 1.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im
0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 1.0 + 0.0im
0.0 + 0.0im 0.0 + 0.0im 1.0 + 0.0im 0.0 + 0.0im
julia> c
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H───────
q[2]:───────X──
Base.append!
— Functionappend!(base_circuit::QuantumCircuit, circuits_to_append::QuantumCircuit...)
Appends one or more circuits_to_append
to the base_circuit
.
The circuits_to_append
cannot contain more qubits than the base_circuit
.
Examples
julia> base = QuantumCircuit(qubit_count = 2, instructions = [sigma_x(1)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X──
q[2]:─────
julia> append_1 = QuantumCircuit(qubit_count = 1, instructions = [sigma_z(1)])
Quantum Circuit Object:
qubit_count: 1
bit_count: 1
q[1]:──Z──
julia> append_2 = QuantumCircuit(qubit_count = 2, instructions = [control_x(1, 2)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──*──
|
q[2]:──X──
julia> append!(base, append_1, append_2)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X────Z────*──
|
q[2]:────────────X──
Base.prepend!
— Functionprepend!(base_circuit::QuantumCircuit, circuits_to_prepend::QuantumCircuit...)
Prepends one or more circuits_to_prepend
to the base_circuit
.
The order of the circuits_to_prepend
is maintained (i.e., circuits_to_prepend[1]
will appear leftmost in base_circuit
). The circuits_to_prepend
cannot contain more qubits than the base_circuit
.
Examples
julia> base = QuantumCircuit(qubit_count = 2, instructions = [sigma_x(1)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X──
q[2]:─────
julia> prepend_1 = QuantumCircuit(qubit_count = 1, instructions = [sigma_z(1)])
Quantum Circuit Object:
qubit_count: 1
bit_count: 1
q[1]:──Z──
julia> prepend_2 = QuantumCircuit(qubit_count = 2, instructions = [control_x(1, 2)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──*──
|
q[2]:──X──
julia> prepend!(base, prepend_1, prepend_2)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Z────*────X──
|
q[2]:───────X───────
Snowflurry.update_circuit_qubit_count
— Functionupdate_circuit_qubit_count(
quantum_cicuit::QuantumCircuit,
qubit_count::Int,
)::QuantumCircuit
Updates the qubit_count
of the quantum_circuit
.
Examples
julia> circuit = QuantumCircuit(qubit_count = 1, instructions = [sigma_x(1)])
Quantum Circuit Object:
qubit_count: 1
bit_count: 1
q[1]:──X──
julia> larger_circuit = update_circuit_qubit_count(circuit, 2)
Quantum Circuit Object:
qubit_count: 2
bit_count: 1
q[1]:──X──
q[2]:─────
Snowflurry.simulate
— Functionsimulate(circuit::QuantumCircuit)::Ket
Performs an ideal simulation of the circuit
and returns the final quantum state (i.e. the wave function). The simulator assumes that the initial state $\Psi$ corresponds to the zeroth Fock basis, i.e.: ψ = fock(0, 2^get_num_qubits(circuit))
. The zeroth Fock basis corresponds to the initial state of most superconducting quantum processors, i.e.:
\[|\Psi\rangle = |0\rangle^{\otimes n},\]
where $n$ is the number of qubits.
The input circuit
must not include Readout
instructions. Use simulate_shots
for the simulation of circuits
with Readout
instructions.
The simulation utilizes the approach described in Listing 5 of Suzuki et. al. (2021).
Examples
julia> c = QuantumCircuit(qubit_count = 2);
julia> push!(c, hadamard(1))
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H──
q[2]:─────
julia> push!(c, control_x(1, 2))
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H────*──
|
q[2]:───────X──
julia> ket = simulate(c)
4-element Ket{ComplexF64}:
0.7071067811865475 + 0.0im
0.0 + 0.0im
0.0 + 0.0im
0.7071067811865475 + 0.0im
Snowflurry.simulate_shots
— Functionsimulate_shots(c::QuantumCircuit, shots_count::Int = 100)
Emulates a quantum computer by running a circuit for a given number of shots and returning measurement results, as prescribed by the Readout
instructions present in the circuit. The distribution of measured states depends on the coefficients of the resulting state Ket.
Examples
julia> c = QuantumCircuit(qubit_count = 2);
julia> push!(c, hadamard(1), control_x(1, 2), readout(1, 1), readout(2, 2))
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H────*────✲───────
|
q[2]:───────X─────────✲──
julia> simulate_shots(c, 99)
99-element Vector{String}:
"11"
"00"
"11"
"11"
"11"
"11"
"11"
"00"
"00"
"11"
⋮
"00"
"00"
"11"
"00"
"00"
"00"
"00"
"00"
"00"
Snowflurry.get_measurement_probabilities
— Methodget_measurement_probabilities(
circuit::QuantumCircuit,
[target_qubits::Vector{<:Integer}]
)::AbstractVector{<:Real}
Returns a list of the measurement probabilities for the target_qubits
in the circuit
.
If no target_qubits
are provided, the probabilities are computed for all the qubits.
The measurement probabilities are listed from the smallest to the largest computational basis state. For instance, for a 2-qubit QuantumCircuit
, the probabilities are listed for $\left|00\right\rangle$, $\left|01\right\rangle$, $\left|10\right\rangle$, and $\left|11\right\rangle$.
By convention, qubit 1 is the leftmost bit, followed by every subsequent qubit. The notation $\left|10\right\rangle$ indicates that qubit 1 is in state $\left|1\right\rangle$ and qubit 2 in state $\left|0\right\rangle$.
Examples
The following example constructs a QuantumCircuit
where the probability of measuring $\left|10\right\rangle$ is 50% and the probability of measuring $\left|11\right\rangle$ is also 50%:
julia> circuit = QuantumCircuit(qubit_count = 2);
julia> push!(circuit, hadamard(1), sigma_x(2))
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H───────
q[2]:───────X──
julia> get_measurement_probabilities(circuit)
4-element Vector{Float64}:
0.0
0.4999999999999999
0.0
0.4999999999999999
For the same circuit
, the probability of measuring qubit 2 and finding 1 is 100%:
julia> target_qubit = [2];
julia> get_measurement_probabilities(circuit, target_qubit)
2-element Vector{Float64}:
0.0
0.9999999999999998
Base.inv
— Methodinv(circuit::QuantumCircuit)
Return a QuantumCircuit
which is the inverse of the input circuit
. Each gate is replaced by its corresponding inverse, and the order of gates is reversed.
Examples
julia> c = QuantumCircuit(qubit_count = 2);
julia> push!(c, rotation_y(1, pi/4));
julia> push!(c, control_x(1, 2))
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Ry(0.7854)────*──
|
q[2]:────────────────X──
julia> inv(c)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──*────Ry(-0.7854)──
|
q[2]:──X─────────────────
Snowflurry.get_num_gates_per_type
— Functionget_num_gates_per_type(
circuit::QuantumCircuit
)::AbstractDict{<: AbstractString, <:Integer}
Returns a dictionary listing the number of gates of each type found in the circuit
.
The dictionary keys are the instruction symbols of the gates while the values are the number of gates found.
Examples
julia> c = QuantumCircuit(qubit_count = 2);
julia> push!(c, hadamard(1), hadamard(2));
julia> push!(c, control_x(1, 2));
julia> push!(c, hadamard(2))
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H─────────*───────
|
q[2]:───────H────X────H──
julia> get_num_gates_per_type(c)
Dict{String, Int64} with 2 entries:
"h" => 3
"cx" => 1
Snowflurry.get_num_gates
— Functionget_num_gates(circuit::QuantumCircuit)::Integer
Returns the number of gates in the circuit
.
Examples
julia> c = QuantumCircuit(qubit_count = 2);
julia> push!(c, hadamard(1), hadamard(2));
julia> push!(c, control_x(1, 2))
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H─────────*──
|
q[2]:───────H────X──
julia> get_num_gates(c)
3
Snowflurry.serialize_job
— Functionserialize_job(circuit::QuantumCircuit,shot_count::Integer,host::String)
Creates a JSON-formatted string that contains the circuit configuration that will be sent to a QPU
service. The URL for the QPU
service corresponds to host
while the number of circuit executions is equal to shot_count
.
Qubit and bit indices use zero-based indexing in the JSON encoding.
Examples
julia> c = QuantumCircuit(
qubit_count = 2,
instructions = [sigma_x(1)],
name = "sigma_x job"
)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X──
q[2]:─────
julia> serialize_job(c, 10, "machine", "project_id")
"{\"shotCount\":10,\"name\":\"sigma_x job\",\"machineName\":\"machine\",\"projectID\":\"project_id\",\"type\":\"circuit\",\"circuit\":{\"operations\":[{\"parameters\":{},\"type\":\"x\",\"qubits\":[0]}],\"bitCount\":2,\"qubitCount\":2}}"
Snowflurry.transpile
— Functiontranspile(transpiler::Transpiler, circuit::QuantumCircuit)::QuantumCircuit
Returns a transpiled copy of the circuit
. The transpilation process depends on the transpiler
.
The following transpilers are available:
SequentialTranspiler
CompressSingleQubitGatesTranspiler
CastSwapToCZGateTranspiler
CastCXToCZGateTranspiler
CastISwapToCZGateTranspiler
CastToffoliToCXGateTranspiler
CastRootZZToZ90AndCZGateTranspiler
CastToPhaseShiftAndHalfRotationXTranspiler
CastUniversalToRzRxRzTranspiler
CastRxToRzAndHalfRotationXTranspiler
SimplifyRxGatesTranspiler
SwapQubitsForAdjacencyTranspiler
SimplifyRzGatesTranspiler
CompressRzGatesTranspiler
RemoveSwapBySwappingGatesTranspiler
SimplifyTrivialGatesTranspiler
UnsupportedGatesTranspiler
ReadoutsAreFinalInstructionsTranspiler
CircuitContainsAReadoutTranspiler
ReadoutsDoNotConflictTranspiler
DecomposeSingleTargetSingleControlGatesTranspiler
RejectNonNativeInstructionsTranspiler
RejectGatesOnExcludedPositionsTranspiler
RejectGatesOnExcludedConnectionsTranspiler
Example
julia> transpiler = CastCXToCZGateTranspiler();
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [control_x(1, 2)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──*──
|
q[2]:──X──
julia> transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:───────*───────
|
q[2]:──H────Z────H──
Snowflurry.SequentialTranspiler
— TypeSequentialTranspiler(Vector{<:Transpiler})
Composite transpiler object which is constructed from an array of Transpiler
stages. Calling transpile(::SequentialTranspiler,::QuantumCircuit)
will apply each stage in sequence to the input circuit and return a transpiled output circuit. The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
Examples
julia> transpiler = SequentialTranspiler([
CompressSingleQubitGatesTranspiler(),
CastToPhaseShiftAndHalfRotationXTranspiler()
]);
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [sigma_x(1), hadamard(1)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X────H──
q[2]:──────────
julia> transpile(transpiler,circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Z────X_90────Z_90────X_m90────Z──
q[2]:───────────────────────────────────
julia> circuit = QuantumCircuit(
qubit_count = 3,
instructions = [
sigma_x(1),
sigma_y(1),
control_x(2,3),
phase_shift(1,π/3)
])
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:──X────Y─────────P(1.0472)──
q[2]:────────────*───────────────
|
q[3]:────────────X───────────────
julia> transpile(transpiler,circuit)
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:──P(-2.0944)───────
q[2]:────────────────*──
|
q[3]:────────────────X──
Snowflurry.CompressSingleQubitGatesTranspiler
— TypeCompressSingleQubitGatesTranspiler
Transpiler stage which gathers all single-qubit gates sharing a common target in an input circuit and combines them into single Universal
gates in a new circuit. Gate ordering may differ when gates are applied to different qubits, but the input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
Examples
julia> transpiler = CompressSingleQubitGatesTranspiler();
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [sigma_x(1), sigma_y(1)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X────Y──
q[2]:──────────
julia> transpiled_circuit=transpile(transpiler,circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──U(θ=0.0000,ϕ=3.1416,λ=0.0000)──
q[2]:─────────────────────────────────
julia> compare_circuits(circuit,transpiled_circuit)
true
julia> circuit = QuantumCircuit(
qubit_count = 3,
instructions = [
sigma_x(1)
sigma_y(1)
control_x(2,3)
phase_shift(1,π/3)
])
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:──X────Y─────────P(1.0472)──
q[2]:────────────*───────────────
|
q[3]:────────────X───────────────
julia> transpiled_circuit=transpile(transpiler,circuit)
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:──U(θ=0.0000,ϕ=-2.0944,λ=0.0000)───────
q[2]:────────────────────────────────────*──
|
q[3]:────────────────────────────────────X──
julia> compare_circuits(circuit,transpiled_circuit)
true
Snowflurry.CastSwapToCZGateTranspiler
— TypeCastSwapToCZGateTranspiler
Transpiler stage which expands all Swap gates into CZ
gates and single-qubit gates. The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
Examples
julia> transpiler = CastSwapToCZGateTranspiler();
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [swap(1, 2)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──☒──
|
q[2]:──☒──
julia> transpile(transpiler,circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:───────────*────Y_m90────────────*────Y_90─────────────*──────────
| | |
q[2]:──Y_m90────Z─────────────Y_90────Z────────────Y_m90────Z────Y_90──
Snowflurry.CastCXToCZGateTranspiler
— TypeCastCXToCZGateTranspiler
Transpiler stage which expands all CX
gates into CZ
and Hadamard
gates. The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
Examples
julia> transpiler = CastCXToCZGateTranspiler();
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [control_x(1, 2)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──*──
|
q[2]:──X──
julia> transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:───────*───────
|
q[2]:──H────Z────H──
Snowflurry.CastISwapToCZGateTranspiler
— TypeCastISwapToCZGateTranspiler
Transpiler stage which expands all ISwap
and ISwapDagger
gates into CZ
gates and single-qubit gates. The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
Examples
julia> transpiler = CastISwapToCZGateTranspiler();
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [iswap(1, 2)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──x──
|
q[2]:──x──
julia> transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Y_m90─────────────*────Y_90─────────────*────Y_90──────────
| |
q[2]:───────────X_m90────Z────────────X_m90────Z────────────X_90──
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [iswap_dagger(1, 2)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──x†──
|
q[2]:──x†──
julia> transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Y_m90─────────────*────Y_m90────────────*────Y_90──────────
| |
q[2]:───────────X_m90────Z─────────────X_90────Z────────────X_90──
Snowflurry.CastToffoliToCXGateTranspiler
— TypeCastToffoliToCXGateTranspiler
Transpiler stage which expands all Toffoli gates into CX
gates and single-qubit gates. The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
Examples
julia> transpiler = CastToffoliToCXGateTranspiler();
julia> circuit = QuantumCircuit(qubit_count = 3, instructions = [toffoli(1, 2, 3)])
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:──*──
|
q[2]:──*──
|
q[3]:──X──
julia> transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:──────────────────*────────────────────*──────────────*─────────T──────────*──
| | | |
q[2]:───────*──────────|─────────*──────────|────T─────────X──────────────T†────X──
| | | |
q[3]:──H────X────T†────X────T────X────T†────X─────────T─────────H──────────────────
Snowflurry.CastRootZZToZ90AndCZGateTranspiler
— TypeCastRootZZToZ90AndCZGateTranspiler
Transpiler stage which converts all RootZZ
and RootZZDagger
gates into Z90
(or ZM90
) gates and a ControlZ
gate. The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
Examples
julia> transpiler = CastRootZZToZ90AndCZGateTranspiler();
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [root_zz(1, 2)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──√ZZ──
|
q[2]:──√ZZ──
julia> transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Z_90────────────*──
|
q[2]:──────────Z_90────Z──
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [root_zz_dagger(1, 2)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──√ZZ†──
|
q[2]:──√ZZ†──
julia> transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Z_m90─────────────*──
|
q[2]:───────────Z_m90────Z──
Snowflurry.CastToPhaseShiftAndHalfRotationXTranspiler
— TypeCastToPhaseShiftAndHalfRotationXTranspiler,
Transpiler stage which converts all single-qubit gates in the input circuit into combinations of PhaseShift
and RotationX
with angle π/2 in the output circuit. For any gate in the input circuit, the number of gates in the output varies between zero and 5. The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
Fields
atol::Real
– Absolute tolerance for the comparison of rotation angles (default = 1e-6).
Examples
julia> transpiler = CastToPhaseShiftAndHalfRotationXTranspiler();
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [sigma_x(1)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X──
q[2]:─────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Z────X_90────Z────X_m90──
q[2]:───────────────────────────
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [sigma_y(1)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Y──
q[2]:─────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X_90────Z────X_m90──
q[2]:──────────────────────
julia> compare_circuits(circuit, transpiled_circuit)
true
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [universal(1, 0., 0., 0.)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──U(θ=0.0000,ϕ=0.0000,λ=0.0000)──
q[2]:─────────────────────────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:
q[2]:
julia> compare_circuits(circuit, transpiled_circuit)
true
Snowflurry.CastUniversalToRzRxRzTranspiler
— TypeCastUniversalToRzRxRzTranspiler
Transpiler stage which finds Universal
gates in an input circuit and casts them into a sequence of PhaseShift
(P), RotationX
(Rx) and PhaseShift
(P) gates in a new circuit. The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
Examples
julia> transpiler = CastUniversalToRzRxRzTranspiler();
julia> circuit = QuantumCircuit(
qubit_count = 2,
instructions = [universal(1, π/2, π/4, π/8)]
)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──U(θ=1.5708,ϕ=0.7854,λ=0.3927)──
q[2]:─────────────────────────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──P(-1.1781)────Rx(1.5708)────P(2.3562)──
q[2]:─────────────────────────────────────────
julia> compare_circuits(circuit, transpiled_circuit)
true
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [universal(1, 0, π/4, 0)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──U(θ=0.0000,ϕ=0.7854,λ=0.0000)──
q[2]:─────────────────────────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──P(-1.5708)────Rx(0.0000)────P(2.3562)──
q[2]:─────────────────────────────────────────
julia> compare_circuits(circuit,transpiled_circuit)
true
Snowflurry.CastRxToRzAndHalfRotationXTranspiler
— TypeCastRxToRzAndHalfRotationXTranspiler
Transpiler stage which finds RotationX(θ)
gates in an input circuit and converts (casts) them into a sequence of gates (Z90
, X90
, PhaseShift(θ)
, XM90
, and ZM90
) in a new circuit. The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
Examples
julia> transpiler=CastRxToRzAndHalfRotationXTranspiler();
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [rotation_x(1,π/8)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Rx(0.3927)──
q[2]:──────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Z_90────X_90────P(0.3927)────X_m90────Z_m90──
q[2]:───────────────────────────────────────────────
julia> compare_circuits(circuit, transpiled_circuit)
true
Snowflurry.SimplifyRxGatesTranspiler
— TypeSimplifyRxGatesTranspiler
Transpiler stage which finds RotationX
gates in an input circuit and, based on their angle theta, casts them to one of the right-angle RotationX
gates (SigmaX
, X90
, or XM90
). In the case where theta≈0.
, the gate is removed. The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
Fields
atol::Real
– Absolute tolerance for the comparison of rotation angles (default = 1e-6).
Examples
julia> transpiler = SimplifyRxGatesTranspiler();
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [rotation_x(1, pi/2)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Rx(1.5708)──
q[2]:──────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X_90──
q[2]:────────
julia> compare_circuits(circuit, transpiled_circuit)
true
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [rotation_x(1, pi)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Rx(3.1416)──
q[2]:──────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X──
q[2]:─────
julia> compare_circuits(circuit, transpiled_circuit)
true
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [rotation_x(1, 0.)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Rx(0.0000)──
q[2]:──────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:
q[2]:
julia> compare_circuits(circuit, transpiled_circuit)
true
Snowflurry.SwapQubitsForAdjacencyTranspiler
— TypeSwapQubitsForAdjacencyTranspiler
Transpiler stage which adds Swap
gates around multi-qubit gates so that the final Operator
acts on adjacent qubits. The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
Fields
connectivity::AbstractConnectivity
– Connectivity for the placement ofSwap
gates.
Examples
julia> transpiler = SwapQubitsForAdjacencyTranspiler(LineConnectivity(6));
julia> circuit = QuantumCircuit(qubit_count = 6, instructions = [toffoli(4, 6, 1)])
Quantum Circuit Object:
qubit_count: 6
bit_count: 6
q[1]:──X──
|
q[2]:──|──
|
q[3]:──|──
|
q[4]:──*──
|
q[5]:──|──
|
q[6]:──*──
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 6
bit_count: 6
q[1]:───────────────────────────X───────────────────────────
|
q[2]:───────☒───────────────────*───────────────────☒───────
| | |
q[3]:──☒────☒──────────────☒────*────☒──────────────☒────☒──
| | | |
q[4]:──☒──────────────☒────☒─────────☒────☒──────────────☒──
| |
q[5]:────────────☒────☒───────────────────☒────☒────────────
| |
q[6]:────────────☒─────────────────────────────☒────────────
julia> compare_circuits(circuit, transpiled_circuit)
true
Snowflurry.SimplifyRzGatesTranspiler
— TypeSimplifyRzGatesTranspiler
Transpiler stage which finds PhaseShift
gates in an input circuit and, based on their phase angle phi, casts them to one of the right-angle RotationZ
gates (SigmaZ
, Z90
, ZM90
, Pi8
or Pi8Dagger
). In the case where phi≈0.
, the gate is removed. The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase). The tolerance used for Base.isapprox()
in each case can be set by passing an optional argument to the Transpiler
, e.g: transpiler=SimplifyRzGatesTranspiler(1.0e-10)
Fields
atol::Real
– Absolute tolerance for the comparison of rotation angles (default = 1e-6).
Examples
julia> transpiler = SimplifyRzGatesTranspiler();
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [phase_shift(1, pi/2)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──P(1.5708)──
q[2]:─────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Z_90──
q[2]:────────
julia> compare_circuits(circuit, transpiled_circuit)
true
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [phase_shift(1, pi)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──P(3.1416)──
q[2]:─────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Z──
q[2]:─────
julia> compare_circuits(circuit, transpiled_circuit)
true
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [phase_shift(1, 0.)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──P(0.0000)──
q[2]:─────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:
q[2]:
julia> compare_circuits(circuit, transpiled_circuit)
true
Snowflurry.CompressRzGatesTranspiler
— TypeCompressRzGatesTranspiler
Transpiler stage which gathers all Rz-type gates sharing a common target in an input circuit and combines them into a single PhaseShift gate in a new circuit. Gates ordering may differ when gates are applied to different qubits, but the input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
Examples
julia> transpiler = CompressRzGatesTranspiler();
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [sigma_z(1), z_90(1)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──Z────Z_90──
q[2]:─────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──P(-1.5708)──
q[2]:──────────────
julia> compare_circuits(circuit, transpiled_circuit)
true
julia> circuit = QuantumCircuit(
qubit_count = 3,
instructions = [sigma_z(1), pi_8(1), control_x(2,3), z_minus_90(1)]
)
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:──Z────T─────────Z_m90──
q[2]:────────────*───────────
|
q[3]:────────────X───────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:──P(2.3562)───────
q[2]:───────────────*──
|
q[3]:───────────────X──
julia> compare_circuits(circuit, transpiled_circuit)
true
Snowflurry.RemoveSwapBySwappingGatesTranspiler
— TypeRemoveSwapBySwappingGatesTranspiler
Transipler stage which removes the Swap
gates from the circuit
assuming all-to-all connectivity.
This transpiler stage assumes that the input state is $|0\rangle^{\otimes N}$, where $N$ is the number of qubits. The stage should not be used on sub-circuits where the input state is not $|0\rangle^{\otimes N}$.
This transpiler stage eliminates Swap
gates by moving the gates preceding each Swap
gate.
Examples
julia> transpiler = RemoveSwapBySwappingGatesTranspiler();
julia> circuit = QuantumCircuit(
qubit_count = 2,
instructions = [hadamard(1), swap(1, 2), sigma_x(2)]
)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H────☒───────
|
q[2]:───────☒────X──
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──────────
q[2]:──H────X──
Snowflurry.SimplifyTrivialGatesTranspiler
— TypeSimplifyTrivialGatesTranspiler
Transpiler stage which removes gates that have no effect on the state Ket
(e.g. Identity
) and parameterized gates with null parameters (e.g. rotation_x(target, 0.)
). The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase). The tolerance used for Base.isapprox()
in each case can be set by passing an optional argument to the transpiler (e.g. transpiler=SimplifyTrivialGatesTranspiler(1.0e-10)
).
Fields
atol::Real
– Absolute tolerance for the comparison of rotation angles (default = 1e-6).
Examples
julia> transpiler = SimplifyTrivialGatesTranspiler();
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [identity_gate(1)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──I──
q[2]:─────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:
q[2]:
julia> compare_circuits(circuit, transpiled_circuit)
true
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [phase_shift(1, 0.)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──P(0.0000)──
q[2]:─────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:
q[2]:
julia> compare_circuits(circuit, transpiled_circuit)
true
julia> circuit = QuantumCircuit(qubit_count = 2, instructions = [universal(1, 0., 0., 0.)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──U(θ=0.0000,ϕ=0.0000,λ=0.0000)──
q[2]:─────────────────────────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:
q[2]:
julia> compare_circuits(circuit, transpiled_circuit)
true
Snowflurry.UnsupportedGatesTranspiler
— TypeUnsupportedGatesTranspiler
Transpiler stage which throws a NotImplementedError
if a Controlled
gate that operates on more than two qubits is found.
Examples
julia> transpiler = UnsupportedGatesTranspiler();
julia> circuit = QuantumCircuit(qubit_count=2, instructions = [control_z(1, 2)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──*──
|
q[2]:──Z──
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──*──
|
q[2]:──Z──
julia> invalid_circuit = QuantumCircuit(
qubit_count = 4,
instructions = [controlled(hadamard(2), [1, 3])],
)
Quantum Circuit Object:
qubit_count: 4
bit_count: 4
q[1]:──*──
|
q[2]:──H──
|
q[3]:──*──
q[4]:─────
julia> transpiled_circuit = transpile(transpiler, invalid_circuit)
ERROR: NotImplementedError{Gate{Controlled{Snowflurry.Hadamard}}}(:Transpiler, Gate Object: Controlled{Snowflurry.Hadamard}
[...]
Snowflurry.ReadoutsAreFinalInstructionsTranspiler
— TypeReadoutsAreFinalInstructionsTranspiler
Transpiler stage which ensures that each Readout
instruction is the last operation on each qubit where readouts are present. It also verifies that repeated readouts on the same qubit do not occur. An error is thrown if these verifications fail. This transpiler stage leaves the QuantumCircuit
unchanged.
Examples
julia> transpiler = ReadoutsAreFinalInstructionsTranspiler();
julia> circuit = QuantumCircuit(qubit_count=2, instructions = [hadamard(1), readout(1,1)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H────✲──
q[2]:──────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H────✲──
q[2]:──────────
julia> circuit = QuantumCircuit(
qubit_count=2,
instructions = [hadamard(1), readout(1,1), sigma_x(1)]
)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H────✲────X──
q[2]:───────────────
julia> transpiled_circuit = transpile(transpiler, circuit)
ERROR: AssertionError: Cannot perform `Gate` following `Readout` on qubit: 1
[...]
julia> circuit = QuantumCircuit(qubit_count=2, instructions = [readout(1,1), readout(1,2)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──✲────✲──
q[2]:──────────
julia> transpiled_circuit = transpile(transpiler, circuit)
ERROR: AssertionError: Found multiple `Readouts` on qubit: 1
[...]
Snowflurry.CircuitContainsAReadoutTranspiler
— TypeCircuitContainsAReadoutTranspiler
A transpiler stage which ensures that at least one Readout
instruction is present in the QuantumCircuit
. Otherwise, an error is thrown. This transpiler stage leaves the QuantumCircuit
unchanged.
Examples
julia> transpiler = CircuitContainsAReadoutTranspiler();
julia> circuit = QuantumCircuit(qubit_count=2, instructions = [hadamard(1), readout(1,1)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H────✲──
q[2]:──────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H────✲──
q[2]:──────────
julia> circuit = QuantumCircuit(qubit_count=2, instructions = [hadamard(1)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H──
q[2]:─────
julia> transpiled_circuit = transpile(transpiler, circuit)
ERROR: ArgumentError: QuantumCircuit is missing a `Readout`. Would not return any result.
[...]
Snowflurry.ReadoutsDoNotConflictTranspiler
— TypeReadoutsDoNotConflictTranspiler
Transpiler stage which ensures that each Readout
instruction present in the QuantumCircuit
does not have conflicting destination bits, Otherwise, an error is thrown. This transpiler stage leaves the QuantumCircuit
unchanged.
Examples
julia> transpiler = ReadoutsDoNotConflictTranspiler();
julia> circuit = QuantumCircuit(qubit_count=2, instructions = [hadamard(1), readout(1,1)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H────✲──
q[2]:──────────
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──H────✲──
q[2]:──────────
julia> circuit = QuantumCircuit(qubit_count=2, instructions = [readout(1,1), readout(2,1)])
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──✲───────
q[2]:───────✲──
julia> transpiled_circuit = transpile(transpiler, circuit)
ERROR: ArgumentError: `Readouts` in `QuantumCircuit` have conflicting destination bit: 1
[...]
Snowflurry.DecomposeSingleTargetSingleControlGatesTranspiler
— TypeDecomposeSingleTargetSingleControlGatesTranspiler
Transpiler stage which finds single-control, single-target Controlled
gates in an input circuit and casts them into a sequence of RotationZ
(Rz), ControlX
, Universal
(U) and PhaseShift
(P) gates in a new, equivalent circuit. For reference, see Nielsen and Chuang, "Quantum Computation and Quantum Information", p. 180. The input and output circuits perform the same operation on an arbitrary state Ket
(up to a global phase).
If a global phase is applied by the kernel of the Controlled
gate on the target qubit, this decomposition preserves it.
For instance, rotation_z(pi)
and phase_shift(pi)
kernels will yield results with a phase offset.
Examples
julia> transpiler = DecomposeSingleTargetSingleControlGatesTranspiler();
julia> circuit = QuantumCircuit(
qubit_count = 2,
instructions = [sigma_x(1), controlled(rotation_z(2, pi), [1])]
)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X────────*───────
|
q[2]:───────Rz(3.1416)──
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X───────────────────*──────────────────────────────────────*───────────────────────────────────
| |
q[2]:───────Rz(-1.5708)────X────U(θ=0.0000,ϕ=-1.5708,λ=0.0000)────X────U(θ=0.0000,ϕ=3.1416,λ=0.0000)──
julia> compare_circuits(circuit, transpiled_circuit)
true
julia> simulate(transpiled_circuit)
4-element Ket{ComplexF64}:
0.0 + 0.0im
-0.0 + 0.0im
0.7071067811865477 - 0.7071067811865474im
0.0 + 0.0im
julia> circuit = QuantumCircuit(
qubit_count = 2,
instructions = [sigma_x(1), controlled(phase_shift(2, pi), [1])]
)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X────────*──────
|
q[2]:───────P(3.1416)──
julia> transpiled_circuit = transpile(transpiler, circuit)
Quantum Circuit Object:
qubit_count: 2
bit_count: 2
q[1]:──X───────────────────*──────────────────────────────────────*─────────────────────────────────────P(1.5708)──
| |
q[2]:───────Rz(-1.5708)────X────U(θ=0.0000,ϕ=-1.5708,λ=0.0000)────X────U(θ=0.0000,ϕ=3.1416,λ=0.0000)───────────────
julia> compare_circuits(circuit,transpiled_circuit)
true
julia> simulate(circuit)
4-element Ket{ComplexF64}:
0.0 + 0.0im
0.0 + 0.0im
1.0 + 0.0im
0.0 + 0.0im
Snowflurry.RejectNonNativeInstructionsTranspiler
— TypeRejectNonNativeInstructionsTranspiler
Transpiler stage which throws a DomainError
if a non-native Instruction
is found in the circuit
. The circuit
remains unchanged if no error is thrown.
See is_native_instruction
for additional information about native instructions.
Fields
- connectivity::AbstractConnectivity – Connectivity which specifies the connections on which two-qubit gates can be applied.
- native_gates::Vector{DataType} – List of native gates. The gates that are native to the Anyon QPUs are used by default.
Examples
julia> connectivity = LineConnectivity(4)
LineConnectivity{4}
1──2──3──4
julia> default_transpiler = RejectNonNativeInstructionsTranspiler(connectivity);
julia> invalid_circuit = QuantumCircuit(
qubit_count = 4,
instructions = [sigma_x(4), control_z(1, 3)],
)
Quantum Circuit Object:
qubit_count: 4
bit_count: 4
q[1]:───────*──
|
q[2]:───────|──
|
q[3]:───────Z──
q[4]:──X───────
julia> transpile(default_transpiler, invalid_circuit)
ERROR: DomainError with LineConnectivity{4}
1──2──3──4
[...]
julia> valid_circuit = QuantumCircuit(
qubit_count = 4,
instructions = [sigma_x(4), control_z(1, 2)],
)
Quantum Circuit Object:
qubit_count: 4
bit_count: 4
q[1]:───────*──
|
q[2]:───────Z──
q[3]:──────────
q[4]:──X───────
julia> transpiled_circuit = transpile(default_transpiler, valid_circuit)
Quantum Circuit Object:
qubit_count: 4
bit_count: 4
q[1]:───────*──
|
q[2]:───────Z──
q[3]:──────────
q[4]:──X───────
julia> custom_circuit = QuantumCircuit(
qubit_count = 4,
instructions = [control_x(2, 3)],
)
Quantum Circuit Object:
qubit_count: 4
bit_count: 4
q[1]:─────
q[2]:──*──
|
q[3]:──X──
q[4]:─────
julia> transpile(default_transpiler, custom_circuit)
ERROR: DomainError with LineConnectivity{4}
1──2──3──4
[...]
julia> custom_transpiler = RejectNonNativeInstructionsTranspiler(
connectivity,
[Snowflurry.ControlX]
);
julia> transpiled_circuit = transpile(custom_transpiler, custom_circuit)
Quantum Circuit Object:
qubit_count: 4
bit_count: 4
q[1]:─────
q[2]:──*──
|
q[3]:──X──
q[4]:─────
Snowflurry.RejectGatesOnExcludedPositionsTranspiler
— TypeRejectGatesOnExcludedPositionsTranspiler
Transpiler stage which throws a DomainError
if an Instruction
in the circuit
operates on an excluded qubit. The excluded qubits are specified with the parameter excluded_positions
in certain AbstractConnectivity
objects. The circuit
remains unchanged if no error is thrown.
Fields
- connectivity::AbstractConnectivity – Connectivity where the
excluded_positions
are specified.
Examples
julia> excluded_positions = [2];
julia> connectivity = LineConnectivity(4, excluded_positions)
LineConnectivity{4}
1──2──3──4
excluded positions: [2]
julia> transpiler = RejectGatesOnExcludedPositionsTranspiler(connectivity);
julia> invalid_circuit = QuantumCircuit(
qubit_count = 4,
instructions = [sigma_x(4), control_z(1, 2)],
)
Quantum Circuit Object:
qubit_count: 4
bit_count: 4
q[1]:───────*──
|
q[2]:───────Z──
q[3]:──────────
q[4]:──X───────
julia> transpile(transpiler, invalid_circuit)
ERROR: DomainError with LineConnectivity{4}
1──2──3──4
excluded positions: [2]
:
the Gate{Snowflurry.ControlZ} on qubits [1, 2] cannot be applied since qubit 2 is unavailable
[...]
julia> valid_circuit = QuantumCircuit(
qubit_count = 4,
instructions = [sigma_x(1), control_z(3, 4)],
)
Quantum Circuit Object:
qubit_count: 4
bit_count: 4
q[1]:──X───────
q[2]:──────────
q[3]:───────*──
|
q[4]:───────Z──
julia> transpiled_circuit = transpile(transpiler, valid_circuit)
Quantum Circuit Object:
qubit_count: 4
bit_count: 4
q[1]:──X───────
q[2]:──────────
q[3]:───────*──
|
q[4]:───────Z──
Snowflurry.RejectGatesOnExcludedConnectionsTranspiler
— TypeRejectGatesOnExcludedConnectionsTranspiler
Transpiler stage which throws a DomainError
if an Instruction
in the circuit
operates on an excluded connection. The excluded connections are specified with the parameter excluded_connections
in certain AbstractConnectivity
objects. The function returns the same circuit
if no error is thrown.
Fields
- connectivity::AbstractConnectivity – Connectivity where the
excluded_connections
are specified.
Examples
julia> excluded_positions = Int[];
julia> excluded_connections = [(2, 3)];
julia> connectivity = LineConnectivity(4, excluded_positions, excluded_connections)
LineConnectivity{4}
1──2──3──4
excluded connections: [(2, 3)]
julia> transpiler = RejectGatesOnExcludedConnectionsTranspiler(connectivity);
julia> invalid_circuit = QuantumCircuit(
qubit_count = 4,
instructions = [sigma_x(4), control_z(3, 2)],
)
Quantum Circuit Object:
qubit_count: 4
bit_count: 4
q[1]:──────────
q[2]:───────Z──
|
q[3]:───────*──
q[4]:──X───────
julia> transpile(transpiler, invalid_circuit)
ERROR: DomainError with LineConnectivity{4}
1──2──3──4
excluded connections: [(2, 3)]
:
the Gate{Snowflurry.ControlZ} on qubits [3, 2] cannot be applied since connection (2, 3) is unavailable
[...]
julia> valid_circuit = QuantumCircuit(
qubit_count = 4,
instructions = [sigma_x(1), control_z(3, 4)],
)
Quantum Circuit Object:
qubit_count: 4
bit_count: 4
q[1]:──X───────
q[2]:──────────
q[3]:───────*──
|
q[4]:───────Z──
julia> transpiled_circuit = transpile(transpiler, valid_circuit)
Quantum Circuit Object:
qubit_count: 4
bit_count: 4
q[1]:──X───────
q[2]:──────────
q[3]:───────*──
|
q[4]:───────Z──
Snowflurry.compare_circuits
— Functioncompare_circuits(c0::QuantumCircuit, c1::QuantumCircuit)::Bool
Tests for the equivalence of two QuantumCircuit
objects based on their effect on an arbitrary input state (a Ket
). The circuits are equivalent if they both yield the same output for any input, up to a global phase. Circuits with gates that are applied in a different order and to different targets can also be equivalent.
If there are Readout
instructions present on either QuantumCircuit
, compare_circuits
checks that both circuits have readouts targeting the same qubits and that no operations exist on those qubits after readout.
Examples
julia> c0 = QuantumCircuit(qubit_count = 1, instructions = [sigma_x(1), sigma_y(1)])
Quantum Circuit Object:
qubit_count: 1
bit_count: 1
q[1]:──X────Y──
julia> c1 = QuantumCircuit(qubit_count = 1, instructions = [phase_shift(1, π)])
Quantum Circuit Object:
qubit_count: 1
bit_count: 1
q[1]:──P(3.1416)──
julia> compare_circuits(c0, c1)
true
julia> c0 = QuantumCircuit(
qubit_count = 3,
instructions = [sigma_x(1), sigma_y(1), control_x(2, 3)]
)
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:──X────Y───────
q[2]:────────────*──
|
q[3]:────────────X──
julia> c1 = QuantumCircuit(
qubit_count = 3,
instructions = [control_x(2, 3), sigma_x(1), sigma_y(1)]
)
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:───────X────Y──
q[2]:──*────────────
|
q[3]:──X────────────
julia> compare_circuits(c0, c1)
true
julia> c2 = QuantumCircuit(qubit_count = 3, instructions = [sigma_x(1), readout(1, 1)])
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:──X────✲──
q[2]:──────────
q[3]:──────────
julia> c3 = QuantumCircuit(qubit_count = 3, instructions = [sigma_x(1)])
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:──X──
q[2]:─────
q[3]:─────
julia> compare_circuits(c2,c3)
false
Snowflurry.circuit_contains_gate_type
— Functioncircuit_contains_gate_type(
circuit::QuantumCircuit,
gate_type::Type{<: AbstractGateSymbol}
)::Bool
Determines if a type of gate is present in a circuit.
Examples
julia> circuit = QuantumCircuit(qubit_count = 1, instructions = [sigma_x(1), sigma_y(1)])
Quantum Circuit Object:
qubit_count: 1
bit_count: 1
q[1]:──X────Y──
julia> circuit_contains_gate_type(circuit, Snowflurry.SigmaX)
true
julia> circuit_contains_gate_type(circuit, Snowflurry.ControlZ)
false
Snowflurry.get_display_symbols
— Functionget_display_symbols(gate::AbstractGateSymbol; precision::Integer = 4,)::Vector{String}
Returns a Vector{String}
of the symbols that describe the gate
.
Each element in the Vector
is associated with a qubit on which the gate
operates. This is useful for the placement of the gate
in a circuit diagram. The optional parameter precision
enables setting the number of digits to keep after the decimal for gate
parameters.
Examples
julia> get_display_symbols(get_gate_symbol(control_z(1, 2)))
2-element Vector{String}:
"*"
"Z"
julia> get_display_symbols(get_gate_symbol(phase_shift(1, π/2)), precision = 3)
1-element Vector{String}:
"P(1.571)"
get_display_symbols(::Readout; precision::Integer = 4,)::Vector{String}
Returns a Vector{String}
of the symbols that describe the Readout
.
Each element in the Vector
is associated with a qubit on which the Readout
operates. This is useful for the placement of the Readout
in a circuit diagram. The optional parameter precision
has no effect for Readout
.
Examples
julia> get_display_symbols(readout(2, 2))
1-element Vector{String}:
"✲"
Snowflurry.get_instruction_symbol
— Functionget_instruction_symbol(instruction::AbstractInstruction)::String
Returns the symbol string that is associated with an instruction
.
Examples
julia> get_instruction_symbol(control_z(1, 2))
"cz"
Snowflurry.get_symbol_for_instruction
— Functionget_symbol_for_instruction(instruction::String)::DataType
Returns a symbol given the corresponding String
.
Examples
julia> get_symbol_for_instruction("cz")
Snowflurry.ControlZ
Snowflurry.permute_qubits!
— Functionpermute_qubits!(
circuit::QuantumCircuit,
qubit_mapping::AbstractDict{T,T}
) where T<:Integer
Modifies a circuit
by moving the gates to other qubits based on a qubit_mapping
.
The dictionary qubit_mapping
contains key-value pairs describing how to update the target qubits. The key indicates which target qubit to change while the associated value specifies the new qubit. All the keys in the dictionary must be present as values and vice versa.
For instance, Dict(1 => 2)
is not a valid qubit_mapping
, but Dict(1 => 2, 2 => 1)
is valid.
Examples
julia> c = QuantumCircuit(qubit_count = 3);
julia> push!(c, sigma_x(1), hadamard(2), sigma_y(3))
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:──X────────────
q[2]:───────H───────
q[3]:────────────Y──
julia> permute_qubits!(c, Dict(1 => 3, 3 => 1))
julia> show(c)
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:────────────Y──
q[2]:───────H───────
q[3]:──X────────────
Snowflurry.permute_qubits
— Functionpermute_qubits(
circuit::QuantumCircuit,
qubit_mapping::AbstractDict{T,T}
)::QuantumCircuit where {T<:Integer}
Returns a QuantumCircuit
that is a copy of circuit
but where the gates have been moved to other qubits based on a qubit_mapping
.
The dictionary qubit_mapping
contains key-value pairs describing how to update the target qubits. The key indicates which target qubit to change while the associated value specifies the new qubit. All the keys in the dictionary must be present as values and vice versa.
For instance, Dict(1=>2)
is not a valid qubit_mapping
, but Dict(1=>2, 2=>1)
is valid.
Examples
julia> c = QuantumCircuit(qubit_count = 3);
julia> push!(c, sigma_x(1), hadamard(2), sigma_y(3))
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:──X────────────
q[2]:───────H───────
q[3]:────────────Y──
julia> permute_qubits(c, Dict(1 => 3, 3 => 1))
Quantum Circuit Object:
qubit_count: 3
bit_count: 3
q[1]:────────────Y──
q[2]:───────H───────
q[3]:──X────────────