2.5. Sequences and Controls#
The concatenation of several gates is the most important contruction for quantum circuits. Besides this, using classical bits as well as qubits to control the execution of gates is also an important building block of quantum circuits. The following constructions are supported by geqo for building up quantum circuits:
Sequence
QuantumControl
ClassicalControl
2.5.1. Sequence#
With the Sequence
constructions, several quantum operations can be assembled together to a single operation.
The first two arguments of Sequence
are lists of classical and quantum bits in the circuit and the third argument is the list of operations in the circuits. Each entry in the latter list consists of the gate and its targets. In this example, the gates have no parameters like rotation angles. For operations with classical and quantum targets, two lists of targets have to be provided. The first list consists of the quantum targets and the second list consists of the classical bits.
Classical bits and qubits can be referred to by their name or their position in the provided list of classical bits and qubits, respectively.
from geqo.gates import Hadamard
from geqo.core.quantum_circuit import Sequence
from geqo.operations import Measure
from geqo.simulators.sympy import ensembleSimulatorSymPy
seq = Sequence(
["c0"],
["q0", "q1"],
[(Hadamard(), ["q0"]), (Hadamard(), ["q1"]), (Measure(1), ["q0"], ["c0"])],
)
sim = ensembleSimulatorSymPy(1, 2)
sim.apply(seq, [0, 1], [0])
sim.ensemble
{(0,): (1/2,
Matrix([
[1/2, 1/2, 0, 0],
[1/2, 1/2, 0, 0],
[ 0, 0, 0, 0],
[ 0, 0, 0, 0]])),
(1,): (1/2,
Matrix([
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 1/2, 1/2],
[0, 0, 1/2, 1/2]]))}
2.5.2. QuantumControl#
With this construction, a gate can be turned into a gate with control qubits, i.e., the gate is only applied to one or several qubits, if the control qubits have a specified state in the computational basis. The first argument of QuantumControl
is a list of 0 and 1 values, which indicate whether a control qubit should lead to the execution of the gate in the basis state \(|0\rangle\) or \(|1\rangle\). The second argument is the gate, which should be turned into the controlled version.
from geqo.gates import Hadamard, PauliX
from geqo.operations.controls import QuantumControl
from geqo.simulators.sympy import ensembleSimulatorSymPy
gate = QuantumControl([0], Hadamard())
sim = ensembleSimulatorSymPy(0, 2)
sim.apply(gate, [0, 1]) # The gate is executed because the control qubit is in state 0.
print(sim.ensemble) # Show the resulting ensemble.
sim.apply(PauliX(), [0]) # Set the state of the control qubit to 1.
sim.apply(
gate, [0, 1]
) # The gate is not executed because the control qubit is in state 1.
print(sim.ensemble) # Show the resulting ensemble.
{(): (1, Matrix([
[1/2, 1/2, 0, 0],
[1/2, 1/2, 0, 0],
[ 0, 0, 0, 0],
[ 0, 0, 0, 0]]))}
{(): (1, Matrix([
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 1/2, 1/2],
[0, 0, 1/2, 1/2]]))}
2.5.3. ClassicalControl#
With this construction, a gate can be turned into a gate with classical control bits, i.e., the gate is only applied to one or several qubits, if the control bits are set to specific values. The first argument of ClassicalControl
is a list of 0 and 1 values, which indicate whether a classical control bit should lead to the execution of the gate if it is set to \(0\) or \(1\). The second argument is the gate, which should be turned into the controlled version.
from geqo.gates import Hadamard
from geqo.operations.controls import ClassicalControl
from geqo.simulators.sympy import ensembleSimulatorSymPy
from geqo.initialization import SetBits
gate = ClassicalControl([0], Hadamard())
bits = SetBits("a", 1)
sim = ensembleSimulatorSymPy(1, 1)
sim.setValue("a", [1])
sim.apply(
gate, [0, 0]
) # Apply the gate. SetBits was not used, so the classical bit is 0.
print(sim.ensemble) # Show the resulting ensemble.
sim.apply(bits, [0]) # Set the bit to value 1.
print(sim.ensemble) # Show the resulting ensemble.
# This operation should be turned off now.
sim.apply(
gate, [0, 0]
) # This operation is not executed, because the classical control is now value 1.
print(sim.ensemble) # Show the resulting ensemble.
{(0,): (1, Matrix([
[1/2, 1/2],
[1/2, 1/2]]))}
{(1,): (1, Matrix([
[1/2, 1/2],
[1/2, 1/2]]))}
{(1,): (1, Matrix([
[1/2, 1/2],
[1/2, 1/2]]))}