def test_conditions() -> None: box_c = Circuit(2, 2) box_c.Z(0) box_c.Y(1, condition_bits=[0, 1], condition_value=1) box_c.Measure(0, 0, condition_bits=[0, 1], condition_value=0) box = CircBox(box_c) u = np.asarray([[0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1], [1, 0, 0, 0]]) ubox = Unitary2qBox(u) c = Circuit(2, 2, name="c") b = c.add_c_register("b", 1) c.add_circbox( box, [Qubit(0), Qubit(1), Bit(0), Bit(1)], condition_bits=[b[0]], condition_value=1, ) c.add_unitary2qbox(ubox, Qubit(0), Qubit(1), condition_bits=[b[0]], condition_value=0) c2 = c.copy() qc = tk_to_qiskit(c) c1 = qiskit_to_tk(qc) assert len(c1.get_commands()) == 2 DecomposeBoxes().apply(c) DecomposeBoxes().apply(c1) assert c == c1 c2.Z(1, condition=reg_eq(b, 1)) qc = tk_to_qiskit(c2) c1 = qiskit_to_tk(qc) assert len(c1.get_commands()) == 3
def test_boxes() -> None: c = Circuit(2) c.S(0) c.H(1) c.CX(0, 1) cbox = CircBox(c) d = Circuit(3, name="d") d.add_circbox(cbox, [0, 1]) d.add_circbox(cbox, [1, 2]) u = np.asarray([[0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1], [1, 0, 0, 0]]) ubox = Unitary2qBox(u) d.add_unitary2qbox(ubox, 0, 1) qsc = tk_to_qiskit(d) d1 = qiskit_to_tk(qsc) assert len(d1.get_commands()) == 3 DecomposeBoxes().apply(d) DecomposeBoxes().apply(d1) assert d == d1
# An example will illustrate how these various box types are added to a circuit: from pytket.circuit import CircBox, Unitary1qBox, Unitary2qBox, ExpBox, PauliExpBox from pytket.pauli import Pauli import numpy as np from math import sqrt boxycirc = Circuit(3) # Add a `CircBox`: subcirc = Circuit(2) subcirc.X(0).Y(1).CZ(0, 1) cbox = CircBox(subcirc) boxycirc.add_circbox(cbox, args=[Qubit(0), Qubit(1)]) # Add a `Unitary1qBox`: m1 = np.asarray([[1 / 2, sqrt(3) / 2], [sqrt(3) / 2, -1 / 2]]) m1box = Unitary1qBox(m1) boxycirc.add_unitary1qbox(m1box, 2) # Add a `Unitary2qBox`: m2 = np.asarray([[0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1], [1, 0, 0, 0]]) m2box = Unitary2qBox(m2) boxycirc.add_unitary2qbox(m2box, 1, 2) # Add an `ExpBox`:
class CircuitBuilder: def __init__( self, qregs: List[QuantumRegister], cregs: Optional[List[ClassicalRegister]] = None, name: Optional[str] = None, phase: Optional[float] = 0.0, ): self.qregs = qregs self.cregs = [] if cregs is None else cregs self.tkc = Circuit(name=name) self.tkc.add_phase(phase) self.qregmap = {} for reg in qregs: tk_reg = self.tkc.add_q_register(reg.name, len(reg)) self.qregmap.update({reg: tk_reg}) self.cregmap = {} for reg in self.cregs: tk_reg = self.tkc.add_c_register(reg.name, len(reg)) self.cregmap.update({reg: tk_reg}) def circuit(self) -> Circuit: return self.tkc def add_qiskit_data(self, data: "QuantumCircuitData") -> None: for i, qargs, cargs in data: condition_kwargs = {} if i.condition is not None: cond_reg = self.cregmap[i.condition[0]] condition_kwargs = { "condition_bits": [cond_reg[k] for k in range(len(cond_reg))], "condition_value": i.condition[1], } if type(i) == ControlledGate: if type(i.base_gate) == qiskit_gates.RYGate: optype = OpType.CnRy else: # Maybe handle multicontrolled gates in a more general way, # but for now just do CnRy raise NotImplementedError( "qiskit ControlledGate with " + "base gate {} not implemented".format(i.base_gate)) else: optype = _known_qiskit_gate[type(i)] qubits = [ self.qregmap[qbit.register][qbit.index] for qbit in qargs ] bits = [self.cregmap[bit.register][bit.index] for bit in cargs] if optype == OpType.Unitary2qBox: u = i.to_matrix() ubox = Unitary2qBox(u) self.tkc.add_unitary2qbox(ubox, qubits[0], qubits[1], **condition_kwargs) elif optype == OpType.Barrier: self.tkc.add_barrier(qubits) elif optype in (OpType.CircBox, OpType.Custom): qregs = [QuantumRegister(i.num_qubits, "q") ] if i.num_qubits > 0 else [] cregs = ([ClassicalRegister(i.num_clbits, "c")] if i.num_clbits > 0 else []) builder = CircuitBuilder(qregs, cregs) builder.add_qiskit_data(i.definition) subc = builder.circuit() if optype == OpType.CircBox: cbox = CircBox(subc) self.tkc.add_circbox(cbox, qubits + bits, **condition_kwargs) else: # warning, this will catch all `Gate` instances # that were not picked up as a subclass in _known_qiskit_gate params = [param_to_tk(p) for p in i.params] gate_def = CustomGateDef.define(i.name, subc, list(subc.free_symbols())) self.tkc.add_custom_gate(gate_def, params, qubits + bits) else: params = [param_to_tk(p) for p in i.params] self.tkc.add_gate(optype, params, qubits + bits, **condition_kwargs)