Circuits

Quantum circuit can be constructed easily when we have a circuit object to which we can apply gates by simply calling method like circuit.H(i=0). This functionality is provided in the Circuit classes, and packed together with the knowledge on how to sample the noisy gates as stochastic matrices from a specific gate set.

Classes

We provide different versions, some of which can be used with a specific backend to speed up the computations.

Circuit

The Circuit class uses trivial matrix multiplications to perform the statevector simulation. Thus, it only scales to 13 qubits, and we only use it for unit testing.

from quantum_gates.circuits import Circuit
from quantum_gates.gates import standard_gates

# The depth has to be set correctly for this class.
circuit = Circuit(nqubit=2, depth=1, gates=standard_gates)

# We apply gates for one timestep.
circuit.X(i=0, ...)
circuit.I(i=1)

# Evaluate the statevector
psi1 = circuit.statevector(psi0=np.array([1, 0, 0, 0]))  # Gives [0, 0, 1, 0]

AlternativeCircuit

We can us the AlternativeCircuit class to build a circuit with a custom backend for performing the computations.

from quantum_gates.circuits import AlternativeCircuit
from quantum_gates.backends import EfficientBackend
from quantum_gates.gates import standard_gates

circuit = AlternativeCircuit(
    nqubit=2,
    gates=standard_gates,
    BackendClass= EfficientBackend
)

This class does not have a depth attribute, it is flexible.

StandardCircuit

Combining the AlternativeCircuit with the trivial StandardBackend, we get the StandardCircuit. Again, we only recommend to use it for unit testing.

EfficientCircuit

This is the class we recommend to use for simulations, as it uses the optimized EfficientBackend for the computations.

Usage

The class is easy to use besides one tricky detail. For each gatetime (timestep), one has to fill in all gates. For example, consider the two qubit case. We apply an X gate on qubit 0 and then a CNOT gate on both qubits with control on 0 and target on 1. Then we use the following code:

from quantum_gates.circuits import EfficientCircuit
from quantum_gates.gates import standard_gates

# The depth can be set arbitrarily for this circuit class.
circuit = EfficientCircuit(nqubit=2, depth=0, gates=standard_gates)

# First timestep -> Each qubit has to get a gate, this is why we apply even identities.
circuit.H(i=0, ...)
circuit.I(i=1)

# Second timestep -> All qubits received a gate, because CNOT is a two-qubit gate.
circuit.CNOT(i=0, k=1, ...)

# Evaluate the statevector
psi1 = circuit.statevector(psi0=np.array([1, 0, 0, 0]))

Not applying gates to each qubit will lead to errors.

Possible extensions

In the future, we could add checks that warns the user in case not all gates are applied.