def test_state() -> None: c = Circuit(2).H(0).CX(0, 1) b = CirqStateSimBackend() state = b.get_state(c) assert np.allclose(state, [math.sqrt(0.5), 0, 0, math.sqrt(0.5)], atol=1e-10) c.add_phase(0.5) state1 = b.get_state(c) assert np.allclose(state1, state * 1j, atol=1e-10)
def test_state() -> None: c0 = Circuit(2).H(0).CX(0, 1) b = CirqStateSimBackend() state0 = b.get_state(c0) assert np.allclose(state0, [math.sqrt(0.5), 0, 0, math.sqrt(0.5)], atol=1e-10) c0.add_phase(0.5) state1 = b.get_state(c0) assert np.allclose(state1, state0 * 1j, atol=1e-10) assert np.allclose(b.get_state(Circuit(2).X(1)), [0, 1.0, 0, 0], atol=1e-10)
def test_statevector_phase() -> None: for b in backends: circ = Circuit(2) circ.H(0).CX(0, 1) b.compile_circuit(circ) state = b.get_state(circ) assert np.allclose( state, [math.sqrt(0.5), 0, 0, math.sqrt(0.5)], atol=1e-10) circ.add_phase(0.5) state1 = b.get_state(circ) assert np.allclose(state1, state * 1j, atol=1e-10)
def _aqt_rebase() -> BasePass: # CX replacement c_cx = Circuit(2) c_cx.Ry(0.5, 0).Rx(0.5, 0) c_cx.Rx(-0.5, 1) c_cx.add_gate(OpType.XXPhase, 0.5, [0, 1]) c_cx.Ry(0.5, 0).Rx(-1, 0) c_cx.add_phase(-0.25) # TK1 replacement c_tk1 = lambda a, b, c: Circuit(1).Rx(-0.5, 0).Ry(c, 0).Rx(b, 0).Ry( a, 0).Rx(0.5, 0) return RebaseCustom({OpType.XXPhase}, c_cx, {OpType.Rx, OpType.Ry}, c_tk1)
def _tk1_to_x_sx_rz(a: float, b: float, c: float) -> Circuit: circ = Circuit(1) if _approx_0_mod_2(b): circ.Rz(a + c, 0) elif _approx_0_mod_2(b + 1): if _approx_0_mod_2(a - 0.5) and _approx_0_mod_2(c - 0.5): circ.X(0) else: circ.Rz(c, 0).X(0).Rz(a, 0) else: # use SX; SX = e^{i\pi/4}V; V = RX(1/2) if _approx_0_mod_2(a - 0.5) and _approx_0_mod_2(c - 0.5): circ.SX(0).Rz(1 - b, 0).SX(0) circ.add_phase(-0.5) else: circ.Rz(c + 0.5, 0).SX(0).Rz(b - 1, 0).SX(0).Rz(a + 0.5, 0) circ.add_phase(-0.5) return circ
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
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_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
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)