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 test_multireg() -> None: b = HoneywellBackend(device_name="HQS-LT-1.0-APIVAL", label="test 3") c = Circuit() q1 = Qubit("q1", 0) q2 = Qubit("q2", 0) c1 = Bit("c1", 0) c2 = Bit("c2", 0) for q in (q1, q2): c.add_qubit(q) for cb in (c1, c2): c.add_bit(cb) c.H(q1) c.CX(q1, q2) c.Measure(q1, c1) c.Measure(q2, c2) b.compile_circuit(c) n_shots = 10 shots = b.get_shots(c, n_shots) assert np.array_equal(shots, np.zeros((10, 2)))
circ2 = cu.circuit print(tk_to_qiskit(circ2)) # Note that the pass we just ran also performed some clean-up: the SWAP gate was decomposed into three CX gates, one of which was cancelled by a preceding CX gate; the cancelling gates were removed from the circuit. # # Every compilation pass has associated sets of preconditions and postconditions on the circuit. If all preconditions are satisfied before the pass, all postconditions are guaranteed to be satisfied afterwards. When we apply a pass to a circuit, we can optionally pass `SafetyMode.Audit` as the second parameter; this will tell the pass to check all preconditions explicitly. By default, there is only limited checking of preconditions and `pytket` relies on the programmer assuring these. # # For example, the `NoClassicalControl` predicate is a precondition of the `PauliSimp` pass. Let's add a classically controlled gate to our circuit: from pytket.passes import PauliSimp, SafetyMode from pytket.circuit import Qubit, Bit q = [Qubit("q", i) for i in range(5)] c = Bit("c") circ.add_bit(c) circ.Measure(q[3], c) circ.CY(q[0], q[1], condition_bits=[c], condition_value=1) cu = CompilationUnit(circ) try: PauliSimp().apply(cu, safety_mode=SafetyMode.Audit) except RuntimeError as e: print("Error:", str(e)) # The preconditions and postconditions of all the elementary predicates are documented in their string representations: PauliSimp() # ## Backends and default passes # A `pytket` `Backend` may have a default compilation pass, which will guarantee that the circuit can run on it. This is given by the `default_compilation_pass` property. For example, the default pass for Qiskit's `AerBackend` just converts all gates to U1, U2, U3 and CX:
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