def dagcircuit_to_tk(dag: DAGCircuit, _BOX_UNKNOWN: bool = BOX_UNKNOWN, _DROP_CONDS: bool = DROP_CONDS) -> Circuit: """Converts a :py:class:`qiskit.DAGCircuit` into a :math:`\\mathrm{t|ket}\\rangle` :py:class:`Circuit`. Note that not all Qiskit operations are currently supported by pytket. Classical registers are supported only as the output of measurements. This does not attempt to preserve the structure of the quantum registers, instead creating one big quantum register. :param dag: A circuit to be converted :return: The converted circuit """ qs = dag.qubits() qnames = ["%s[%d]" % (r.name, i) for r, i in qs] g = dag._multi_graph circ = Circuit() if DEBUG: print("new graph w " + str(len(qs)) + " qubits") print(str(qs)) # process vertices tk_vs = dict() for n in list(g.nodes(data=True)): node = n[0] if DEBUG: print(str(node.type) + " " + str(node.name)) if ((node.type == "in" or node.type == "out") and not node.name in qnames): # don't create vertices for in/outs of classical registers if DEBUG: print("Dropping node " + str(node)) continue else: tk_vs[node] = circ._add_vertex( _node_converter(circ, node, _BOX_UNKNOWN=_BOX_UNKNOWN, _DROP_CONDS=_DROP_CONDS)) if DEBUG: print("qiskit vertex " + str(node) + " is t|ket> vertex " + str(tk_vs[node])) # process edges for e in g.edges(data=True): wire = e[2]["wire"] if wire in qs: # ignore classical wires src_port = _get_port_for_edge(e[0], wire) tgt_port = _get_port_for_edge(e[1], wire) if DEBUG: print( _make_edge_str(tk_vs[e[0]], src_port, tk_vs[e[1]], tgt_port)) circ._add_edge(tk_vs[e[0]], src_port, tk_vs[e[1]], tgt_port) return circ
def pyquil_to_tk(prog: Program) -> Circuit: """ Convert a :py:class:`pyquil.Program` to a :math:`\\mathrm{t|ket}\\rangle` :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 """ reg_name = None qubits = prog.get_qubits() n_qubits = max(qubits) + 1 tkc = Circuit(n_qubits) for i in prog.instructions: if isinstance(i, Gate): name = i.name try: optype = _known_quil_gate[name] except KeyError as error: raise NotImplementedError("Operation not supported by tket: " + str(i)) from error if len(i.params) == 0: tkc.add_operation(optype, [q.index for q in i.qubits]) else: params = [p / PI for p in i.params] op = tkc._get_op(optype, params) tkc._add_operation(op, [q.index for q in i.qubits]) elif isinstance(i, Measurement): if not i.classical_reg: raise NotImplementedError( "Program has no defined classical register for measurement on qubit: ", i.qubits[0]) reg = i.classical_reg if reg_name and reg_name != reg.name: raise NotImplementedError( "Program has multiple classical registers: ", reg_name, reg.name) reg_name = reg.name op = tkc._get_op(OpType.Measure, str(reg.offset)) tkc._add_operation(op, [i.qubit.index]) elif isinstance(i, Declare): continue 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 qiskit_to_tk(qcirc: QuantumCircuit) -> Circuit : """Convert a :py:class:`qiskit.QuantumCircuit` to a :py:class:`Circuit`. :param qcirc: A circuit to be converted :type qcirc: QuantumCircuit :return: The converted circuit :rtype: Circuit """ tkc = Circuit() qregmap = {} for reg in qcirc.qregs : tk_reg = tkc.add_q_register(reg.name, len(reg)) qregmap.update({reg : tk_reg}) cregmap = {} for reg in qcirc.cregs : tk_reg = tkc.add_c_register(reg.name, len(reg)) cregmap.update({reg : tk_reg}) for i, qargs, cargs in qcirc.data : if i.control is not None : raise NotImplementedError("Cannot convert conditional gates from Qiskit to tket") optype = _known_qiskit_gate[type(i)] qubits = [qregmap[r][ind] for r, ind in qargs] bits = [cregmap[r][ind] for r, ind in cargs] if optype == OpType.Measure : tkc.add_measure(*qubits, *bits) continue params = [p/pi for p in i.params] tkc.add_gate(optype, params, qubits, []) return tkc
def cirq_to_tk(circuit: cirq.Circuit) -> Circuit: """Converts a Cirq :py:class:`Circuit` to a :math:`\\mathrm{t|ket}\\rangle` :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 :math:`\\mathrm{t|ket}\\rangle` :py:class:`Circuit` corresponding to the input circuit """ qubit_list = _indexed_qubits_from_circuit(circuit) qid_to_num = {q: i for i, q in enumerate(qubit_list)} n_qubits = len(circuit.all_qubits()) tkcirc = Circuit(n_qubits) for moment in circuit: for op in moment.operations: gate = op.gate gatetype = type(gate) qb_lst = [qid_to_num[q] for q in op.qubits] n_qubits = len(op.qubits) if gatetype == cirq_common.HPowGate and gate.exponent == 1: gate = cirq_common.H elif gatetype == cirq_common.CNotPowGate and gate.exponent == 1: gate = cirq_common.CNOT elif gatetype == cirq_pauli._PauliX and gate.exponent == 1: gate = cirq_pauli.X elif gatetype == cirq_pauli._PauliY and gate.exponent == 1: gate = cirq_pauli.Y elif gatetype == cirq_pauli._PauliZ and 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 o = tkcirc._get_op(optype) elif isinstance(gate, cirq_common.MeasurementGate): o = tkcirc._get_op(OpType.Measure, n_qubits, n_qubits, gate.key) elif isinstance(gate, cirq.PhasedXPowGate): pe = gate.phase_exponent e = gate.exponent o = tkcirc._get_op(OpType.PhasedX, 1, 1, [e, pe]) else: try: optype = _cirq2ops_mapping[gatetype] except KeyError as error: raise NotImplementedError( "Operation not supported by tket: " + str(op.gate)) from error o = tkcirc._get_op(optype, n_qubits, n_qubits, gate.exponent) tkcirc._add_operation(o, qb_lst) return tkcirc
def run(self, circuit: Circuit, shots: int, fit_to_constraints=True, seed: int = None) -> np.ndarray: """Run a circuit on Qiskit Aer Qasm simulator. :param circuit: The circuit to run :type circuit: Circuit :param shots: Number of shots (repeats) to run :type shots: int :param fit_to_constraints: Compile the circuit to meet the constraints of the backend, defaults to True :type fit_to_constraints: bool, optional :param seed: random seed to for simulator :type seed: int :return: Table of shot results, each row is a shot, columns are ordered by qubit ordering. Values are 0 or 1, corresponding to qubit basis states. :rtype: numpy.ndarray """ c = circuit.copy() if fit_to_constraints: Transform.RebaseToQiskit().apply(c) dag = tk_to_dagcircuit(c) qc = dag_to_circuit(dag) qobj = assemble(qc, shots=shots, seed_simulator=seed, memory=True) job = self._backend.run(qobj, noise_model=self.noise_model) shot_list = job.result().get_memory(qc) return np.asarray([_convert_bin_str(shot) for shot in shot_list])
def __init__(self): """ Initialize the tketBackendEngine. Initializes local Circuit to an empty Circuit. """ BasicEngine.__init__(self) self._circuit = Circuit()
def _routed_ibmq_circuit(circuit: Circuit, arc: Architecture) -> QuantumCircuit: c = circuit.copy() Transform.RebaseToQiskit().apply(c) physical_c = route(c, arc) physical_c.decompose_SWAP_to_CX() physical_c.redirect_CX_gates(arc) Transform.OptimisePostRouting().apply(physical_c) qc = tk_to_qiskit(physical_c) return qc
def projectq_expectation_value(circuit:Circuit,hamiltonian:QubitOperator) -> float : ProjectQback = Simulator() fwd = ForwarderEngine(ProjectQback) eng = MainEngine(backend=ProjectQback,engine_list=[fwd]) qureg = eng.allocate_qureg(circuit.n_qubits) c = circuit.copy() Transform.RebaseToProjectQ().apply(c) tk_to_projectq(eng,qureg,c) eng.flush() energy = eng.backend.get_expectation_value(hamiltonian,qureg) All(Measure) | qureg return energy
def get_state(self,circuit:Circuit, fit_to_constraints=True) -> list: c = circuit.copy() if fit_to_constraints : Transform.RebaseToProjectQ().apply(c) fwd = ForwarderEngine(self._backend) eng = MainEngine(backend=self._backend,engine_list=[fwd]) qureg = eng.allocate_qureg(c.n_qubits) tk_to_projectq(eng,qureg,c) eng.flush() state = self._backend.cheat()[1] #`cheat()` returns tuple:(a dictionary of qubit indices, statevector) All(Measure) | qureg return state #list of complex numbers
def pyzx_to_tk(pyzx_circ: pyzxCircuit) -> Circuit: """ Convert a :py:class:`pyzx.Circuit` to a :math:`\\mathrm{t|ket}\\rangle` :py:class:`Circuit` . All PyZX basic gate operations are currently supported by pytket. Run `pyzx_circuit_name.to_basic_gates()` before conversion. :param prog: A circuit to be converted :return: The converted circuit """ c = Circuit(pyzx_circ.qubits) for g in pyzx_circ.gates: if not g.name in _pyzx_to_tk_gates: raise Exception("Cannot parse PyZX gate of type " + g.name + "into tket Circuit") op_type = _pyzx_to_tk_gates[g.name] if (hasattr(g, 'control')): qbs = [getattr(g, 'control'), getattr(g, 'target')] else: qbs = [getattr(g, 'target')] if (hasattr(g, "printphase") and op_type in _parameterised_gates): op = c._get_op(OpType=op_type, param=float(g.phase)) else: op = c._get_op(OpType=op_type, parameters=[]) c._add_operation(Op=op, qubits=qbs) return c
def tk_to_qiskit(tkcirc: Circuit) -> QuantumCircuit : """Convert back :param tkcirc: A circuit to be converted :type tkcirc: Circuit :return: The converted circuit :rtype: QuantumCircuit """ tkc = tkcirc if isinstance(tkcirc, PhysicalCircuit) : tkc = tkcirc._get_circuit() qcirc = QuantumCircuit() qregmap = {} for _, reg in tkc.q_regs.items() : if reg.size() == 0 : continue name = reg.name if len(name) == 0 : name = None qis_reg = QuantumRegister(reg.size(), name) qregmap.update({reg : qis_reg}) qcirc.add_register(qis_reg) cregmap = {} for _, reg in tkc.c_regs.items() : if reg.size() == 0 : continue name = reg.name if len(name) == 0 : name = None qis_reg = ClassicalRegister(reg.size(), name) cregmap.update({reg : qis_reg}) qcirc.add_register(qis_reg) tempregmap = {} for command in tkc : op = command.op qubits = command.qubits qargs = [qregmap[q.reg][q.index] for q in qubits] if len(command.controls) != 0 : raise NotImplementedError("Cannot convert conditional gates from tket to Qiskit") if op.get_type() == OpType.Measure : bits = [_convert_bit(b, cregmap, qcirc, tempregmap) for b in command.bits] qcirc.measure(*qargs, *bits) continue params = [p * pi for p in op.get_params()] try : gatetype = _known_qiskit_gate_rev[op.get_type()] except KeyError as error : raise NotImplementedError("Cannot convert tket Op to Qiskit gate: " + op.get_name()) from error g = gatetype(*params) qcirc.append(g, qargs=qargs) return qcirc
def receive(self, command_list): """ Receives a list of commands and appends to local Circuit. If a flush gate is received, optimises the Circuit using a default Transform pass and then sends the commands from this optimised Circuit into the next engine. """ for cmd in command_list: if cmd.gate == pqo.FlushGate(): #flush gate --> optimize and then flush cmd_list = self._optimise() cmd_list.append(cmd) self._circuit = Circuit() self._qubit_dictionary = dict() self.send(cmd_list) continue _handle_gate(cmd,self)
def pyquil_to_tk(prog: Program) -> Circuit: """ Convert a :py:class:`pyquil.Program` to a :math:`\\mathrm{t|ket}\\rangle` :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 """ qubits = prog.get_qubits() n_qubits = max(qubits) + 1 tkc = Circuit(n_qubits) qreg = tkc.q_regs["q"] cregmap = {} 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 = [qreg[q.index] for q in i.qubits] params = [p / pi for p in i.params] tkc.add_gate(optype, params, qubits, []) elif isinstance(i, Measurement): qubit = qreg[i.qubit.index] reg = cregmap[i.classical_reg.name] bit = reg[i.classical_reg.offset] tkc.add_measure(qubit, bit) elif isinstance(i, Declare): if i.memory_type is not 'BIT': raise NotImplementedError("Cannot handle memory of type " + i.memory_type) new_reg = tkc.add_c_register(i.name, i.memory_size) cregmap.update({i.name: new_reg}) 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 _add_single_qubit_op_to_circuit(cmd:ProjectQCommand,circ:Circuit): 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 type(cmd.gate) in (pqo.Rx,pqo.Ry,pqo.Rz): op = circ._get_op(OpType=_pq_to_tk_singleqs[type(cmd.gate)],param=cmd.gate.angle/np.pi) else: op = circ._get_op(OpType=_pq_to_tk_singleqs[type(cmd.gate)]) if (qubit_no >= circ.n_qubits): circ.add_blank_wires(1+qubit_no-circ.n_qubits) new_qubit = True circ._add_operation(Op=op,qubits=[qubit_no]) return new_qubit
def _add_daggered_op_to_circuit(cmd:ProjectQCommand, circ:Circuit): undaggered_gate = cmd.gate.get_inverse() if (type(undaggered_gate) == pqo.TGate): op = circ._get_op(OpType=OpType.Tdg) elif (type(undaggered_gate) == pqo.SGate): op = circ._get_op(OpType=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_operation(Op=op,qubits=[qubit_no]) return new_qubit
def raw_run_return_result(self, circuit: Circuit, shots: int, circ_name: str, seed: int = None) -> np.ndarray: """Run a circuit on Qiskit Aer Qasm simulator. :param circuit: The circuit to run :type circuit: Circuit :param shots: Number of shots (repeats) to run :type shots: int :param fit_to_constraints: Compile the circuit to meet the contstraints of the backend, defaults to True :type fit_to_constraints: bool, optional :param seed: random seed to for simulator :type seed: int :return: Table of shot results, each row is a shot, columns are ordered by qubit ordering. Values are 0 or 1, corresponding to qubit basis states. :rtype: numpy.ndarray """ c = circuit.copy() dag = tk_to_named_dagcircuit(circ_name, c) qc = dag_to_circuit(dag) qobj = assemble(qc, shots=shots, seed_simulator=seed, memory=True) job = self._backend.run(qobj, noise_model=self.noise_model) return job.result()
def _add_multi_qubit_op_to_circuit(cmd:ProjectQCommand,circ:Circuit): 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 = circ._get_op(OpType=_pq_to_tk_multiqs[type(cmd.gate)],param=cmd.gate.angle/np.pi) else: op = circ._get_op(OpType=_pq_to_tk_multiqs[type(cmd.gate)]) qubit_nos = [qb.id for qr in cmd.all_qubits for qb in qr] circ._add_operation(Op = op, qubits=qubit_nos) return new_qubits
def cirq_to_tk(circuit: cirq.Circuit) -> Circuit: """Converts a Cirq :py:class:`Circuit` to a :math:`\\mathrm{t|ket}\\rangle` :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 :math:`\\mathrm{t|ket}\\rangle` :py:class:`Circuit` corresponding to the input circuit """ qubit_list = _indexed_qubits_from_circuit(circuit) n_qubits = len(circuit.all_qubits()) tkcirc = Circuit(n_qubits) qreg = tkcirc.q_regs["q"] qmap = {q: qreg[i] for i, q in enumerate(qubit_list)} for moment in circuit: for op in moment.operations: gate = op.gate gatetype = type(gate) qb_lst = [qmap[q] for q in op.qubits] n_qubits = len(op.qubits) if gatetype == cirq_common.HPowGate and gate.exponent == 1: gate = cirq_common.H elif gatetype == cirq_common.CNotPowGate and gate.exponent == 1: gate = cirq_common.CNOT elif gatetype == cirq_pauli._PauliX and gate.exponent == 1: gate = cirq_pauli.X elif gatetype == cirq_pauli._PauliY and gate.exponent == 1: gate = cirq_pauli.Y elif gatetype == cirq_pauli._PauliZ and 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): creg = tkcirc.add_c_register(gate.key, 1) tkcirc.add_measure(*qb_lst, creg[0]) continue elif isinstance(gate, cirq.PhasedXPowGate): optype = OpType.PhasedX pe = gate.phase_exponent e = gate.exponent params = [e, pe] else: try: optype = _cirq2ops_mapping[gatetype] except KeyError as error: raise NotImplementedError( "Operation not supported by tket: " + str(op.gate)) from error params = [gate.exponent] tkcirc.add_gate(optype, params, qb_lst, []) return tkcirc
def __init__(self): BasicEngine.__init__(self) self._circuit = Circuit() self._qubit_dictionary = dict()