def p_quantum_arg_register(self, p): """qarg : ID""" reg = p[1] if reg not in self.qregs.keys(): raise QasmException(f'Undefined quantum register "{reg}" at line {p.lineno(1)}') qubits = [] for idx in range(self.qregs[reg]): arg_name = self.make_name(idx, reg) if arg_name not in self.qubits.keys(): self.qubits[arg_name] = NamedQubit(arg_name) qubits.append(self.qubits[arg_name]) p[0] = qubits
def run(self, target, run_analyser=True): with tempfile.TemporaryDirectory() as tmpdirname: fname = os.path.join(tmpdirname, "target.qasm") target.save_to_qasm(fname, qreg_name="q") with open(fname) as file: qasm_data = file.read() optimised_circuit = circuit_from_qasm(qasm_data) start_time = timer() # Push Z gates toward the end of the circuit eject_z = cirq.optimizers.EjectZ() eject_z.optimize_circuit(optimised_circuit) # Push X, Y, and PhasedXPow gates toward the end of the circuit eject_paulis = cirq.optimizers.EjectPhasedPaulis() eject_paulis.optimize_circuit(optimised_circuit) # Merge single qubit gates into PhasedX and PhasedZ gates cirq.merge_single_qubit_gates_into_phased_x_z(optimised_circuit) # drop negligible gates drop_neg = cirq.optimizers.DropNegligible() drop_neg.optimize_circuit(optimised_circuit) # drop empty moments drop_empty = cirq.optimizers.DropEmptyMoments() drop_empty.optimize_circuit(optimised_circuit) self.execution_time = timer() - start_time qubit_order = { NamedQubit(f'q_{n}'): NamedQubit(f'q_{n}') for n in range(target.quantum_hardware.num_qubits) } qasm_data = optimised_circuit.to_qasm(qubit_order=qubit_order) lines = qasm_data.split("\n") gate_chain = GateChain.from_qasm_list_of_lines(lines, quantum_hardware=None) if run_analyser: self.analyse(target, gate_chain) self.analyser_report["Execution Time"] = self.execution_time return gate_chain
def p_quantum_arg_bit(self, p): """qarg : ID '[' NATURAL_NUMBER ']' """ reg = p[1] idx = p[3] arg_name = self.make_name(idx, reg) if reg not in self.qregs.keys(): raise QasmException('Undefined quantum register "{}" ' 'at line {}'.format(reg, p.lineno(1))) size = self.qregs[reg] if idx >= size: raise QasmException('Out of bounds qubit index {} ' 'on register {} of size {} ' 'at line {}'.format(idx, reg, size, p.lineno(1))) if arg_name not in self.qubits.keys(): self.qubits[arg_name] = NamedQubit(arg_name) p[0] = [self.qubits[arg_name]]
def run(self, target, run_analyser=True): with tempfile.TemporaryDirectory() as tmpdirname: fname = os.path.join(tmpdirname, "target.qasm") target.save_to_qasm(fname, qreg_name="q") with open(fname) as file: qasm_data = file.read() original_circuit = circuit_from_qasm(qasm_data) start_time = timer() # only 'greedy' routing is implemented in Cirq swap_networks: List[ccr.SwapNetwork] = [] routing_attempts = 1 with suppress(KeyError): routing_attempts = self._cfg["routing_attempts"] for _ in range(routing_attempts): swap_network = ccr.route_circuit(original_circuit, self.cirq_hardware, router=None, algo_name="greedy") swap_networks.append(swap_network) assert len(swap_networks) > 0, "Unable to get routing for circuit" # Sort by the least number of qubits first (as routing sometimes adds extra ancilla qubits), # and then the length of the circuit second. swap_networks.sort(key=lambda swap_network: (len( swap_network.circuit.all_qubits()), len(swap_network.circuit))) routed_circuit = swap_networks[0].circuit qubit_order = { LineQubit(n): NamedQubit(f"q_{n}") for n in range(self.quantum_hardware.num_qubits) } # decompose composite gates no_decomp = lambda op: isinstance(op.gate, CNotPowGate) opt = ExpandComposite(no_decomp=no_decomp) opt.optimize_circuit(routed_circuit) self.execution_time = timer() - start_time qasm_data = routed_circuit.to_qasm(qubit_order=qubit_order) lines = qasm_data.split("\n") gate_chain = GateChain.from_qasm_list_of_lines(lines, quantum_hardware=None) if run_analyser: self.analyse(target, gate_chain) self.analyser_report["Execution Time"] = self.execution_time return gate_chain
def rand_circuit_zne( n_qubits: int, depth: int, trials: int, noise: float, fac: Optional[Factory] = None, scale_noise: Callable[[QPROGRAM, float], QPROGRAM] = fold_gates_at_random, op_density: float = 0.99, silent: bool = True, seed: Optional[int] = None, ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: """Benchmarks a zero-noise extrapolation method and noise scaling executor by running on randomly sampled quantum circuits. Args: n_qubits: The number of qubits. depth: The depth in moments of the random circuits. trials: The number of random circuits to average over. noise: The noise level of the depolarizing channel for simulation. fac: The Factory giving the extrapolation method. scale_noise: The method for scaling noise, e.g. fold_gates_at_random op_density: The expected proportion of qubits that are acted on in any moment. silent: If False will print out statements every tenth trial to track progress. seed: Optional seed for random number generator. Returns: The triple (exacts, unmitigateds, mitigateds) where each is a list whose values are the expectations of that trial in noiseless, noisy, and error-mitigated runs respectively. """ exacts = [] unmitigateds = [] mitigateds = [] qubits = [NamedQubit(str(xx)) for xx in range(n_qubits)] if seed: rnd_state = np.random.RandomState(seed) else: rnd_state = None for ii in range(trials): if not silent and ii % 10 == 0: print(ii) qc = random_circuit( qubits, n_moments=depth, op_density=op_density, random_state=rnd_state, ) wvf = qc.final_state_vector() # calculate the exact obs = sample_projector(n_qubits, seed=rnd_state) exact = np.conj(wvf).T @ obs @ wvf # make sure it is real exact = np.real_if_close(exact) assert np.isreal(exact) # create the simulation type def obs_sim(circ: Circuit) -> float: # we only want the expectation value not the variance # this is why we return [0] return noisy_simulation(circ, noise, obs) # evaluate the noisy answer unmitigated = obs_sim(qc) # evaluate the ZNE answer mitigated = execute_with_zne( qp=qc, executor=obs_sim, scale_noise=scale_noise, factory=fac ) exacts.append(exact) unmitigateds.append(unmitigated) mitigateds.append(mitigated) return np.asarray(exacts), np.asarray(unmitigateds), np.asarray(mitigateds)
def make_maxcut( graph: List[Tuple[int, int]], noise: float = 0, scale_noise: Optional[Callable[[QPROGRAM, float], QPROGRAM]] = None, factory: Optional[Factory] = None, ) -> Tuple[ Callable[[np.ndarray], float], Callable[[np.ndarray], Circuit], np.ndarray ]: """Makes an executor that evaluates the QAOA ansatz at a given beta and gamma parameters. Args: graph: The MAXCUT graph as a list of edges with integer labelled nodes. noise: The level of depolarizing noise. scale_noise: The noise scaling method for ZNE. factory: The factory to use for ZNE. Returns: (ansatz_eval, ansatz_maker, cost_obs) as a triple. Here ansatz_eval: function that evalutes the maxcut ansatz on the noisy cirq backend. ansatz_maker: function that returns an ansatz circuit. cost_obs: the cost observable as a dense matrix. """ # get the list of unique nodes from the list of edges nodes = list({node for edge in graph for node in edge}) nodes = list(range(max(nodes) + 1)) # one qubit per node qreg = [NamedQubit(str(nn)) for nn in nodes] def cost_step(beta: float) -> Circuit: return Circuit(ZZ(qreg[u], qreg[v]) ** (beta) for u, v in graph) def mix_step(gamma: float) -> Circuit: return Circuit(X(qq) ** gamma for qq in qreg) init_state_prog = Circuit(H.on_each(qreg)) def qaoa_ansatz(params: np.ndarray) -> Circuit: half = int(len(params) / 2) betas, gammas = params[:half], params[half:] qaoa_steps = sum( [ cost_step(beta) + mix_step(gamma) for beta, gamma in zip(betas, gammas) ], Circuit(), ) return init_state_prog + qaoa_steps # make the cost observable identity = np.eye(2 ** len(nodes)) cost_mat = -0.5 * sum( identity - Circuit([id(*qreg), ZZ(qreg[i], qreg[j])]).unitary() for i, j in graph ) noisy_backend = make_noisy_backend(noise, cost_mat) # must have this function signature to work with scipy minimize def qaoa_cost(params: np.ndarray) -> float: qaoa_prog = qaoa_ansatz(params) if scale_noise is None and factory is None: return noisy_backend(qaoa_prog) else: assert scale_noise is not None return execute_with_zne( qaoa_prog, executor=noisy_backend, scale_noise=scale_noise, factory=factory, ) return qaoa_cost, qaoa_ansatz, cost_mat
tdg q[2]; cx q[0], q[2]; t q[2]; cx q[1], q[2]; tdg q[2]; cx q[0], q[2]; t q[1]; t q[2]; cx q[0], q[1]; h q[2]; t q[0]; tdg q[1]; cx q[0], q[1];""") device_graph = networkx.Graph() device_graph.add_nodes_from([NamedQubit(f'q_{i}') for i in range(5)]) device_graph.add_edge(NamedQubit('q_0'), NamedQubit('q_1')) device_graph.add_edge(NamedQubit('q_1'), NamedQubit('q_2')) device_graph.add_edge(NamedQubit('q_1'), NamedQubit('q_3')) device_graph.add_edge(NamedQubit('q_3'), NamedQubit('q_4')) def test_olsq_depth_normal(): lsqc_solver = OLSQ_cirq("depth", "normal") lsqc_solver.setdevicegraph(device_graph) lsqc_solver.setprogram(circuit) assert lsqc_solver.solve()[2] == 14 def test_olsq_swap_normal(): lsqc_solver = OLSQ_cirq("swap", "normal") lsqc_solver.setdevicegraph(device_graph) lsqc_solver.setprogram(circuit)