3.4. CliffordSim Simple Examples
In this notebook we shall simulate some simple Clifford circuits using CliffordSim. We will also demonstrate the propagation of Pauli frames using the simulator.
3.4.1. Bell Pair Circuit
from loom.cliffordsim import Engine
from loom.cliffordsim.operations import (
Hadamard,
CNOT,
Measurement,
Reset,
Z,
Phase,
PhaseInv,
)
import pprint
# Bell Pair
operation_list_bell_pair = [Hadamard(0), CNOT(0, 1), Measurement(0), Measurement(1)]
nqubits = 2
seed = None # Optional seed for reproducibility
cliffordsim_engine = Engine(operation_list_bell_pair, nqubits, seed)
# Runs the Simulator
cliffordsim_engine.run()
In this example, we measure qubits 0 and 1 after applying the Hadamard and CNOT gates.
CliffordSim performs the measurement and stores the result in its DataStore object, accessible through the data_store attribute.
pprint.pprint(cliffordsim_engine.data_store.measurements)
{'2': {'b6d256d7-fef1-4af4-9bcf-9d5beac17c05': {'flip_results': {},
'is_random': np.True_,
'measurement_result': 1}},
'3': {'0d64a510-12c7-452b-a7c3-581a93e7a859': {'flip_results': {},
'is_random': np.False_,
'measurement_result': np.int8(1)}},
'time_step': [2, 3]}
The structure of the DataStore.measurements can be understood as follows:
time_stepare the parallelized time steps in which the measurement operations were performed.String-fied versions of the values in the
time_steplist as keys. The values for these keys will contain the measurement data from that particular time step.Measurement data, from one
MeasurementOperation is stored in the following format:
'uuid of measurement operation': {'is_random': boolean, 'measurement_result': int}
print(cliffordsim_engine.stabilizer_set)
{'-Z_', '+ZZ'}
3.4.2. Five-Qubit Code Initialization
Encoding circuit taken from here
operation_list_five_qubit = [
# Layer 0
Z(0),
Hadamard(2),
Hadamard(3),
# Layer 1
PhaseInv(0),
CNOT(2, 4),
# Layer 2
CNOT(3, 1),
# Layer 3
Hadamard(1),
CNOT(3, 4),
# Layer 4
CNOT(1, 0),
PhaseInv(2),
Phase(3),
PhaseInv(4),
# Layer 5
Phase(0),
Phase(1),
Z(2),
# Layer 6
CNOT(4, 0),
# Layer 7
Hadamard(4),
# Layer 8
CNOT(4, 1),
]
nqubits = 5
seed = None
cliffordsim_engine = Engine(operation_list_five_qubit, nqubits, seed)
# Runs the Simulator
cliffordsim_engine.run()
pprint.pprint(cliffordsim_engine.data_store.measurements)
{'time_step': []}
Since there are no measurement operations in this circuit, the measurements attribute of the DataStore Object is empty.
print(cliffordsim_engine.stabilizer_set)
{'+YZ_ZY', '+XXY_Y', '+_XZZX', '-ZY__Y', '+XY_YX'}
Note
The above may not look exactly how we would expect the state to look like for the five-qubit code. Multiplying in pairs appropriately the above Paulis, we can get the standard set:
+XZZX_+_XZZX+X_XZZ+ZX_XZ+ZZZZZ(Z Logical operator)
3.4.3. PauliFrame basic example
Below follows a demonstration on how to create and propagate Pauli frames using a simple circuit that is based on the Repetition code syndrome extraction circuit.
from loom.cliffordsim.pauli_frame import PauliFrame
from loom.cliffordsim.operations import CreatePauliFrame, RecordPauliFrame
pframe_0 = PauliFrame.from_string("XIIII")
pframe_1 = PauliFrame.from_string("IXIII")
rep_code_pframe_operation_list = [
CreatePauliFrame(pframe_0),
CNOT(0, 3),
CNOT(1, 3),
CNOT(1, 4),
CNOT(2, 4),
Measurement(3),
Measurement(4),
Reset(3),
Reset(4),
RecordPauliFrame(pframe_0),
CreatePauliFrame(pframe_1),
CNOT(0, 3),
CNOT(1, 3),
CNOT(1, 4),
CNOT(2, 4),
Measurement(3),
Measurement(4),
RecordPauliFrame(pframe_1),
]
# Define the Engine
p_frame_engine = Engine(rep_code_pframe_operation_list, 5)
# Run the simulator
p_frame_engine.run()
# Show propagated pauli frames
p_frame_engine.data_store.get_pframes()
({'initial_pauli_frame': PauliFrame: X____,
'recorded_pauli_frame': PauliFrame: X__X_},
{'initial_pauli_frame': PauliFrame: _X___,
'recorded_pauli_frame': PauliFrame: _X_XX})