Exemplo n.º 1
0
def _swap_ops_from_edge(edge, state):
    """Generate list of ops to implement a SWAP gate along a coupling edge."""
    device_qreg = state.register
    qreg_edge = tuple(device_qreg[i] for i in edge)

    # TODO shouldn't be making other nodes not by the DAG!!
    return [DAGOpNode(op=SwapGate(), qargs=qreg_edge, cargs=())]
def _swap_ops_from_edge(edge, layout):
    """Generate list of ops to implement a SWAP gate along a coupling edge."""
    device_qreg = QuantumRegister(len(layout.get_physical_bits()), "q")
    qreg_edge = [device_qreg[i] for i in edge]

    # TODO shouldn't be making other nodes not by the DAG!!
    return [DAGOpNode(op=SwapGate(), qargs=qreg_edge, cargs=[])]
Exemplo n.º 3
0
def permutation_circuit(swaps: Iterable[List[Swap[_V]]]) -> PermutationCircuit:
    """Produce a circuit description of a list of swaps.
        With a given permutation and permuter you can compute the swaps using the permuter function
        then feed it into this circuit function to obtain a circuit description.
    Args:
      swaps: An iterable of swaps to perform.
    Returns:
      A MappingCircuit with the circuit and a mapping of node to qubit in the circuit.
    """
    # Construct a circuit with each unique node id becoming a quantum register of size 1.
    dag = DAGCircuit()
    swap_list = list(swaps)

    # Set of unique nodes used in the swaps.
    nodes = {
        swap_node
        for swap_step in swap_list for swap_nodes in swap_step
        for swap_node in swap_nodes
    }

    node_qargs = {node: QuantumRegister(1) for node in nodes}
    for qubit in node_qargs.values():
        dag.add_qreg(qubit)

    inputmap = {node: q[0] for node, q in node_qargs.items()}

    # Apply swaps to the circuit.
    for swap_step in swap_list:
        for swap0, swap1 in swap_step:
            dag.apply_operation_back(SwapGate(),
                                     [inputmap[swap0], inputmap[swap1]])

    return PermutationCircuit(dag, inputmap)
Exemplo n.º 4
0
 def _process_swaps(self, swap_map, node, mapped_dag, current_layout,
                    canonical_register):
     if node._node_id in swap_map:
         for swap in swap_map[node._node_id]:
             swap_qargs = [
                 canonical_register[swap[0]], canonical_register[swap[1]]
             ]
             self._apply_gate(
                 mapped_dag,
                 DAGOpNode(op=SwapGate(), qargs=swap_qargs),
                 current_layout,
                 canonical_register,
             )
             current_layout.swap_logical(*swap)
Exemplo n.º 5
0
    def _define(self):
        definition = []
        qr = QuantumRegister(self.num_qubits)

        for i in reversed(range(self.num_qubits)):
            definition.append((HGate(), [qr[i]], []))
            for j in range(i):
                definition.append(
                    (CU1Gate(np.pi / 2.0**(i - j)), [qr[j], qr[i]], []))

        if self.do_swaps:
            for i in range(self.num_qubits // 2):
                definition.append(
                    (SwapGate(), [qr[i], qr[self.num_qubits - 1 - i]], []))

        self.definition = definition
Exemplo n.º 6
0
def random_linear_circuit(num_qubits, num_gates, seed=None):
    """Generate a pseudo random linear circuit."""

    instructions = {
        "cx": (CXGate(), 2),
        "swap": (SwapGate(), 2),
    }

    if isinstance(seed, np.random.Generator):
        rng = seed
    else:
        rng = np.random.default_rng(seed)

    name_samples = rng.choice(tuple(instructions), num_gates)

    circ = QuantumCircuit(num_qubits)

    for name in name_samples:
        gate, nqargs = instructions[name]
        qargs = rng.choice(range(num_qubits), nqargs, replace=False).tolist()
        circ.append(gate, qargs)

    return circ
Exemplo n.º 7
0
    def _layer_permutation(self, layer_partition, layout, qubit_subset,
                           coupling, trials):
        """Find a swap circuit that implements a permutation for this layer.

        The goal is to swap qubits such that qubits in the same two-qubit gates
        are adjacent.

        Based on S. Bravyi's algorithm.

        Args:
            layer_partition (list): The layer_partition is a list of (qu)bit
                lists and each qubit is a tuple (qreg, index).
            layout (Layout): The layout is a Layout object mapping virtual
                qubits in the input circuit to physical qubits in the coupling
                graph. It reflects the current positions of the data.
            qubit_subset (list): The qubit_subset is the set of qubits in
                the coupling graph that we have chosen to map into, as tuples
                (Register, index).
            coupling (CouplingMap): Directed graph representing a coupling map.
                This coupling map should be one that was provided to the
                stochastic mapper.
            trials (int): Number of attempts the randomized algorithm makes.

        Returns:
            Tuple: success_flag, best_circuit, best_depth, best_layout

        If success_flag is True, then best_circuit contains a DAGCircuit with
        the swap circuit, best_depth contains the depth of the swap circuit,
        and best_layout contains the new positions of the data qubits after the
        swap circuit has been applied.

        Raises:
            TranspilerError: if anything went wrong.
        """
        logger.debug("layer_permutation: layer_partition = %s",
                     layer_partition)
        logger.debug("layer_permutation: layout = %s",
                     layout.get_virtual_bits())
        logger.debug("layer_permutation: qubit_subset = %s", qubit_subset)
        logger.debug("layer_permutation: trials = %s", trials)

        # The input dag is on a flat canonical register
        # TODO: cleanup the code that is general for multiple qregs below
        canonical_register = QuantumRegister(len(layout), 'q')
        qregs = OrderedDict({canonical_register.name: canonical_register})

        gates = []  # list of lists of tuples [[(register, index), ...], ...]
        for gate_args in layer_partition:
            if len(gate_args) > 2:
                raise TranspilerError("Layer contains > 2-qubit gates")
            if len(gate_args) == 2:
                gates.append(tuple(gate_args))
        logger.debug("layer_permutation: gates = %s", gates)

        # Can we already apply the gates? If so, there is no work to do.
        dist = sum(
            [coupling.distance(layout[g[0]], layout[g[1]]) for g in gates])
        logger.debug("layer_permutation: distance = %s", dist)
        if dist == len(gates):
            logger.debug("layer_permutation: nothing to do")
            circ = DAGCircuit()
            circ.add_qreg(canonical_register)
            return True, circ, 0, layout

        # Begin loop over trials of randomized algorithm
        num_qubits = len(layout)
        best_depth = inf  # initialize best depth
        best_edges = None  # best edges found
        best_circuit = None  # initialize best swap circuit
        best_layout = None  # initialize best final layout

        cdist2 = coupling._dist_matrix**2
        # Scaling matrix
        scale = np.zeros((num_qubits, num_qubits))

        int_qubit_subset = np.fromiter(
            (self._qubit_indices[bit] for bit in qubit_subset),
            dtype=np.int32,
            count=len(qubit_subset))

        int_gates = np.fromiter(
            (self._qubit_indices[bit] for gate in gates for bit in gate),
            dtype=np.int32,
            count=2 * len(gates))

        int_layout = nlayout_from_layout(layout, self._qubit_indices,
                                         num_qubits, coupling.size())

        trial_circuit = DAGCircuit(
        )  # SWAP circuit for slice of swaps in this trial
        trial_circuit.add_qubits(layout.get_virtual_bits())

        edges = np.asarray(coupling.get_edges(), dtype=np.int32).ravel()
        cdist = coupling._dist_matrix
        for trial in range(trials):
            logger.debug("layer_permutation: trial %s", trial)
            # This is one Trial --------------------------------------
            dist, optim_edges, trial_layout, depth_step = swap_trial(
                num_qubits, int_layout, int_qubit_subset, int_gates, cdist2,
                cdist, edges, scale, self.rng)

            logger.debug(
                "layer_permutation: final distance for this trial = %s", dist)
            if dist == len(gates) and depth_step < best_depth:
                logger.debug(
                    "layer_permutation: got circuit with improved depth %s",
                    depth_step)
                best_edges = optim_edges
                best_layout = trial_layout
                best_depth = min(best_depth, depth_step)

            # Break out of trial loop if we found a depth 1 circuit
            # since we can't improve it further
            if best_depth == 1:
                break

        # If we have no best circuit for this layer, all of the
        # trials have failed
        if best_layout is None:
            logger.debug("layer_permutation: failed!")
            return False, None, None, None

        edges = best_edges.edges()
        for idx in range(best_edges.size // 2):
            swap_src = self.trivial_layout[edges[2 * idx]]
            swap_tgt = self.trivial_layout[edges[2 * idx + 1]]
            trial_circuit.apply_operation_back(SwapGate(),
                                               [swap_src, swap_tgt], [])
        best_circuit = trial_circuit

        # Otherwise, we return our result for this layer
        logger.debug("layer_permutation: success!")
        best_lay = best_layout.to_layout(qregs)
        return True, best_circuit, best_depth, best_lay
Exemplo n.º 8
0
    def run(self, dag):
        """Run the SabreSwap pass on `dag`.

        Args:
            dag (DAGCircuit): the directed acyclic graph to be mapped.
        Returns:
            DAGCircuit: A dag mapped to be compatible with the coupling_map.
        Raises:
            TranspilerError: if the coupling map or the layout are not
            compatible with the DAG
        """
        if len(dag.qregs) != 1 or dag.qregs.get('q', None) is None:
            raise TranspilerError('Sabre swap runs on physical circuits only.')

        if len(dag.qubits) > self.coupling_map.size():
            raise TranspilerError('More virtual qubits exist than physical.')

        rng = np.random.default_rng(self.seed)

        # Preserve input DAG's name, regs, wire_map, etc. but replace the graph.
        mapped_dag = dag._copy_circuit_metadata()

        # Assume bidirectional couplings, fixing gate direction is easy later.
        self.coupling_map.make_symmetric()

        canonical_register = dag.qregs['q']
        current_layout = Layout.generate_trivial_layout(canonical_register)

        # A decay factor for each qubit used to heuristically penalize recently
        # used qubits (to encourage parallelism).
        self.qubits_decay = {qubit: 1 for qubit in dag.qubits}

        # Start algorithm from the front layer and iterate until all gates done.
        num_search_steps = 0
        front_layer = dag.front_layer()
        self.applied_gates = set()
        while front_layer:
            execute_gate_list = []

            # Remove as many immediately applicable gates as possible
            for node in front_layer:
                if len(node.qargs) == 2:
                    v0, v1 = node.qargs
                    physical_qubits = (current_layout[v0], current_layout[v1])
                    if physical_qubits in self.coupling_map.get_edges():
                        execute_gate_list.append(node)
                else:  # Single-qubit gates as well as barriers are free
                    execute_gate_list.append(node)

            if execute_gate_list:
                for node in execute_gate_list:
                    new_node = _transform_gate_for_layout(node, current_layout)
                    mapped_dag.apply_operation_back(new_node.op,
                                                    new_node.qargs,
                                                    new_node.cargs,
                                                    new_node.condition)
                    front_layer.remove(node)
                    self.applied_gates.add(node)
                    for successor in dag.quantum_successors(node):
                        if successor.type != 'op':
                            continue
                        if self._is_resolved(successor, dag):
                            front_layer.append(successor)

                    if node.qargs:
                        self._reset_qubits_decay()

                # Diagnostics
                logger.debug('free! %s',
                             [(n.name, n.qargs) for n in execute_gate_list])
                logger.debug('front_layer: %s',
                             [(n.name, n.qargs) for n in front_layer])

                continue

            # After all free gates are exhausted, heuristically find
            # the best swap and insert it. When two or more swaps tie
            # for best score, pick one randomly.
            extended_set = self._obtain_extended_set(dag, front_layer)
            swap_candidates = self._obtain_swaps(front_layer, current_layout)
            swap_scores = dict.fromkeys(swap_candidates, 0)
            for swap_qubits in swap_scores:
                trial_layout = current_layout.copy()
                trial_layout.swap(*swap_qubits)
                score = self._score_heuristic(self.heuristic, front_layer,
                                              extended_set, trial_layout,
                                              swap_qubits)
                swap_scores[swap_qubits] = score
            min_score = min(swap_scores.values())
            best_swaps = [k for k, v in swap_scores.items() if v == min_score]
            best_swaps.sort(key=lambda x: (x[0].index, x[1].index))
            best_swap = rng.choice(best_swaps)
            swap_node = DAGNode(op=SwapGate(), qargs=best_swap, type='op')
            swap_node = _transform_gate_for_layout(swap_node, current_layout)
            mapped_dag.apply_operation_back(swap_node.op, swap_node.qargs)
            current_layout.swap(*best_swap)

            num_search_steps += 1
            if num_search_steps % DECAY_RESET_INTERVAL == 0:
                self._reset_qubits_decay()
            else:
                self.qubits_decay[best_swap[0]] += DECAY_RATE
                self.qubits_decay[best_swap[1]] += DECAY_RATE

            # Diagnostics
            logger.debug('SWAP Selection...')
            logger.debug('extended_set: %s',
                         [(n.name, n.qargs) for n in extended_set])
            logger.debug('swap scores: %s', swap_scores)
            logger.debug('best swap: %s', best_swap)
            logger.debug('qubits decay: %s', self.qubits_decay)

        self.property_set['final_layout'] = current_layout

        return mapped_dag
    def run(self, dag):
        """Run the BIPMapping pass on `dag`, assuming the number of virtual qubits (defined in
        `dag`) and the number of physical qubits (defined in `coupling_map`) are the same.

        Args:
            dag (DAGCircuit): DAG to map.

        Returns:
            DAGCircuit: A mapped DAG. If there is no 2q-gate in DAG or it fails to map,
                returns the original dag.

        Raises:
            TranspilerError: if the number of virtual and physical qubits are not the same.
            AssertionError: if the final layout is not valid.
        """
        if self.coupling_map is None:
            return dag

        if len(dag.qubits) > len(self.qubit_subset):
            raise TranspilerError("More virtual qubits exist than physical qubits.")

        if len(dag.qubits) != len(self.qubit_subset):
            raise TranspilerError(
                "BIPMapping requires the number of virtual and physical qubits to be the same. "
                "Supply 'qubit_subset' to specify physical qubits to use."
            )

        original_dag = dag

        dummy_steps = math.ceil(math.sqrt(dag.num_qubits()))
        if self.max_swaps_inbetween_layers is not None:
            dummy_steps = max(0, self.max_swaps_inbetween_layers - 1)

        model = BIPMappingModel(
            dag=dag,
            coupling_map=self.coupling_map,
            qubit_subset=self.qubit_subset,
            dummy_timesteps=dummy_steps,
        )

        if len(model.su4layers) == 0:
            logger.info("BIPMapping is skipped due to no 2q-gates.")
            return original_dag

        model.create_cpx_problem(
            objective=self.objective,
            backend_prop=self.backend_prop,
            depth_obj_weight=self.depth_obj_weight,
            default_cx_error_rate=self.default_cx_error_rate,
        )

        status = model.solve_cpx_problem(time_limit=self.time_limit, threads=self.threads)
        if model.solution is None:
            logger.warning("Failed to solve a BIP problem. Status: %s", status)
            return original_dag

        # Get the optimized initial layout
        optimized_layout = model.get_layout(0)

        # Create a layout to track changes in layout for each layer
        layout = copy.deepcopy(optimized_layout)

        # Construct the mapped circuit
        canonical_qreg = QuantumRegister(self.coupling_map.size(), "q")
        mapped_dag = self._create_empty_dagcircuit(dag, canonical_qreg)
        interval = dummy_steps + 1
        for k, layer in enumerate(dag.layers()):
            if model.is_su4layer(k):
                su4dep = model.to_su4layer_depth(k)
                # add swaps between (su4dep-1)-th and su4dep-th su4layer
                from_steps = max(interval * (su4dep - 1), 0)
                to_steps = min(interval * su4dep, model.depth - 1)
                for t in range(from_steps, to_steps):  # pylint: disable=invalid-name
                    for (i, j) in model.get_swaps(t):
                        mapped_dag.apply_operation_back(
                            op=SwapGate(),
                            qargs=[canonical_qreg[i], canonical_qreg[j]],
                        )
                        # update layout, swapping physical qubits (i, j)
                        layout.swap(i, j)

            # map gates in k-th layer
            for node in layer["graph"].nodes():
                if isinstance(node, DAGOpNode):
                    mapped_dag.apply_operation_back(
                        op=copy.deepcopy(node.op),
                        qargs=[canonical_qreg[layout[q]] for q in node.qargs],
                        cargs=node.cargs,
                    )
                # TODO: double check with y values?

        # Check final layout
        final_layout = model.get_layout(model.depth - 1)
        if layout != final_layout:
            raise AssertionError(
                f"Bug: final layout {final_layout} != the layout computed from swaps {layout}"
            )

        self.property_set["layout"] = self._to_full_layout(optimized_layout)
        self.property_set["final_layout"] = self._to_full_layout(final_layout)

        return mapped_dag
Exemplo n.º 10
0
    def run(self, dag):
        """Run the SabreSwap pass on `dag`.

        Args:
            dag (DAGCircuit): the directed acyclic graph to be mapped.
        Returns:
            DAGCircuit: A dag mapped to be compatible with the coupling_map.
        Raises:
            TranspilerError: if the coupling map or the layout are not
            compatible with the DAG
        """
        if len(dag.qregs) != 1 or dag.qregs.get("q", None) is None:
            raise TranspilerError("Sabre swap runs on physical circuits only.")

        if len(dag.qubits) > self.coupling_map.size():
            raise TranspilerError("More virtual qubits exist than physical.")

        rng = np.random.default_rng(self.seed)

        # Preserve input DAG's name, regs, wire_map, etc. but replace the graph.
        mapped_dag = None
        if not self.fake_run:
            mapped_dag = dag._copy_circuit_metadata()

        canonical_register = dag.qregs["q"]
        current_layout = Layout.generate_trivial_layout(canonical_register)

        self._bit_indices = {
            bit: idx
            for idx, bit in enumerate(canonical_register)
        }

        # A decay factor for each qubit used to heuristically penalize recently
        # used qubits (to encourage parallelism).
        self.qubits_decay = {qubit: 1 for qubit in dag.qubits}

        # Start algorithm from the front layer and iterate until all gates done.
        num_search_steps = 0
        front_layer = dag.front_layer()
        self.applied_predecessors = defaultdict(int)
        for _, input_node in dag.input_map.items():
            for successor in self._successors(input_node, dag):
                self.applied_predecessors[successor] += 1
        while front_layer:
            execute_gate_list = []

            # Remove as many immediately applicable gates as possible
            for node in front_layer:
                if len(node.qargs) == 2:
                    v0, v1 = node.qargs
                    if self.coupling_map.graph.has_edge(
                            current_layout[v0], current_layout[v1]):
                        execute_gate_list.append(node)
                else:  # Single-qubit gates as well as barriers are free
                    execute_gate_list.append(node)

            if execute_gate_list:
                for node in execute_gate_list:
                    self._apply_gate(mapped_dag, node, current_layout,
                                     canonical_register)
                    front_layer.remove(node)
                    for successor in self._successors(node, dag):
                        self.applied_predecessors[successor] += 1
                        if self._is_resolved(successor):
                            front_layer.append(successor)

                    if node.qargs:
                        self._reset_qubits_decay()

                # Diagnostics
                logger.debug(
                    "free! %s",
                    [(n.name if isinstance(n, DAGOpNode) else None, n.qargs)
                     for n in execute_gate_list],
                )
                logger.debug(
                    "front_layer: %s",
                    [(n.name if isinstance(n, DAGOpNode) else None, n.qargs)
                     for n in front_layer],
                )

                continue

            # After all free gates are exhausted, heuristically find
            # the best swap and insert it. When two or more swaps tie
            # for best score, pick one randomly.
            extended_set = self._obtain_extended_set(dag, front_layer)
            swap_candidates = self._obtain_swaps(front_layer, current_layout)
            swap_scores = dict.fromkeys(swap_candidates, 0)
            for swap_qubits in swap_scores:
                trial_layout = current_layout.copy()
                trial_layout.swap(*swap_qubits)
                score = self._score_heuristic(self.heuristic, front_layer,
                                              extended_set, trial_layout,
                                              swap_qubits)
                swap_scores[swap_qubits] = score
            min_score = min(swap_scores.values())
            best_swaps = [k for k, v in swap_scores.items() if v == min_score]
            best_swaps.sort(key=lambda x:
                            (self._bit_indices[x[0]], self._bit_indices[x[1]]))
            best_swap = rng.choice(best_swaps)
            swap_node = DAGOpNode(op=SwapGate(), qargs=best_swap)
            self._apply_gate(mapped_dag, swap_node, current_layout,
                             canonical_register)
            current_layout.swap(*best_swap)

            num_search_steps += 1
            if num_search_steps % DECAY_RESET_INTERVAL == 0:
                self._reset_qubits_decay()
            else:
                self.qubits_decay[best_swap[0]] += DECAY_RATE
                self.qubits_decay[best_swap[1]] += DECAY_RATE

            # Diagnostics
            logger.debug("SWAP Selection...")
            logger.debug("extended_set: %s",
                         [(n.name, n.qargs) for n in extended_set])
            logger.debug("swap scores: %s", swap_scores)
            logger.debug("best swap: %s", best_swap)
            logger.debug("qubits decay: %s", self.qubits_decay)

        self.property_set["final_layout"] = current_layout

        if not self.fake_run:
            return mapped_dag
        return dag
Exemplo n.º 11
0
    def run(self, dag):
        """Run the BasicSwap pass on `dag`.

        Args:
            dag (DAGCircuit): DAG to map.

        Returns:
            DAGCircuit: A mapped DAG.

        Raises:
            TranspilerError: if the coupling map or the layout are not
            compatible with the DAG.
        """
        new_dag = DAGCircuit()
        for qreg in dag.qregs.values():
            new_dag.add_qreg(qreg)
        for creg in dag.cregs.values():
            new_dag.add_creg(creg)

        if len(dag.qregs) != 1 or dag.qregs.get('q', None) is None:
            raise TranspilerError('Basic swap runs on physical circuits only')

        if len(dag.qubits()) > len(self.coupling_map.physical_qubits):
            raise TranspilerError(
                'The layout does not match the amount of qubits in the DAG')

        canonical_register = dag.qregs['q']
        trivial_layout = Layout.generate_trivial_layout(canonical_register)
        current_layout = trivial_layout.copy()

        for layer in dag.serial_layers():
            subdag = layer['graph']

            for gate in subdag.two_qubit_ops():
                physical_q0 = current_layout[gate.qargs[0]]
                physical_q1 = current_layout[gate.qargs[1]]
                if self.coupling_map.distance(physical_q0, physical_q1) != 1:
                    # Insert a new layer with the SWAP(s).
                    swap_layer = DAGCircuit()
                    swap_layer.add_qreg(canonical_register)

                    path = self.coupling_map.shortest_undirected_path(
                        physical_q0, physical_q1)
                    for swap in range(len(path) - 2):
                        connected_wire_1 = path[swap]
                        connected_wire_2 = path[swap + 1]

                        qubit_1 = current_layout[connected_wire_1]
                        qubit_2 = current_layout[connected_wire_2]

                        # create the swap operation
                        swap_layer.apply_operation_back(
                            SwapGate(), qargs=[qubit_1, qubit_2], cargs=[])

                    # layer insertion
                    edge_map = current_layout.combine_into_edge_map(
                        trivial_layout)
                    new_dag.compose(swap_layer, edge_map)

                    # update current_layout
                    for swap in range(len(path) - 2):
                        current_layout.swap(path[swap], path[swap + 1])

            edge_map = current_layout.combine_into_edge_map(trivial_layout)
            new_dag.compose(subdag, edge_map)

        return new_dag
Exemplo n.º 12
0
    def run(self, dag):
        """Run the BasicSwap pass on `dag`.

        Args:
            dag (DAGCircuit): DAG to map.

        Returns:
            DAGCircuit: A mapped DAG.

        Raises:
            TranspilerError: if the coupling map or the layout are not
            compatible with the DAG.
        """
        if self.fake_run:
            return self.fake_run(dag)

        new_dag = dag.copy_empty_like()

        if len(dag.qregs) != 1 or dag.qregs.get("q", None) is None:
            raise TranspilerError("Basic swap runs on physical circuits only")

        if len(dag.qubits) > len(self.coupling_map.physical_qubits):
            raise TranspilerError(
                "The layout does not match the amount of qubits in the DAG")

        canonical_register = dag.qregs["q"]
        trivial_layout = Layout.generate_trivial_layout(canonical_register)
        current_layout = trivial_layout.copy()

        for layer in dag.serial_layers():
            subdag = layer["graph"]

            for gate in subdag.two_qubit_ops():
                physical_q0 = current_layout[gate.qargs[0]]
                physical_q1 = current_layout[gate.qargs[1]]
                if self.coupling_map.distance(physical_q0, physical_q1) != 1:
                    # Insert a new layer with the SWAP(s).
                    swap_layer = DAGCircuit()
                    swap_layer.add_qreg(canonical_register)

                    path = self.coupling_map.shortest_undirected_path(
                        physical_q0, physical_q1)
                    for swap in range(len(path) - 2):
                        connected_wire_1 = path[swap]
                        connected_wire_2 = path[swap + 1]

                        qubit_1 = current_layout[connected_wire_1]
                        qubit_2 = current_layout[connected_wire_2]

                        # create the swap operation
                        swap_layer.apply_operation_back(
                            SwapGate(), qargs=[qubit_1, qubit_2], cargs=[])

                    # layer insertion
                    order = current_layout.reorder_bits(new_dag.qubits)
                    new_dag.compose(swap_layer, qubits=order)

                    # update current_layout
                    for swap in range(len(path) - 2):
                        current_layout.swap(path[swap], path[swap + 1])

            order = current_layout.reorder_bits(new_dag.qubits)
            new_dag.compose(subdag, qubits=order)

        return new_dag
Exemplo n.º 13
0
def _standard_gate_instruction(instruction, ignore_phase=True):
    """Temporary function to create Instruction objects from a json string,
    which is necessary for creating a new QuantumError object from deprecated
    json-based input. Note that the type of returned object is different from
    the deprecated standard_gate_instruction.
    TODO: to be removed after deprecation period.

    Args:
        instruction (dict): A qobj instruction.
        ignore_phase (bool): Ignore global phase on unitary matrix in
                             comparison to canonical unitary.

    Returns:
        list: a list of (instructions, qubits) equivalent to in input instruction.
    """
    gate = {
        "id": IGate(),
        "x": XGate(),
        "y": YGate(),
        "z": ZGate(),
        "h": HGate(),
        "s": SGate(),
        "sdg": SdgGate(),
        "t": TGate(),
        "tdg": TdgGate(),
        "cx": CXGate(),
        "cz": CZGate(),
        "swap": SwapGate()
    }

    name = instruction.get("name", None)
    qubits = instruction["qubits"]
    if name in gate:
        return [(gate[name], qubits)]

    if name not in ["mat", "unitary", "kraus"]:
        return [instruction]

    params = instruction["params"]
    with warnings.catch_warnings():
        warnings.filterwarnings("ignore",
                                category=DeprecationWarning,
                                module="qiskit.providers.aer.noise.errors.errorutils")

        # Check for single-qubit reset Kraus
        if name == "kraus":
            if len(qubits) == 1:
                superop = SuperOp(Kraus(params))
                # Check if reset to |0>
                reset0 = reset_superop(1)
                if superop == reset0:
                    return [(Reset(), [0])]
                # Check if reset to |1>
                reset1 = reset0.compose(Operator(standard_gate_unitary('x')))
                if superop == reset1:
                    return [(Reset(), [0]), (XGate(), [0])]
            return [instruction]

        # Check single qubit gates
        mat = params[0]
        if len(qubits) == 1:
            # Check clifford gates
            for j in range(24):
                if matrix_equal(
                        mat,
                        single_qubit_clifford_matrix(j),
                        ignore_phase=ignore_phase):
                    return [(gate, [0]) for gate in _CLIFFORD_GATES[j]]
            # Check t gates
            for name in ["t", "tdg"]:
                if matrix_equal(
                        mat,
                        standard_gate_unitary(name),
                        ignore_phase=ignore_phase):
                    return [(gate[name], qubits)]
            # TODO: u1,u2,u3 decomposition
        # Check two qubit gates
        if len(qubits) == 2:
            for name in ["cx", "cz", "swap"]:
                if matrix_equal(
                        mat,
                        standard_gate_unitary(name),
                        ignore_phase=ignore_phase):
                    return [(gate[name], qubits)]
            # Check reversed CX
            if matrix_equal(
                    mat,
                    standard_gate_unitary("cx_10"),
                    ignore_phase=ignore_phase):
                return [(CXGate(), [qubits[1], qubits[0]])]
            # Check 2-qubit Pauli's
            paulis = ["id", "x", "y", "z"]
            for pauli0 in paulis:
                for pauli1 in paulis:
                    pmat = np.kron(
                        standard_gate_unitary(pauli1),
                        standard_gate_unitary(pauli0))
                    if matrix_equal(mat, pmat, ignore_phase=ignore_phase):
                        if pauli0 == "id":
                            return [(gate[pauli1], [qubits[1]])]
                        elif pauli1 == "id":
                            return [(gate[pauli0], [qubits[0]])]
                        else:
                            return [(gate[pauli0], [qubits[0]]), (gate[pauli1], [qubits[1]])]
        # Check three qubit toffoli
        if len(qubits) == 3:
            if matrix_equal(
                    mat,
                    standard_gate_unitary("ccx_012"),
                    ignore_phase=ignore_phase):
                return [(CCXGate(), qubits)]
            if matrix_equal(
                    mat,
                    standard_gate_unitary("ccx_021"),
                    ignore_phase=ignore_phase):
                return [(CCXGate(), [qubits[0], qubits[2], qubits[1]])]
            if matrix_equal(
                    mat,
                    standard_gate_unitary("ccx_120"),
                    ignore_phase=ignore_phase):
                return [(CCXGate(), [qubits[1], qubits[2], qubits[0]])]

    # Else return input in
    return [instruction]
Exemplo n.º 14
0
 def _mirrored_gate_fidelities(node):
     matrix = node.op.to_matrix()
     swap = SwapGate().to_matrix()
     targetm = TwoQubitWeylDecomposition(matrix @ swap)
     tracesm = two_qubit_cnot_decompose.traces(targetm)
     return [trace_to_fid(tracesm[i]) for i in range(4)]