def _add_single_qubit_op_to_circuit(cmd: ProjectQCommand, circ: Circuit) -> bool: assert len(cmd.qubits) == 1 assert len(cmd.qubits[0]) == 1 qubit_no = cmd.qubits[0][0].id new_qubit = False if get_control_count(cmd) > 0: raise Exception("singleq gate " + str(cmd.gate) + " has " + str(get_control_count(cmd)) + " control qubits") else: if qubit_no >= circ.n_qubits: circ.add_blank_wires(1 + qubit_no - circ.n_qubits) new_qubit = True if type(cmd.gate) == pqo.MeasureGate: bit = Bit("c", qubit_no) if bit not in circ.bits: circ.add_bit(bit) circ.Measure(qubit_no, qubit_no) return new_qubit elif type(cmd.gate) in (pqo.Rx, pqo.Ry, pqo.Rz): op = Op.create(_pq_to_tk_singleqs[type(cmd.gate)], cmd.gate.angle / np.pi) else: op = Op.create(_pq_to_tk_singleqs[type(cmd.gate)]) circ.add_gate(Op=op, args=[qubit_no]) return new_qubit
def pyzx_to_tk(pyzx_circ: pyzxCircuit) -> Circuit: """ Convert a :py:class:`pyzx.Circuit` to a tket :py:class:`Circuit` . All PyZX basic gate operations are currently supported by pytket. Run `pyzx_circuit_name.to_basic_gates()` before conversion. :param pyzx_circ: A circuit to be converted :return: The converted circuit """ c = Circuit(pyzx_circ.qubits, name=pyzx_circ.name) for g in pyzx_circ.gates: if not type(g) in _pyzx_to_tk_gates: raise Exception("Cannot parse PyZX gate of type " + g.name + "into tket Circuit") op_type = _pyzx_to_tk_gates[type(g)] if hasattr(g, "control"): qbs = [getattr(g, "control"), getattr(g, "target")] else: qbs = [getattr(g, "target")] if op_type == OpType.Sdg and not getattr(g, "adjoint"): op_type = OpType.S elif op_type == OpType.Tdg and not getattr(g, "adjoint"): op_type = OpType.T if hasattr(g, "printphase") and op_type in _parameterised_gates: op = Op.create(op_type, g.phase) else: op = Op.create(op_type) c.add_gate(Op=op, args=qbs) return c
def test_incrementer() -> None: """ Simulate an 8-bit incrementer """ b = QsharpToffoliSimulatorBackend() c = Circuit(8) c.add_gate(OpType.CnX, [0, 1, 2, 3, 4, 5, 6, 7]) c.add_gate(OpType.CnX, [0, 1, 2, 3, 4, 5, 6]) c.add_gate(OpType.CnX, [0, 1, 2, 3, 4, 5]) c.add_gate(OpType.CnX, [0, 1, 2, 3, 4]) c.add_gate(OpType.CnX, [0, 1, 2, 3]) c.CCX(0, 1, 2) c.CX(0, 1) c.X(0) for x in [0, 23, 79, 198, 255]: # some arbitrary 8-bit numbers circ = Circuit(8) # prepare the state corresponding to x for i in range(8): if (x >> i) % 2 == 1: circ.X(i) # append the incrementer circ.add_circuit(c, list(range(8))) circ.measure_all() # run the simulator b.compile_circuit(circ) bits = b.get_shots(circ, 1)[0] # check the result for i in range(8): assert bits[i] == ((x + 1) >> i) % 2
def circuits( draw: Callable[[SearchStrategy[Any]], Any], n_qubits: SearchStrategy[int] = st.integers(min_value=2, max_value=6), depth: SearchStrategy[int] = st.integers(min_value=1, max_value=100), ) -> Circuit: total_qubits = draw(n_qubits) circuit = Circuit(total_qubits, total_qubits) for _ in range(draw(depth)): gate = draw(st.sampled_from(list(_GATE_SET))) control = draw(st.integers(min_value=0, max_value=total_qubits - 1)) if gate == OpType.ZZMax: target = draw( st.integers(min_value=0, max_value=total_qubits - 1).filter( lambda x: x != control ) ) circuit.add_gate(gate, [control, target]) elif gate == OpType.Measure: circuit.add_gate(gate, [control, control]) circuit.add_gate(OpType.Reset, [control]) elif gate == OpType.Rz: param = draw(st.floats(min_value=0, max_value=2)) circuit.add_gate(gate, [param], [control]) elif gate == OpType.PhasedX: param1 = draw(st.floats(min_value=0, max_value=2)) param2 = draw(st.floats(min_value=0, max_value=2)) circuit.add_gate(gate, [param1, param2], [control]) circuit.measure_all() return circuit
def test_handles() -> None: b = QsharpSimulatorBackend() c = Circuit(4) c.X(0).X(1).X(2) c.add_gate(OpType.CnX, [0, 1, 2, 3]) c.measure_all() b.compile_circuit(c) n_shots = 3 shots = b.get_shots(c, n_shots=n_shots) assert all(shots[i, 3] == 1 for i in range(n_shots))
def test_handles() -> None: b = QsharpToffoliSimulatorBackend() c = Circuit(4) c.CX(0, 1) c.CCX(0, 1, 2) c.add_gate(OpType.CnX, [0, 1, 2, 3]) c.add_gate(OpType.noop, [2]) c.X(3) c.SWAP(1, 2) c.measure_all() b.compile_circuit(c) shots = b.get_shots(c, n_shots=2) assert all(shots[0] == shots[1])
def _aqt_rebase() -> BasePass: # CX replacement c_cx = Circuit(2) c_cx.Ry(0.5, 0) c_cx.add_gate(OpType.XXPhase, 0.5, [0, 1]) c_cx.Ry(1.0, 0).Rx(-0.5, 0).Ry(0.5, 0) c_cx.Rx(-0.5, 1) # TK1 replacement c_tk1 = lambda a, b, c: Circuit(1).Rx(-0.5, 0).Ry(a, 0).Rx(b, 0).Ry( c, 0).Rx(0.5, 0) return RebaseCustom({OpType.XXPhase}, c_cx, {OpType.Rx, OpType.Ry}, c_tk1)
def test_rebase_singleq() -> None: circ = Circuit(1) # some arbitrary unitary circ.add_gate(OpType.U3, [0.01231, 0.848, 38.200], [0]) orig_circ = circ.copy() _aqt_rebase().apply(circ) # TODO use tketsim for this test once available u1 = AerUnitaryBackend().get_unitary(orig_circ) u2 = AerUnitaryBackend().get_unitary(circ) assert np.allclose(u1, u2)
def test_default_pass() -> None: b = QsharpToffoliSimulatorBackend() for ol in range(3): comp_pass = b.default_compilation_pass(ol) c = Circuit(4, 4) c.CX(0, 1) c.CCX(0, 1, 2) c.add_gate(OpType.CnX, [0, 1, 2, 3]) c.add_gate(OpType.noop, [2]) c.X(3) c.SWAP(1, 2) c.measure_all() comp_pass.apply(c) for pred in b.required_predicates: assert pred.verify(c)
def test_convert() -> None: circ = Circuit(4, 4) circ.H(0).CX(0, 1) circ.add_gate(OpType.noop, [1]) circ.CRz(0.5, 1, 2) circ.add_barrier([2]) circ.ZZPhase(0.3, 2, 3).CX(3, 0).Tdg(1) circ.Measure(0, 0) circ.Measure(1, 2) circ.Measure(2, 3) circ.Measure(3, 1) circ_aqt = tk_to_aqt(circ) assert json.loads(circ_aqt[1]) == [0, 3, 1, 2] assert all(gate[0] in ["X", "Y", "MS"] for gate in circ_aqt[0])
def pyquil_to_tk(prog: Program) -> Circuit: """ Convert a :py:class:`pyquil.Program` to a tket :py:class:`Circuit` . Note that not all pyQuil operations are currently supported by pytket. :param prog: A circuit to be converted :return: The converted circuit """ tkc = Circuit() qmap = {} for q in prog.get_qubits(): uid = Qubit("q", q) tkc.add_qubit(uid) qmap.update({q: uid}) cregmap: Dict = {} for i in prog.instructions: if isinstance(i, Gate): try: optype = _known_quil_gate[i.name] except KeyError as error: raise NotImplementedError("Operation not supported by tket: " + str(i)) from error qubits = [qmap[q.index] for q in i.qubits] params = [param_from_pyquil(p) for p in i.params] # type: ignore tkc.add_gate(optype, params, qubits) elif isinstance(i, Measurement): qubit = qmap[i.qubit.index] reg = cregmap[i.classical_reg.name] # type: ignore bit = reg[i.classical_reg.offset] # type: ignore tkc.Measure(qubit, bit) elif isinstance(i, Declare): if i.memory_type == "BIT": new_reg = tkc.add_c_register(i.name, i.memory_size) cregmap.update({i.name: new_reg}) elif i.memory_type == "REAL": continue else: raise NotImplementedError("Cannot handle memory of type " + i.memory_type) elif isinstance(i, Pragma): continue elif isinstance(i, Halt): return tkc else: raise NotImplementedError("PyQuil instruction is not a gate: " + str(i)) return tkc
def test_compile() -> None: """ Compile a circuit containing SWAPs and noops down to CnX's """ b = QsharpToffoliSimulatorBackend() c = Circuit(4) c.CX(0, 1) c.CCX(0, 1, 2) c.add_gate(OpType.CnX, [0, 1, 2, 3]) c.add_gate(OpType.noop, [2]) c.X(3) c.SWAP(1, 2) c.measure_all() b.compile_circuit(c) shots = b.get_shots(c, 2) assert all(shots[0] == shots[1])
def test_convert() -> None: circ = Circuit(4) circ.H(0).CX(0, 1) circ.add_gate(OpType.noop, [1]) circ.CRz(0.5, 1, 2) circ.add_barrier([2]) circ.ZZPhase(0.3, 2, 3).CX(3, 0).Tdg(1) circ.measure_all() RebaseHQS().apply(circ) circ_hqs = circuit_to_qasm_str(circ, header="hqslib1") qasm_str = circ_hqs.split("\n")[6:-1] test = True for com in qasm_str: test &= any( com.startswith(gate) for gate in ("rz", "U1q", "ZZ", "measure", "barrier")) assert test
def _add_daggered_op_to_circuit(cmd: ProjectQCommand, circ: Circuit) -> bool: undaggered_gate = cmd.gate.get_inverse() if type(undaggered_gate) == pqo.TGate: op = Op.create(OpType.Tdg) elif type(undaggered_gate) == pqo.SGate: op = Op.create(OpType.Sdg) else: raise Exception("cannot recognise daggered op of type " + str(cmd.gate)) qubit_no = cmd.qubits[0][0].id assert len(cmd.qubits) == 1 assert len(cmd.qubits[0]) == 1 new_qubit = False if qubit_no >= circ.n_qubits: circ.add_blank_wires(1 + qubit_no - circ.n_qubits) new_qubit = True circ.add_gate(Op=op, args=[qubit_no]) return new_qubit
def test_convert() -> None: circ = Circuit(3, 3) circ.H(0).CX(0, 1) circ.add_gate(OpType.XXPhase, 0.12, [1, 2]) circ.add_gate(OpType.noop, [1]) circ.add_barrier([2]) circ.Measure(0, 1) circ.Measure(1, 0) circ.Measure(2, 2) (circ_ionq, measures) = tk_to_ionq(circ) assert measures[0] == 1 assert measures[1] == 0 assert measures[2] == 2 assert circ_ionq["qubits"] == 3 assert circ_ionq["circuit"][0]["gate"] == "h" assert circ_ionq["circuit"][1]["gate"] == "cnot" assert circ_ionq["circuit"][2]["gate"] == "xx"
def test_aer_default_pass() -> None: with open(os.path.join(sys.path[0], "ibmqx2_properties.pickle"), "rb") as f: properties = pickle.load(f) noise_model = NoiseModel.from_backend(properties) for nm in [None, noise_model]: b = AerBackend(nm) for ol in range(3): comp_pass = b.default_compilation_pass(ol) c = Circuit(3, 3) c.H(0) c.CX(0, 1) c.CSWAP(1, 0, 2) c.ZZPhase(0.84, 2, 0) c.add_gate(OpType.TK1, [0.2, 0.3, 0.4], [0]) comp_pass.apply(c) c.measure_all() for pred in b.required_predicates: assert pred.verify(c)
def _add_multi_qubit_op_to_circuit(cmd: ProjectQCommand, circ: Circuit) -> list: assert len(cmd.qubits) > 0 qubs = [qb for qr in cmd.all_qubits for qb in qr] if get_control_count(cmd) < 1: raise Exception("multiq gate " + str(cmd.gate) + " has no controls") else: new_qubits = [] for q in qubs: qubit_no = q.id if qubit_no >= circ.n_qubits: circ.add_blank_wires(1 + qubit_no - circ.n_qubits) new_qubits.append(q) if type(cmd.gate) == pqo.CRz: op = Op.create(_pq_to_tk_multiqs[type(cmd.gate)], cmd.gate.angle / np.pi) else: op = Op.create(_pq_to_tk_multiqs[type(cmd.gate)]) qubit_nos = [qb.id for qr in cmd.all_qubits for qb in qr] circ.add_gate(Op=op, args=qubit_nos) return new_qubits
def test_aer_expanded_gates() -> None: c = Circuit(3).CX(0, 1) c.add_gate(OpType.ZZPhase, 0.1, [0, 1]) c.add_gate(OpType.CY, [0, 1]) c.add_gate(OpType.CCX, [0, 1, 2]) backend = AerBackend() assert backend.valid_circuit(c)
def test_remote_simulator() -> None: remote_qasm = IBMQBackend("ibmq_qasm_simulator", hub="ibm-q", group="open", project="main") c = Circuit(3).CX(0, 1) c.add_gate(OpType.ZZPhase, 0.1, [0, 1]) c.add_gate(OpType.CY, [0, 1]) c.add_gate(OpType.CCX, [0, 1, 2]) c.measure_all() assert remote_qasm.valid_circuit(c) assert sum(remote_qasm.get_counts(c, 10).values()) == 10
def test_ibm_gateset() -> None: state = QuantumState(3) state.set_zero_state() circ = Circuit(3) circ.add_gate(OpType.U1, 0.19, [0]) circ.add_gate(OpType.U2, [0.19, 0.24], [1]) circ.add_gate(OpType.U3, [0.19, 0.24, 0.32], [2]) qulacs_circ = tk_to_qulacs(circ) qulacs_circ.update_quantum_state(state) state1 = QuantumState(3) state1.set_zero_state() qulacs_circ1 = QuantumCircuit(3) qulacs_circ1.add_U1_gate(0, 0.19 * np.pi) qulacs_circ1.add_U2_gate(1, 0.19 * np.pi, 0.24 * np.pi) qulacs_circ1.add_U3_gate(2, 0.19 * np.pi, 0.24 * np.pi, 0.32 * np.pi) qulacs_circ1.update_quantum_state(state1) overlap = inner_product(state1, state) assert np.isclose(1, overlap)
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)
def tk_to_cirq(tkcirc: Circuit, copy_all_qubits: bool = False) -> cirq.circuits.Circuit: """Converts a tket :py:class:`Circuit` object to a Cirq :py:class:`Circuit`. :param tkcirc: The input tket :py:class:`Circuit` :return: The Cirq :py:class:`Circuit` corresponding to the input circuit """ if copy_all_qubits: tkcirc = tkcirc.copy() for q in tkcirc.qubits: tkcirc.add_gate(OpType.noop, [q]) qmap = {} line_name = None grid_name = None # Since Cirq can only support registers of up to 2 dimensions, we explicitly # check for 3-dimensional registers whose third dimension is trivial. # SquareGrid architectures are of this form. indices = [qb.index for qb in tkcirc.qubits] is_flat_3d = all(idx[2] == 0 for idx in indices if len(idx) == 3) for qb in tkcirc.qubits: if len(qb.index) == 0: qmap.update({qb: cirq.ops.NamedQubit(qb.reg_name)}) elif len(qb.index) == 1: if line_name != None and line_name != qb.reg_name: raise NotImplementedError( "Cirq can only support a single linear register") line_name = qb.reg_name qmap.update({qb: LineQubit(qb.index[0])}) elif len(qb.index) == 2 or (len(qb.index) == 3 and is_flat_3d): if grid_name != None and grid_name != qb.reg_name: raise NotImplementedError( "Cirq can only support a single grid register") grid_name = qb.reg_name qmap.update({qb: GridQubit(qb.index[0], qb.index[1])}) else: raise NotImplementedError( "Cirq can only support registers of dimension <=2") oplst = [] for command in tkcirc: op = command.op optype = op.type try: gatetype = _ops2cirq_mapping[optype] except KeyError as error: raise NotImplementedError("Cannot convert tket Op to Cirq gate: " + op.get_name()) from error if optype == OpType.Measure: qid = qmap[command.args[0]] bit = command.args[1] cirqop = cirq.ops.measure(qid, key=bit.__repr__()) else: qids = [qmap[qbit] for qbit in command.args] params = op.params if len(params) == 0: cirqop = gatetype(*qids) elif optype == OpType.PhasedX: cirqop = gatetype(phase_exponent=params[1], exponent=params[0])(*qids) elif optype == OpType.FSim: cirqop = gatetype(theta=float(params[0] * pi), phi=float(params[1] * pi))(*qids) elif optype == OpType.PhasedISWAP: cirqop = gatetype(phase_exponent=params[0], exponent=params[1])(*qids) else: cirqop = gatetype(exponent=params[0])(*qids) oplst.append(cirqop) try: coeff = cmath.exp(float(tkcirc.phase) * cmath.pi * 1j) if coeff != 1.0: oplst.append(cirq.ops.GlobalPhaseOperation(coeff)) except ValueError: warning( "Global phase is dependent on a symbolic parameter, so cannot adjust for " "phase") return cirq.circuits.Circuit(*oplst)
# # Circuit analysis: tket example # This notebook will introduce the basic methods of analysis and visualization of circuits available in `pytket`. # # It makes use of the modules `pytket_qiskit` and `pytket_cirq` for visualization; these need to be installed (with `pip`) in addition to `pytket`. # # We'll start by generating a small circuit to use as an example, and give it a name. from pytket.circuit import Circuit, OpType c = Circuit(4, name="example") c.add_gate(OpType.CU1, 0.5, [0, 1]) c.H(0).X(1).Y(2).Z(3) c.X(0).CX(1, 2).Y(1).Z(2).H(3) c.Y(0).Z(1) c.add_gate(OpType.CU1, 0.5, [2, 3]) c.H(2).X(3) c.Z(0).H(1).X(2).Y(3).CX(3, 0) # ## Basic statistics # From the circuit we can easily read off the number of qubits ... c.n_qubits # ... the name ... c.name # ... the overall depth of the circuit ...
def _tk1_to_u(a: float, b: float, c: float) -> Circuit: circ = Circuit(1) circ.add_gate(OpType.U3, [b, a - 0.5, c + 0.5], [0]) circ.add_phase(-0.5 * (a + c)) return circ
def test_convert() -> None: c = Circuit(3) c.add_gate(OpType.CCX, [0, 1, 2]) c.add_gate(OpType.CX, [0, 1]) c.add_gate(OpType.CU1, 0.1, [0, 1]) c.add_gate(OpType.CSWAP, [0, 1, 2]) c.add_gate(OpType.CY, [0, 1]) c.add_gate(OpType.CZ, [0, 1]) c.add_gate(OpType.H, [0]) c.add_gate(OpType.ISWAPMax, [0, 1]) c.add_gate(OpType.U1, 0.2, [0]) c.add_gate(OpType.Rx, 0.3, [0]) c.add_gate(OpType.Ry, 0.4, [0]) c.add_gate(OpType.Rz, 0.5, [0]) c.add_gate(OpType.S, [0]) c.add_gate(OpType.Sdg, [0]) c.add_gate(OpType.SWAP, [0, 1]) c.add_gate(OpType.T, [0]) c.add_gate(OpType.Tdg, [0]) c.add_gate(OpType.V, [0]) c.add_gate(OpType.Vdg, [0]) c.add_gate(OpType.X, [0]) c.add_gate(OpType.XXPhase, 0.6, [0, 1]) c.add_gate(OpType.ISWAP, 0.7, [0, 1]) c.add_gate(OpType.Y, [0]) c.add_gate(OpType.YYPhase, 0.8, [0, 1]) c.add_gate(OpType.Z, [0]) c.add_gate(OpType.ZZPhase, 0.9, [0, 1]) bkc = tk_to_braket(c) c1 = braket_to_tk(bkc) assert c.get_commands() == c1.get_commands()
def braket_to_tk(bkcirc: BK_Circuit) -> Circuit: """ Convert a braket circuit to a tket :py:class:`Circuit` :param bkcirc: circuit to be converted :returns: circuit converted to tket """ n_qbs = len(bkcirc.qubits) tkcirc = Circuit(n_qbs) for instr in bkcirc.instructions: op = instr.operator qbs = [bkcirc.qubits.index(qb) for qb in instr.target] opname = op.name if opname == "CCNot": tkcirc.add_gate(OpType.CCX, qbs) elif opname == "CNot": tkcirc.add_gate(OpType.CX, qbs) elif opname == "CPhaseShift": tkcirc.add_gate(OpType.CU1, op.angle / pi, qbs) elif opname == "CSwap": tkcirc.add_gate(OpType.CSWAP, qbs) elif opname == "CY": tkcirc.add_gate(OpType.CY, qbs) elif opname == "CZ": tkcirc.add_gate(OpType.CZ, qbs) elif opname == "H": tkcirc.add_gate(OpType.H, qbs) elif opname == "I": pass elif opname == "ISwap": tkcirc.add_gate(OpType.ISWAPMax, qbs) elif opname == "PhaseShift": tkcirc.add_gate(OpType.U1, op.angle / pi, qbs) elif opname == "Rx": tkcirc.add_gate(OpType.Rx, op.angle / pi, qbs) elif opname == "Ry": tkcirc.add_gate(OpType.Ry, op.angle / pi, qbs) elif opname == "Rz": tkcirc.add_gate(OpType.Rz, op.angle / pi, qbs) elif opname == "S": tkcirc.add_gate(OpType.S, qbs) elif opname == "Si": tkcirc.add_gate(OpType.Sdg, qbs) elif opname == "Swap": tkcirc.add_gate(OpType.SWAP, qbs) elif opname == "T": tkcirc.add_gate(OpType.T, qbs) elif opname == "Ti": tkcirc.add_gate(OpType.Tdg, qbs) elif opname == "V": tkcirc.add_gate(OpType.V, qbs) tkcirc.add_phase(0.25) elif opname == "Vi": tkcirc.add_gate(OpType.Vdg, qbs) tkcirc.add_phase(-0.25) elif opname == "X": tkcirc.add_gate(OpType.X, qbs) elif opname == "XX": tkcirc.add_gate(OpType.XXPhase, op.angle / pi, qbs) elif opname == "XY": tkcirc.add_gate(OpType.ISWAP, op.angle / pi, qbs) elif opname == "Y": tkcirc.add_gate(OpType.Y, qbs) elif opname == "YY": tkcirc.add_gate(OpType.YYPhase, op.angle / pi, qbs) elif opname == "Z": tkcirc.add_gate(OpType.Z, qbs) elif opname == "ZZ": tkcirc.add_gate(OpType.ZZPhase, op.angle / pi, qbs) else: # The following don't have direct equivalents: # - CPhaseShift00, CPhaseShift01, CPhaseShift10: diagonal unitaries with 1s # on the diagonal except for a phase e^{ia} in the (0,0), (1,1) or (2,2) # position respectively. # - PSwap: unitary with 1s at (0,0) and (3,3), a phase e^{ia} at (1,2) and # (2,1), and zeros elsewhere. # They could be decomposed into pytket gates, but it would be better to add # the gate types to tket. # The "Unitary" type could be represented as a box in the 1q and 2q cases, # but not in general. raise NotImplementedError(f"Cannot convert {opname} to tket") return tkcirc
# ## Classical controls # Most of the examples above involve only pure quantum gates. However, `pytket` can also represent gates whose operation is conditional on one or more classical inputs. # # For example, suppose we want to run the complex circuit `c` we've just constructed, then measure qubits 0 and 1, and finally apply an $\mathrm{Rz}(\frac{1}{2})$ rotation to qubit 2 if and only if the measurements were 0 and 1 respectively. # # First, we'll add two classical wires to the circuit to store the measurement results: from pytket.circuit import Bit c.add_c_register("m", 2) m = [Bit("m", i) for i in range(2)] # Classically conditioned operations depend on all their inputs being 1. Since we want to condition on `m[0]` being 0, we must first apply an X gate to its qubit, and then measure: q = [Qubit("q", i) for i in range(3)] c.X(q[0]) c.Measure(q[0], m[0]) c.Measure(q[1], m[1]) # Finally we add the classically conditioned Rz operation, using the `add_gate()` method: from pytket.circuit import OpType c.add_gate(OpType.Rz, [0.5], [q[2]], condition_bits=[m[0], m[1]], condition_value=3) # Note that many of the transforms and compilation passes will not accept circuits that contain classical controls.
def cirq_to_tk(circuit: cirq.circuits.Circuit) -> Circuit: """Converts a Cirq :py:class:`Circuit` to a tket :py:class:`Circuit` object. :param circuit: The input Cirq :py:class:`Circuit` :raises NotImplementedError: If the input contains a Cirq :py:class:`Circuit` operation which is not yet supported by pytket :return: The tket :py:class:`Circuit` corresponding to the input circuit """ tkcirc = Circuit() qmap = {} for qb in circuit.all_qubits(): if isinstance(qb, LineQubit): uid = Qubit("q", qb.x) elif isinstance(qb, GridQubit): uid = Qubit("g", qb.row, qb.col) elif isinstance(qb, cirq.ops.NamedQubit): uid = Qubit(qb.name) else: raise NotImplementedError("Cannot convert qubits of type " + str(type(qb))) tkcirc.add_qubit(uid) qmap.update({qb: uid}) for moment in circuit: for op in moment.operations: if isinstance(op, cirq.ops.GlobalPhaseOperation): tkcirc.add_phase(cmath.phase(op.coefficient) / pi) continue gate = op.gate gatetype = type(gate) qb_lst = [qmap[q] for q in op.qubits] if isinstance(gate, cirq_common.HPowGate) and gate.exponent == 1: gate = cirq_common.H elif (gatetype == cirq_common.CNotPowGate and cast(cirq_common.CNotPowGate, gate).exponent == 1): gate = cirq_common.CNOT elif (gatetype == cirq_pauli._PauliX and cast(cirq_pauli._PauliX, gate).exponent == 1): gate = cirq_pauli.X elif (gatetype == cirq_pauli._PauliY and cast(cirq_pauli._PauliY, gate).exponent == 1): gate = cirq_pauli.Y elif (gatetype == cirq_pauli._PauliZ and cast(cirq_pauli._PauliZ, gate).exponent == 1): gate = cirq_pauli.Z if gate in _constant_gates: try: optype = _cirq2ops_mapping[gate] except KeyError as error: raise NotImplementedError( "Operation not supported by tket: " + str(op.gate)) from error params = [] elif isinstance(gate, cirq_common.MeasurementGate): uid = Bit(gate.key) tkcirc.add_bit(uid) tkcirc.Measure(*qb_lst, uid) continue elif isinstance(gate, cirq.ops.PhasedXPowGate): optype = OpType.PhasedX pe = gate.phase_exponent params = [gate.exponent, pe] elif isinstance(gate, cirq.ops.FSimGate): optype = OpType.FSim params = [gate.theta / pi, gate.phi / pi] elif isinstance(gate, cirq.ops.PhasedISwapPowGate): optype = OpType.PhasedISWAP params = [gate.phase_exponent, gate.exponent] else: try: optype = _cirq2ops_mapping[gatetype] params = [cast(Any, gate).exponent] except (KeyError, AttributeError) as error: raise NotImplementedError( "Operation not supported by tket: " + str(op.gate)) from error tkcirc.add_gate(optype, params, qb_lst) return tkcirc
def _tk1_to_phasedxrz(a: float, b: float, c: float) -> Circuit: circ = Circuit(1) circ.Rz(a + c, 0) circ.add_gate(OpType.PhasedX, [b, a], [0]) RemoveRedundancies().apply(circ) return circ