Ejemplo n.º 1
0
 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
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
 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]]
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
                               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)