Quantum Circuit

Snowflurry.QuantumCircuitType
QuantumCircuit(
    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., specifying qubit_count=n enables the use of qubits 1 to n).
  • bit_count::Int – Optional: Number of classical bits (i.e., result register size). Defaults to qubit_count if unspecified.
  • instructions::Vector{AbstractInstruction} – Optional: Sequence of AbstractInstructions (Gates and Readouts) 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─────────✲──
                              
source
Snowflurry.get_num_qubitsFunction
get_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
source
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
source
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
source
Snowflurry.get_num_bitsFunction
get_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
source
Snowflurry.get_nameFunction
get_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"
source
Snowflurry.get_circuit_instructionsFunction
get_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

source
Base.push!Function
push!(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──
                              


source
Base.pop!Function
pop!(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──
               
source
Base.append!Function
append!(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──
                    

source
Base.prepend!Function
prepend!(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───────
                    

source
Snowflurry.update_circuit_qubit_countFunction
update_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]:─────
          

source
Snowflurry.simulateFunction
simulate(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.

Note

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

source
Snowflurry.simulate_shotsFunction
simulate_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"
source
Snowflurry.get_measurement_probabilitiesMethod
get_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$.

Note

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
source
Base.invMethod
inv(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─────────────────
                         


source
Snowflurry.get_num_gates_per_typeFunction
get_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
source
Snowflurry.get_num_gatesFunction
get_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
source
Snowflurry.serialize_jobFunction
serialize_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.

Note

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}}"
source
Snowflurry.transpileFunction
transpile(transpiler::Transpiler, circuit::QuantumCircuit)::QuantumCircuit

Returns a transpiled copy of the circuit. The transpilation process depends on the transpiler.

The following transpilers are available:

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──
source
Snowflurry.SequentialTranspilerType
SequentialTranspiler(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──
                        


source
Snowflurry.CompressSingleQubitGatesTranspilerType
CompressSingleQubitGatesTranspiler

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
source
Snowflurry.CastSwapToCZGateTranspilerType
CastSwapToCZGateTranspiler

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──
                                              
source
Snowflurry.CastCXToCZGateTranspilerType
CastCXToCZGateTranspiler

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──
source
Snowflurry.CastISwapToCZGateTranspilerType
CastISwapToCZGateTranspiler

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──
source
Snowflurry.CastToffoliToCXGateTranspilerType
CastToffoliToCXGateTranspiler

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──────────────────
                                                                                   
source
Snowflurry.CastRootZZToZ90AndCZGateTranspilerType
CastRootZZToZ90AndCZGateTranspiler

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──
source
Snowflurry.CastToPhaseShiftAndHalfRotationXTranspilerType
CastToPhaseShiftAndHalfRotationXTranspiler,

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
source
Snowflurry.CastUniversalToRzRxRzTranspilerType
CastUniversalToRzRxRzTranspiler

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
source
Snowflurry.CastRxToRzAndHalfRotationXTranspilerType
CastRxToRzAndHalfRotationXTranspiler

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
source
Snowflurry.SimplifyRxGatesTranspilerType
SimplifyRxGatesTranspiler

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
source
Snowflurry.SwapQubitsForAdjacencyTranspilerType
SwapQubitsForAdjacencyTranspiler

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 of Swap 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
source
Snowflurry.SimplifyRzGatesTranspilerType
SimplifyRzGatesTranspiler

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
source
Snowflurry.CompressRzGatesTranspilerType
CompressRzGatesTranspiler

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
source
Snowflurry.RemoveSwapBySwappingGatesTranspilerType
RemoveSwapBySwappingGatesTranspiler

Transipler stage which removes the Swap gates from the circuit assuming all-to-all connectivity.

The initial state must be the ground state!

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──
               


source
Snowflurry.SimplifyTrivialGatesTranspilerType
SimplifyTrivialGatesTranspiler

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
source
Snowflurry.UnsupportedGatesTranspilerType
UnsupportedGatesTranspiler

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}
[...]
source
Snowflurry.ReadoutsAreFinalInstructionsTranspilerType
ReadoutsAreFinalInstructionsTranspiler

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
[...]
source
Snowflurry.CircuitContainsAReadoutTranspilerType
CircuitContainsAReadoutTranspiler

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.
[...]
source
Snowflurry.ReadoutsDoNotConflictTranspilerType
ReadoutsDoNotConflictTranspiler

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
[...]
source
Snowflurry.DecomposeSingleTargetSingleControlGatesTranspilerType
DecomposeSingleTargetSingleControlGatesTranspiler

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).

Note

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
source
Snowflurry.RejectNonNativeInstructionsTranspilerType
RejectNonNativeInstructionsTranspiler

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]:─────
          
source
Snowflurry.RejectGatesOnExcludedPositionsTranspilerType

RejectGatesOnExcludedPositionsTranspiler

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──
               


source
Snowflurry.RejectGatesOnExcludedConnectionsTranspilerType
RejectGatesOnExcludedConnectionsTranspiler

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──
               

source
Snowflurry.compare_circuitsFunction
compare_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.

Note

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    
source
Snowflurry.circuit_contains_gate_typeFunction
circuit_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
source
Snowflurry.get_display_symbolsFunction
get_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)"
source
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}:
 "✲"
source
Snowflurry.get_instruction_symbolFunction
get_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"
source
Snowflurry.get_symbol_for_instructionFunction
get_symbol_for_instruction(instruction::String)::DataType

Returns a symbol given the corresponding String.

Examples

julia> get_symbol_for_instruction("cz")
Snowflurry.ControlZ
source
Snowflurry.permute_qubits!Function
permute_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────────────
                    

source
Snowflurry.permute_qubitsFunction
permute_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────────────
                    


source