Clifford Gates
import sys
sys.path.insert(0, '..')
import numpy as np
import qutip as qt
import src
from src import (utils, paulialg, stabilizer, circuit)
3.1. Clifford Gates#
CliffordGate
class represents the Clifford gates.
Attribute:
qubits: a tuple containing the number of qubits that it acts on
n: number of qubits it acts on
generator(Pauli): the generator for \(C_{\pi/4}\) rotation.
Default: None
forward_map(CliffordMap): forward Clifford Map.
Default: None
backward_map(CliffordMap): backward Clifford Map.
Default: None
Methods:
CliffordGate.set_generator(Pauli)
CliffordGate.set_forward_map(CliffordMap)
CliffordGate.set_backward_map(CliffordMap)
TODO: we need to add a handle to prevent user set conflict Clifford mapsCliffordGate.copy()
: return a copy of the Clifford gateCliffordGate.independent_from(Other_gate)
: if there is no overlap between acting qubits, then they are independent.CliffordGate.compile()
: build (forward&backward) Clifford map representation. If generator is given, then it will be converted to forward/backward map; if forward map is given, the backward map will be calculated; if backward map is given, the forward map will be calculatedCliffordGate.forward(obj)
: forward transformation of the object.obj
can be Pauli, PauliList, PauliPolynomial, StabilizerState.
CliffordGate is the low-level API(class) for Clifford gates. One can create a null Clifford gate by sepecifying what are the qubits this gate will act on:
Example: circuit.CliffordGate(1,2)
will create a null gate acting on qubit 1, and 2. Null gate does not contain any forward_map
or backward_map
gate = circuit.CliffordGate(1,2)
print("gate acts on: {}, and there are {} qubits the gates will act on.".format(
gate.qubits, gate.n
))
gate acts on: (1, 2), and there are 2 qubits the gates will act on.
There are three ways to equip the null gate with Clifford map:
One can use
gate.set_generator(Pauli)
. This will create a \(\pi/2\) rotation generated by the pauli string.One can use
gate.set_forward_map(CliffordMap)
One can use
gate.set_backward_map(CliffordMap)
gate.set_generator(paulialg.pauli("XX"))
gate.set_forward_map(stabilizer.random_clifford_map(2))
gate.set_backward_map(stabilizer.random_clifford_map(2))
gate.compile()
will construct both forward_clifford_map
and backward_clifford_map
. Compilation is not necessary!
gate.copy()
will return a copy of the CliffordGate
One can apply Clifford Gate \(U\) or \(U^{\dagger}\) to: Pauli strings, Stabilizer States by gate.forward(obj)
and gate.backward(obj)
psi = stabilizer.random_clifford_state(5)
gate = circuit.CliffordGate(1,2)
gate.set_generator(paulialg.pauli("XX"))
gate.forward(psi)
StabilizerState(
+YIZZY
+XYYXX
+YZXYI
+XZZYY
-IYIZY)
We see the wavefunction \(|\psi\rangle\) has been changed in-place. And the gate only changes qubit 1&2.
If two Clifford gate acting on different qubits, then they are independent. We can check dependency by gate.independent_from(other_gate)
gate1 = circuit.CliffordGate(0,1)
gate2 = circuit.CliffordGate(2,3)
print(gate1.independent_from(gate2))
True
gate1 = circuit.CliffordGate(0,1)
gate2 = circuit.CliffordGate(1,2)
print(gate1.independent_from(gate2))
False