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
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)]), )
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)
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
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
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
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
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)]))
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)]))