Beginner¶
1. Getting Started¶
In this tutorial we will explore the basic workflow of using zyglrox
.
We start by defining a quantum circuit. First, we import the necessary modules:
the QuantumCircuit
class, two gates and the Observable
class.
from zyglrox.core.circuit import QuantumCircuit
from zyglrox.core.gates import Hadamard, PauliZ
from zyglrox.core.observables import Observable
Next, we will will construct a quantum circuit on a single qubit, where we first apply a Hadmard gate, and afterwards a Pauli Z gate.
Specifiying the circuit is done by make a list of Gate
objects, where for each gate we specify on which ‘quantum wire’ they operate.
gates = [Hadamard(wires=[0,]), PauliZ(wires=[0,])]
qc = QuantumCircuit(nqubits=1, gates=gates, device="CPU")
Before we can calculate anything, we need to initialize the model in true TensorFlow fashion. If you have a CUDA enabled GPU available, you can choose to run the calculation on the GPU. For now, we will select the CPU to do the heavy lifting.
qc.initialize()
Note
zyglrox
relies on tensorflow 1.15.0
. This Python framework uses an imperative programming paradigm to
construct a computational graph, which is then executed in a so called ‘session’.

Understanding and managing these graphs and sessions requires some understanding of TensorFlow. However, when using zyglrox
you only have to worry
about calling qc.initalize
after all the circuit definitions are done.
Now we are ready to do some calculations. QuantumCircuit
has a method circuit
, that can be called on a complex vector to output
the wavefunction after applying the gates. Additionally, QuantumCircuit
contains a constant vector qc.phi
corresponding to the \(|0\rangle^{\otimes N}\),
that can be propagated through the circuit. We can call the initialized session to extract the values of interest from the graph.
phi = qc.circuit(qc.phi)
# graph definitions are done
qc_tf = qc._sess.run(phi)
print(qc_tf)
>>> [ 0.70710677+0.j -0.70710677+0.j]
Which outputs the correct state:
On a real quantum computer, we do not have access to the full wave function. Instead, we have to rely on the measurement of observables to obtain information about the state of the system. To simulate this, we add an observable layer to our quantum circuit. For instance, lets say we want to measure in the X-basis on the first qubit.
obs = [Observable("x", wires=[0, ])]
expval_layer = ExpectationValue(obs)
This adds the ExpectationValue
layer to the graph, a layer containing all the observables of interest measured on our quantum circuit.
To retrieve the observable \(\langle \sigma^x \rangle\) from the graph, we run the ExpectationValue
layer and extract the observables.
measurements = qc._sess.run(expval_layer(phi))
print(measurements)
>>> [[[[-0.99999994]]]]
Which is again the value we expect.
2. Multi-Qubit gates and Visualization¶
For this tutorial we will explore the usage of multi-qubit gates and parametrizable gates. First we import the QuantumCircuit
, some gates
and the Observable
class.
from zyglrox.core.circuit import QuantumCircuit
from zyglrox.core.gates import Hadamard, Phase, CNOT
from zyglrox.core.observables import Observable
import numpy as np
Next, we will define the gates of our circuit for 2 qubits. The Phase
gate rotates the qubit state around the z-axis of the Bloch sphere
where \(\theta\) is the so-called phase shift. When we move on to variational circuits, this variable will be adjustable. For now, we set this parameter to \(\pi/8\).
In order to make use of entanglement, we need integrate CNOT gates, since these gates turn a product state
into a linear combination of pure states
by conditionally flipping the target qubit (in this case the second qubit) if the first qubit is in the \(|1\rangle\) state. We will apply a single CNOT at the end of our circuit.
In zyglrox
, we define this circuit as follows
gates = [Hadamard(wires=[0, ]), Phase(wires=[0, ], value=[np.pi / 8]),
Hadamard(wires=[1, ]), Phase(wires=[1, ], value=[np.pi / 8]), CNOT(wires=[0, 1])]
To enable visualization in TensorBoard, we pass the tensorboard=True
argument to the QuantumCircuit
constructor.
qc = QuantumCircuit(nqubits=2, gates=gates,tensorboard=True)
Since the qc.circuit
method is a sequential Keras model, we can call the summary()
function on this object to print
the parameters and layers of this circuit.
phi = qc.circuit(qc.phi)
qc.circuit.summary()
>>> Model: "circuit"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
H_0 (Hadamard) multiple 0
_________________________________________________________________
Phase_0 (Phase) multiple 1
_________________________________________________________________
CNOT_0_1 (CNOT) multiple 0
_________________________________________________________________
H_1 (Hadamard) multiple 0
_________________________________________________________________
Phase_1 (Phase) multiple 1
_________________________________________________________________
CNOT_1_0 (CNOT) multiple 0
=================================================================
Total params: 2
Trainable params: 2
Non-trainable params: 0
Note
Printing out the commonly used quantum circuit representation of wires and blocks of gates will be added in a future release.
In zyglrox
, we are not limited by the physical constraints of a quantum computer. We can extract multiple
observables in parallel, even from the same qubit.
obs = [Observable("x", wires=[0, ]), Observable("x", wires=[1, ]),
Observable("y", wires=[0, ]), Observable("y", wires=[1, ]),
Observable("z", wires=[0, ]), Observable("z", wires=[1, ])]
expval_layer = ExpectationValue(obs)
Now that we’re done, we initialize the session and extract the measurements.
qc.initialize()
measurements = qc._sess.run(expval_layer(phi))
print(measurements)
>>> [[[[ 8.5355318e-01]]
[[ 9.2387938e-01]]
[[ 3.5355335e-01]]
[[-7.4505806e-09]]
[[ 2.9802322e-08]]
[[ 1.4901161e-08]]]]
Additionally, we can visualize the computational graph in TensorBoard. When enabled, the logs are automatically stored in the ./logdir folder.
>>> tensorboard --logdir=logdir
which looks like this. .