def test_missing_qubits(self): """Test that an error is raised if qubits are missing.""" with self.subTest(msg="no control qubits"): with self.assertRaises(AttributeError): _ = MCMT(XGate(), num_ctrl_qubits=0, num_target_qubits=1) with self.subTest(msg="no target qubits"): with self.assertRaises(AttributeError): _ = MCMT(ZGate(), num_ctrl_qubits=4, num_target_qubits=0)
def test_different_gate_types(self): """Test the different supported input types for the target gate.""" x_circ = QuantumCircuit(1) x_circ.x(0) for input_gate in [x_circ, QuantumCircuit.cx, QuantumCircuit.x, "cx", "x", CXGate()]: with self.subTest(input_gate=input_gate): mcmt = MCMT(input_gate, 2, 2) if isinstance(input_gate, QuantumCircuit): self.assertEqual(mcmt.gate.definition[0][0], XGate()) self.assertEqual(len(mcmt.gate.definition), 1) else: self.assertEqual(mcmt.gate, XGate())
def controlled_controlled_minus_iY(): target = QuantumRegister(1,'t_qbit') register = QuantumRegister(2,'r_qbit') ancillae = QuantumRegister(1,'a_qbit') or_qubit = QuantumRegister(1,'o_qbit') qc = QuantumCircuit(or_qubit,register,ancillae,target) qc.ccx(or_qubit,register[0],ancillae[0]) qc.append(MCMT(minus_iY(),2,1),[ancillae[-1],register[-1],target]) qc.ccx(or_qubit,register[0],ancillae[0]) return qc.to_instruction()
def controlled_U(theta): """ Controlled post-select unitary U """ new_qubit = QuantumRegister(1, 'n_qbit') old_qubit = QuantumRegister(1, 'o_qbit') target = QuantumRegister(1, 't_qbit') qc = QuantumCircuit(old_qubit, new_qubit, target) qc.ry(2 * theta, new_qubit) qc.append(MCMT(minus_iY(), 2, 1), [old_qubit, new_qubit, target]) qc.ry(-2 * theta, new_qubit) return qc.to_instruction()
def U(theta): """ Post-select unitary U """ register = QuantumRegister(2,'a_qbit') target = QuantumRegister(1,'t_qbit') qc = QuantumCircuit(register,target) qc.ry(2*theta,[*register]) qc.append(MCMT(minus_iY(),2,1),[*register,*target]) qc.ry(-2*theta,[*register]) return qc.to_instruction()
def U(theta): """ Post-select unitary U """ ancillae = QuantumRegister(1, 'a_qbit') target = QuantumRegister(1, 't_qbit') qc = QuantumCircuit(ancillae, target) qc.ry(2 * theta, [*ancillae]) qc.append(MCMT(minus_iY(), 1, 1), [*ancillae, *target]) #qc.u3(np.pi,0,0) = -iY qc.ry(-2 * theta, [*ancillae]) return qc.to_instruction()
def add_cnry( param: float, qbits: List[int], qr: QuantumRegister, circuits: List[Union[Circuit, QuantumCircuit]], ) -> None: """Add a CnRy gate to each circuit in a list, each one being either a tket or qiskit circuit.""" assert len(qbits) >= 2 for circ in circuits: if isinstance(circ, Circuit): circ.add_gate(OpType.CnRy, param, qbits) else: # param was "raw", so needs an extra PI. new_ry_gate = RYGate(param * pi) new_gate = MCMT(gate=new_ry_gate, num_ctrl_qubits=len(qbits) - 1, num_target_qubits=1) circ.append(new_gate, [qr[nn] for nn in qbits])
def S_m(): """ Reflection operator S_m(pi/3) """ def phase_shift(): S = Operator(np.array([[1,0],[0,np.exp(1j*np.pi/3)]])) target = QuantumRegister(1,'t_qbit') qc = QuantumCircuit(target) qc.unitary(S,[*target]) return qc target_register = QuantumRegister(1,'ta_qbit') register = QuantumRegister(1,'r_qbit') qc = QuantumCircuit(target_register,register) qc.x([*register,*target_register]) qc.append(MCMT(phase_shift(),1,1),[*register,*target_register]) qc.x([*register,*target_register]) return qc.to_instruction()
def ram(nqubits, lists_final): list_qram = [i for i in range(nqubits)] qram = QuantumRegister(nqubits, "qram") qalgo = QuantumRegister(nqubits, "algo") qc = QuantumCircuit(qram, qalgo) control_h = MCMT("h", nqubits, 1).to_gate() map_ram_2 = [["x", "x"], ["o", "x"], ["x", "o"], ["o", "o"]] map_ram_3 = [ ["x", "x", "x"], ["o", "x", "x"], ["x", "o", "x"], ["o", "o", "x"], ["x", "x", "o"], ["o", "x", "o"], ["x", "o", "o"], ["o", "o", "o"], ] if len(bin(len(lists_final))[2:]) == 3: map_ram = map_ram_3 if len(bin(len(lists_final))[2:]) == 2: map_ram = map_ram_2 for i, m_ram in zip(range(len(lists_final)), map_ram): # qc.barrier() for index, gate in enumerate(m_ram): if gate == "x": qc.x(qram[index]) if lists_final[i][0] == "x" or lists_final[i][0] == "sup": qc.mcx(qram, qalgo[0]) else: qc.append(control_h, [*list_qram, qalgo[0]]) if len(lists_final[i]) == 3: if lists_final[i][1] == "x": qc.mcx(qram, qalgo[1]) elif lists_final[i][1] == "intric": qc.mcx([qram[0], qram[1], qram[2], qalgo[0]], qalgo[1]) else: qc.append(control_h, [*list_qram, qalgo[1]]) if lists_final[i][-1] == "x": qc.mcx(qram, qalgo[-1]) elif lists_final[i][-1] == "intric": if len(lists_final[i]) == 3: qc.mcx([qram[0], qram[1], qram[2], qalgo[1]], qalgo[-1]) else: qc.mcx([qram[0], qram[1], qalgo[0]], qalgo[-1]) else: qc.append(control_h, [*list_qram, qalgo[-1]]) for index, gate in enumerate(m_ram): if gate == "x": qc.x(qram[index]) # print(qc.draw()) U_s = qc.to_gate() U_s.name = "$Qram$" return U_s
def experiment(p, t, measure_type=None, noise_model=None): n_register_qubits = t + p * t n_state_qubits = 1 n_or_qubits = (p + 1) * (t - 1 ) #additional OR gates for scrambling at the end register_qubits = QuantumRegister(n_register_qubits, 'r_qbit') state_qubits = QuantumRegister(n_state_qubits, 's_qbit') or_qubits = QuantumRegister(n_or_qubits, 'o_qbit') c = ClassicalRegister(1) circ = QuantumCircuit(register_qubits, or_qubits, state_qubits, c) circ.h(state_qubits) #initial input state circ.h(register_qubits) #Initial Round #Controlled Unitary for i, q in enumerate(register_qubits[:t][::-1]): circ.append(MCMT(Unitary(i), 1, 1), [q, state_qubits]) #QFT-dagger for qubit in range(int(t / 2)): circ.swap(qubit, t - qubit - 1) for j in range(t, 0, -1): k = t - j for m in range(k): circ.cu1(-np.pi / float(2**(k - m)), t - m - 1, t - k - 1) circ.h(t - k - 1) #OR-Gate circ.x([*register_qubits[:t], *or_qubits[:t - 1]]) circ.ccx(register_qubits[0], register_qubits[1], or_qubits[0]) for i in range(t - 2): circ.x(or_qubits[i]) circ.ccx(or_qubits[i], register_qubits[i + 2], or_qubits[i + 1]) #Reset / Scrambling gate circ.ch(or_qubits[t - 2], state_qubits) #Subsequent Rounds for j in range(1, p + 1): #CCU for i, q in enumerate(register_qubits[t * j:t * (j + 1)][::-1]): #circ.append(MCMT(Unitary(i),2,1),[or_qubits[j-1],q,state_qubits]) circ.x(q) circ.cx(or_qubits[j - 1], q) circ.append(MCMT(Unitary(i), 1, 1), [q, state_qubits]) #QFT-dagger for qubit in range(int(t / 2)): circ.swap(qubit + t * j, t - qubit - 1 + t * j) for f in range(t, 0, -1): k = t - f for m in range(k): circ.cu1(-np.pi / float(2**(k - m)), t - m - 1 + t * j, t - k - 1 + t * j) circ.h(t - k - 1 + t * j) #Or Gate circ.x([ *register_qubits[t * j:t * (j + 1)], *or_qubits[(t - 1) * j:(t - 1) * (j + 1)] ]) circ.ccx(register_qubits[t * j], register_qubits[t * j + 1], or_qubits[(t - 1) * j]) for i in range(t - 2): circ.x(or_qubits[(t - 1) * j + i]) circ.ccx(or_qubits[(t - 1) * j + i], register_qubits[t * j + 2 + i], or_qubits[(t - 1) * j + i + 1]) #Scrambling gate circ.ch(or_qubits[(t - 1) * j + t - 2], state_qubits) #Pauli Measurements if measure_type == 'x': circ.h(state_qubits) elif measure_type == 'y': circ.sdg(state_qubits) circ.h(state_qubits) circ.measure(state_qubits, c) #IBMQ.load_account() #provider = IBMQ.get_provider('ibm-q') #qcomp = provider.get_backend('ibmq_qasm_simulator') qcomp = Aer.get_backend('qasm_simulator') shots = 8192 if noise_model is None: job = execute(circ, backend=qcomp, shots=shots) else: job = execute(circ, backend=qcomp, shots=shots, noise_model=noise_model, basis_gates=noise_model.basis_gates) #print(job_monitor(job)) result = job.result() result_dictionary = result.get_counts(circ) probs = {} for output in ['0', '1']: if output in result_dictionary: probs[output] = result_dictionary[output] else: probs[output] = 0 return (probs['0'] - probs['1']) / shots
def append_tk_command_to_qiskit( op: "Op", args: List["UnitID"], qcirc: QuantumCircuit, qregmap: Dict[str, QuantumRegister], cregmap: Dict[str, ClassicalRegister], symb_map: Dict[Parameter, sympy.Symbol], range_preds: Dict[Bit, Tuple[List["UnitID"], int]], ) -> Instruction: optype = op.type if optype == OpType.Measure: qubit = args[0] bit = args[1] qb = qregmap[qubit.reg_name][qubit.index[0]] b = cregmap[bit.reg_name][bit.index[0]] return qcirc.measure(qb, b) if optype == OpType.Reset: qb = qregmap[args[0].reg_name][args[0].index[0]] return qcirc.reset(qb) if optype in [ OpType.CircBox, OpType.ExpBox, OpType.PauliExpBox, OpType.Custom ]: subcircuit = op.get_circuit() subqc = tk_to_qiskit(subcircuit) qargs = [] cargs = [] for a in args: if a.type == UnitType.qubit: qargs.append(qregmap[a.reg_name][a.index[0]]) else: cargs.append(cregmap[a.reg_name][a.index[0]]) if optype == OpType.Custom: instruc = subqc.to_gate() instruc.name = op.get_name() else: instruc = subqc.to_instruction() return qcirc.append(instruc, qargs, cargs) if optype == OpType.Unitary2qBox: qargs = [qregmap[q.reg_name][q.index[0]] for q in args] u = op.get_matrix() g = UnitaryGate(u, label="u2q") return qcirc.append(g, qargs=qargs) if optype == OpType.Barrier: qargs = [qregmap[q.reg_name][q.index[0]] for q in args] g = Barrier(len(args)) return qcirc.append(g, qargs=qargs) if optype == OpType.RangePredicate: if op.lower != op.upper: raise NotImplementedError range_preds[args[-1]] = (args[:-1], op.lower) # attach predicate to bit, # subsequent conditional will handle it return Instruction("", 0, 0, []) if optype == OpType.ConditionalGate: if args[0] in range_preds: assert op.value == 1 condition_bits, value = range_preds[args[0]] del range_preds[args[0]] args = condition_bits + args[1:] width = len(condition_bits) else: width = op.width value = op.value regname = args[0].reg_name if len(cregmap[regname]) != width: raise NotImplementedError( "OpenQASM conditions must be an entire register") for i, a in enumerate(args[:width]): if a.reg_name != regname: raise NotImplementedError( "OpenQASM conditions can only use a single register") if a.index != [i]: raise NotImplementedError( "OpenQASM conditions must be an entire register in order") instruction = append_tk_command_to_qiskit(op.op, args[width:], qcirc, qregmap, cregmap, symb_map, range_preds) instruction.c_if(cregmap[regname], value) return instruction # normal gates qargs = [qregmap[q.reg_name][q.index[0]] for q in args] if optype == OpType.CnX: return qcirc.mcx(qargs[:-1], qargs[-1]) # special case if optype == OpType.CnRy: # might as well do a bit more checking assert len(op.params) == 1 alpha = param_to_qiskit(op.params[0], symb_map) assert len(qargs) >= 2 if len(qargs) == 2: # presumably more efficient; single control only new_gate = CRYGate(alpha) else: new_ry_gate = RYGate(alpha) new_gate = MCMT(gate=new_ry_gate, num_ctrl_qubits=len(qargs) - 1, num_target_qubits=1) qcirc.append(new_gate, qargs) return qcirc # others are direct translations try: gatetype = _known_qiskit_gate_rev[optype] except KeyError as error: raise NotImplementedError("Cannot convert tket Op to Qiskit gate: " + op.get_name()) from error params = [param_to_qiskit(p, symb_map) for p in op.params] g = gatetype(*params) return qcirc.append(g, qargs=qargs)