Beispiel #1
0
def _resolve_gate(gate):
    """Resolve the given pyquil Gate as far as possible.

    For example, the gate ``CONTROLLED CONTROLLED X`` will be resolved to ``CCNOT``.
    The gate ``CONTROLLED CONTROLLED RX(0.3)`` will be resolved to ``CONTROLLED CRX(0.3)``.

    Args:
        gate (pyquil.quil.Gate): The gate that should be resolved

    Returns:
        pyquil.quil.Gate: The maximally resolved gate
    """
    for i, modifier in enumerate(gate.modifiers):
        if modifier == "CONTROLLED":
            if gate.name in _control_map:
                stripped_gate = Gate(_control_map[gate.name], gate.params,
                                     gate.qubits)
                stripped_gate.modifiers = gate.modifiers.copy()
                del stripped_gate.modifiers[i]

                return _resolve_gate(stripped_gate)
            else:
                break

    return gate
Beispiel #2
0
def test_def_circuit():
    defcircuit = """
DEFCIRCUIT bell a b:
    H a
    CNOT a b
""".strip()
    gate = "bell 0 1"

    defcircuit_no_qubits = """
DEFCIRCUIT bell:
    H 0
    CNOT 0 1
""".strip()
    gate_no_qubits = "bell"

    defcircuit_param = """
DEFCIRCUIT parameterized(%theta, %phi) a:
    RX(%theta) a
    RZ(%phi) a
""".strip()
    gate_param = "parameterized(0.0, 1.0) 0"

    parse_equals(defcircuit + "\n" + gate, RawInstr(defcircuit),
                 Gate("bell", [], [Qubit(0), Qubit(1)]))
    parse_equals(
        defcircuit_no_qubits + "\n" + gate_no_qubits,
        RawInstr(defcircuit_no_qubits),
        RawInstr(gate_no_qubits),
    )
    parse_equals(
        defcircuit_param + "\n" + gate_param,
        RawInstr(defcircuit_param),
        Gate("parameterized", [0.0, 1.0], [Qubit(0)]),
    )
Beispiel #3
0
    def is_gate_executable(self, gate: Gate, qubit_mapping: dict) -> bool:
        """Determines if a 2 qubut gate is executable, i.e., whether the gate acts on qubits which are connected in
        the coupling graph

        Args:
            gate (Gate): input 2 qubit gate
            qubit_mapping (dict): logical to physical qubit mapping

        Returns:
            bool: True if the input gate acts on connected qubits. False otherwise
        """
        gate_qubits = list(gate.get_qubits())
        logical_qubit_1, logical_qubit_2 = gate_qubits[0], gate_qubits[1]
        physical_qubit_1, physical_qubit_2 = qubit_mapping.get(
            logical_qubit_1), qubit_mapping.get(logical_qubit_2)
        return self.coupling_graph.has_edge(physical_qubit_1, physical_qubit_2)
Beispiel #4
0
    def update_decay_parameter(self, min_score_swap_gate: Gate,
                               decay_parameter: list) -> list:
        """Updates decay parameters for qubits on which SWAP gate with the minimum heuristic score is applied

        Args:
            min_score_swap_gate (Gate): SWAP gate with the minimum heuristic score
            decay_parameter (list): decay parameter list to be updated

        Returns:
            list: updated decay parameter list
        """
        min_score_swap_qubits = list(min_score_swap_gate.get_qubits())
        decay_parameter[min_score_swap_qubits[0]] = decay_parameter[
            min_score_swap_qubits[0]] + 0.001
        decay_parameter[min_score_swap_qubits[1]] = decay_parameter[
            min_score_swap_qubits[1]] + 0.001
        return decay_parameter
Beispiel #5
0
    def update_initial_mapping(self, swap_gate: Gate,
                               qubit_mapping: dict) -> dict:
        """Update qubit mapping between logical and physical if a SWAP gate is inserted in the program

        Args:
            swap_gate (Gate): a pyquil SWAP gate
            qubit_mapping (dict): a dictionary containing logical to physical qubit mapping

        Returns:
            dict: updated qubit mapping
        """
        temp_mapping = qubit_mapping.copy()
        swap_qubits = list(swap_gate.get_qubits())
        p_qubit_1, p_qubit_2 = qubit_mapping.get(
            swap_qubits[0]), qubit_mapping.get(swap_qubits[1])
        p_qubit_1, p_qubit_2 = p_qubit_2, p_qubit_1
        temp_mapping.update({
            swap_qubits[0]: p_qubit_1,
            swap_qubits[1]: p_qubit_2
        })
        return temp_mapping
Beispiel #6
0
    def gate(self, modifiers, name, params, qubits):
        # TODO Don't like this.
        modifiers = modifiers or []
        params = params or []

        # Some gate modifiers increase the arity of the base gate. The
        # new qubit arguments prefix the old ones.
        modifier_qubits = []
        for m in modifiers:
            if m in ["CONTROLLED", "FORKED"]:
                modifier_qubits.append(qubits[len(modifier_qubits)])

        base_qubits = qubits[len(modifier_qubits):]
        forked_offset = len(params) >> modifiers.count("FORKED")
        base_params = params[:forked_offset]

        if name in QUANTUM_GATES:
            if base_params:
                gate = QUANTUM_GATES[name](*base_params, *base_qubits)
            else:
                gate = QUANTUM_GATES[name](*base_qubits)
        else:
            gate = Gate(name, base_params, base_qubits)

        for modifier in modifiers[::-1]:
            if modifier == "CONTROLLED":
                gate.controlled(modifier_qubits.pop())
            elif modifier == "DAGGER":
                gate.dagger()
            elif modifier == "FORKED":
                gate.forked(modifier_qubits.pop(),
                            params[forked_offset:(2 * forked_offset)])
                forked_offset *= 2
            else:
                raise ValueError(f"Unsupported gate modifier {modifier}.")

        return gate
Beispiel #7
0
def heuristic_function(F: list, circuit_dag: DiGraph, initial_mapping: dict,
                       distance_matrix: np.matrix, swap_gate: Gate,
                       decay_parameter: list) -> float:
    """Computes a heuristic cost function that is used to rate a candidate SWAP to determine whether the SWAP gate can be inserted in a program to resolve
        qubit dependencies

    Args:
        F (list): list of gates that have no unexecuted predecessors in the DAG
        circuit_dag (DiGraph): a directed acyclic graph representing qubit dependencies between
                                gates
        initial_mapping (dict): a dictionary containing logical to physical qubit mapping
        distance_matrix (np.matrix): represents qubit connections from given coupling graph
        swap_gate (Gate): candidate SWAP gate
        decay_parameter (list): decay parameters for each logical qubit in the mapping

    Returns:
        float: heuristic score for the candidate SWAP gate
    """
    E = create_extended_successor_set(F, circuit_dag)
    min_score_swap_qubits = list(swap_gate.get_qubits())
    size_E = len(E)
    size_F = len(F)
    W = 0.5
    max_decay = max(decay_parameter[min_score_swap_qubits[0]],
                    decay_parameter[min_score_swap_qubits[1]])
    f_distance = 0
    e_distance = 0
    for gate_details in F:
        f_distance += calculate_distance(gate_details, distance_matrix,
                                         initial_mapping)

    for gate_details in E:
        e_distance += calculate_distance(gate_details, distance_matrix,
                                         initial_mapping)

    f_distance = f_distance / size_F
    e_distance = W * (e_distance / size_E)
    H = max_decay * (f_distance + e_distance)
    return H
Beispiel #8
0
def test_parameters():
    parse_equals("RX(123) 0", RX(123, 0))
    parse_equals("CPHASE00(0) 0 1", CPHASE00(0, 0, 1))
    parse_equals("A(8,9) 0", Gate("A", [8, 9], [Qubit(0)]))
    parse_equals("A(8, 9) 0", Gate("A", [8, 9], [Qubit(0)]))
Beispiel #9
0
def test_simple_gate():
    parse_equals("A 0", Gate("A", [], [Qubit(0)]))
    parse_equals("A 1 10 100",
                 Gate("A", [],
                      [Qubit(1), Qubit(10), Qubit(100)]))