Beispiel #1
0
    def run(self, dag: DAGCircuit) -> DAGCircuit:
        """Run the Decompose pass on `dag`.

        Args:
            dag: input dag.

        Returns:
            output dag where ``gate`` was expanded.
        """
        # Walk through the DAG and expand each non-basis node
        for node in dag.op_nodes(self.gate):
            # opaque or built-in gates are not decomposable
            if not node.op.definition:
                continue
            if node.op.definition.global_phase:
                dag.global_phase += node.op.definition.global_phase
            # TODO: allow choosing among multiple decomposition rules
            rule = node.op.definition.data

            if len(rule) == 1 and len(node.qargs) == len(rule[0][1]) == 1:
                dag.substitute_node(node, rule[0][0], inplace=True)
            else:
                decomposition = circuit_to_dag(node.op.definition)
                dag.substitute_node_with_dag(node, decomposition)
        return dag
    def run(self, dag: DAGCircuit) -> DAGCircuit:
        """Run the Decompose pass on `dag`.

        Args:
            dag: input dag.

        Returns:
            output dag where ``gate`` was expanded.
        """
        # Walk through the DAG and expand each non-basis node
        for node in dag.op_nodes():
            if self._should_decompose(node):
                if getattr(node.op, "definition", None) is None:
                    continue
                # TODO: allow choosing among multiple decomposition rules
                rule = node.op.definition.data
                if len(rule) == 1 and len(node.qargs) == len(
                        rule[0].qubits) == 1:
                    if node.op.definition.global_phase:
                        dag.global_phase += node.op.definition.global_phase
                    dag.substitute_node(node, rule[0].operation, inplace=True)
                else:
                    decomposition = circuit_to_dag(node.op.definition)
                    dag.substitute_node_with_dag(node, decomposition)

        return dag
Beispiel #3
0
    def run(self, dag: DAGCircuit) -> DAGCircuit:
        """Run the UnitarySynthesis pass on `dag`.

        Args:
            dag: input dag.

        Returns:
            Output dag with UnitaryGates synthesized to target basis.
        """
        for node in dag.nodes():
            if node.type != 'op':
                continue  # skip all nodes that do not represent operations

            if not node.op.num_qubits == 1:
                continue  # ignore all non-single qubit gates, possible raise error here?

            matrix = node.op.to_matrix()

            # call solovay kitaev
            approximation = self._sk.run(matrix, self._recursion_degree)

            # convert to a dag and replace the gate by the approximation
            substitute = circuit_to_dag(approximation)
            dag.substitute_node_with_dag(node, substitute)

        return dag
Beispiel #4
0
    def run(self, dag: DAGCircuit) -> DAGCircuit:
        """Run the Decompose pass on `dag`.

        Args:
            dag: input dag.

        Returns:
            output dag where ``gate`` was expanded.
        """
        # Walk through the DAG and expand each non-basis node
        for node in dag.op_nodes(self.gate):
            # opaque or built-in gates are not decomposable
            if not node.op.definition:
                continue
            # TODO: allow choosing among multiple decomposition rules
            rule = node.op.definition

            if len(rule) == 1 and len(node.qargs) == len(rule[0][1]):
                dag.substitute_node(node, rule[0][0], inplace=True)
            else:
                # hacky way to build a dag on the same register as the rule is defined
                # TODO: need anonymous rules to address wires by index
                decomposition = DAGCircuit()
                qregs = {qb.register for inst in rule for qb in inst[1]}
                cregs = {cb.register for inst in rule for cb in inst[2]}
                for qreg in qregs:
                    decomposition.add_qreg(qreg)
                for creg in cregs:
                    decomposition.add_creg(creg)
                for inst in rule:
                    decomposition.apply_operation_back(*inst)
                dag.substitute_node_with_dag(node, decomposition)
        return dag
    def run(self, dag: DAGCircuit) -> DAGCircuit:
        """Run the UnitarySynthesis pass on `dag`.

        Args:
            dag: input dag.

        Returns:
            Output dag with UnitaryGates synthesized to target basis.

        Raises:
            TranspilerError:
                1. pulse_optimize is True but pulse optimal decomposition is not known
                   for requested basis.
                2. pulse_optimize is True and natural_direction is True but a preferred
                   gate direction can't be determined from the coupling map or the
                   relative gate lengths.
        """

        euler_basis = _choose_euler_basis(self._basis_gates)
        kak_gate = _choose_kak_gate(self._basis_gates)
        decomposer1q, decomposer2q = None, None
        if euler_basis is not None:
            decomposer1q = one_qubit_decompose.OneQubitEulerDecomposer(
                euler_basis)
        if kak_gate is not None:
            decomposer2q = TwoQubitBasisDecomposer(
                kak_gate,
                euler_basis=euler_basis,
                pulse_optimize=self._pulse_optimize)

        for node in dag.named_nodes(*self._synth_gates):
            if self._basis_gates and node.name in self._basis_gates:
                continue
            synth_dag = None
            wires = None
            if len(node.qargs) == 1:
                if decomposer1q is None:
                    continue
                synth_dag = circuit_to_dag(
                    decomposer1q._decompose(node.op.to_matrix()))
            elif len(node.qargs) == 2:
                if decomposer2q is None:
                    continue
                synth_dag, wires = self._synth_natural_direction(
                    node, dag, decomposer2q)
            else:
                synth_dag = circuit_to_dag(
                    isometry.Isometry(node.op.to_matrix(), 0, 0).definition)

            dag.substitute_node_with_dag(node, synth_dag, wires=wires)

        return dag
Beispiel #6
0
    def run(self, dag: DAGCircuit) -> DAGCircuit:
        """Run the HighLevelSynthesis pass on `dag`.
        Args:
            dag: input dag.
        Returns:
            Output dag with high level objects synthesized.
        """

        for node in dag.named_nodes("clifford"):
            decomposition = circuit_to_dag(decompose_clifford(node.op))
            dag.substitute_node_with_dag(node, decomposition)

        return dag
    def run(self, dag: DAGCircuit) -> DAGCircuit:
        """Run the LinearFunctionsSynthesis pass on `dag`.
        Args:
            dag: input dag.
        Returns:
            Output dag with LinearFunctions synthesized.
        """

        for node in dag.named_nodes("linear_function"):
            decomposition = circuit_to_dag(node.op.definition)
            dag.substitute_node_with_dag(node, decomposition)

        return dag
Beispiel #8
0
    def run(self, dag: DAGCircuit) -> DAGCircuit:
        """Run the UnitarySynthesis pass on `dag`.

        Args:
            dag: input dag.

        Returns:
            Output dag with UnitaryGates synthesized to target basis.
        """
        euler_basis = _choose_euler_basis(self._basis_gates)
        kak_gate = _choose_kak_gate(self._basis_gates)

        decomposer1q, decomposer2q = None, None
        if euler_basis is not None:
            decomposer1q = one_qubit_decompose.OneQubitEulerDecomposer(
                euler_basis)
        if kak_gate is not None:
            decomposer2q = TwoQubitBasisDecomposer(kak_gate,
                                                   euler_basis=euler_basis)

        for node in dag.named_nodes("unitary"):

            synth_dag = None
            if len(node.qargs) == 1:
                if decomposer1q is None:
                    continue
                synth_dag = circuit_to_dag(
                    decomposer1q._decompose(node.op.to_matrix()))
            elif len(node.qargs) == 2:
                if decomposer2q is None:
                    continue
                synth_dag = circuit_to_dag(
                    decomposer2q(node.op.to_matrix(),
                                 basis_fidelity=self._approximation_degree))
            else:
                synth_dag = circuit_to_dag(
                    isometry.Isometry(node.op.to_matrix(), 0, 0).definition)

            dag.substitute_node_with_dag(node, synth_dag)

        return dag
    def run(self, dag: DAGCircuit) -> DAGCircuit:
        """Run the UnitarySynthesis pass on `dag`.

        Args:
            dag: input dag.

        Returns:
            Output dag with UnitaryGates synthesized to target basis.

        Raises:
            TranspilerError: if a 'method' was specified for the class and is not
                found in the installed plugins list. The list of installed
                plugins can be queried with
                :func:`~qiskit.transpiler.passes.synthesis.plugin.unitary_synthesis_plugin_names`
        """
        if self.method not in self.plugins.ext_plugins:
            raise TranspilerError(
                "Specified method: %s not found in plugin list" % self.method)
        default_method = self.plugins.ext_plugins["default"].obj
        plugin_method = self.plugins.ext_plugins[self.method].obj
        if plugin_method.supports_coupling_map:
            dag_bit_indices = {bit: idx for idx, bit in enumerate(dag.qubits)}
        kwargs = {}
        if plugin_method.supports_basis_gates:
            kwargs["basis_gates"] = self._basis_gates
        if plugin_method.supports_natural_direction:
            kwargs["natural_direction"] = self._natural_direction
        if plugin_method.supports_pulse_optimize:
            kwargs["pulse_optimize"] = self._pulse_optimize
        if plugin_method.supports_gate_lengths:
            kwargs["gate_lengths"] = _build_gate_lengths(self._backend_props)
        if plugin_method.supports_gate_errors:
            kwargs["gate_errors"] = _build_gate_errors(self._backend_props)
        supported_bases = plugin_method.supported_bases
        if supported_bases is not None:
            kwargs["matched_basis"] = _choose_bases(self._basis_gates,
                                                    supported_bases)

        # Handle approximation degree as a special case for backwards compatibility, it's
        # not part of the plugin interface and only something needed for the default
        # pass.
        default_method._approximation_degree = self._approximation_degree
        if self.method == "default":
            plugin_method._approximation_degree = self._approximation_degree

        for node in dag.named_nodes(*self._synth_gates):
            if self._min_qubits is not None and len(
                    node.qargs) < self._min_qubits:
                continue
            if plugin_method.supports_coupling_map:
                kwargs["coupling_map"] = (
                    self._coupling_map,
                    [dag_bit_indices[x] for x in node.qargs],
                )
            synth_dag = None
            unitary = node.op.to_matrix()
            n_qubits = len(node.qargs)
            if (plugin_method.max_qubits is not None
                    and n_qubits > plugin_method.max_qubits) or (
                        plugin_method.min_qubits is not None
                        and n_qubits < plugin_method.min_qubits):
                synth_dag = default_method.run(unitary, **kwargs)
            else:
                synth_dag = plugin_method.run(unitary, **kwargs)
            if synth_dag is not None:
                if isinstance(synth_dag, tuple):
                    dag.substitute_node_with_dag(node,
                                                 synth_dag[0],
                                                 wires=synth_dag[1])
                else:
                    dag.substitute_node_with_dag(node, synth_dag)
        return dag
    def run(self, dag: DAGCircuit) -> DAGCircuit:
        """Run the UnitarySynthesis pass on `dag`.

        Args:
            dag: input dag.

        Returns:
            Output dag with UnitaryGates synthesized to target basis.

        Raises:
            TranspilerError: if a 'method' was specified for the class and is not
                found in the installed plugins list. The list of installed
                plugins can be queried with
                :func:`~qiskit.transpiler.passes.synthesis.plugin.unitary_synthesis_plugin_names`
        """
        if self.method not in self.plugins.ext_plugins:
            raise TranspilerError(
                "Specified method: %s not found in plugin list" % self.method)
        # Return fast if we have no synth gates (ie user specified an empty
        # list or the synth gates are all in the basis
        if not self._synth_gates:
            return dag

        plugin_method = self.plugins.ext_plugins[self.method].obj
        plugin_kwargs = {"config": self._plugin_config}
        _gate_lengths = _gate_errors = None
        dag_bit_indices = {}

        if self.method == "default":
            # If the method is the default, we only need to evaluate one set of keyword arguments.
            # To simplify later logic, and avoid cases where static analysis might complain that we
            # haven't initialised the "default" handler, we rebind the names so they point to the
            # same object as the chosen method.
            default_method = plugin_method
            default_kwargs = plugin_kwargs
            method_list = [(plugin_method, plugin_kwargs)]
        else:
            # If the method is not the default, we still need to initialise the default plugin's
            # keyword arguments in case we have to fall back on it during the actual run.
            default_method = self.plugins.ext_plugins["default"].obj
            default_kwargs = {}
            method_list = [(plugin_method, plugin_kwargs),
                           (default_method, default_kwargs)]

        for method, kwargs in method_list:
            if method.supports_basis_gates:
                kwargs["basis_gates"] = self._basis_gates
            if method.supports_coupling_map:
                dag_bit_indices = dag_bit_indices or {
                    bit: i
                    for i, bit in enumerate(dag.qubits)
                }
            if method.supports_natural_direction:
                kwargs["natural_direction"] = self._natural_direction
            if method.supports_pulse_optimize:
                kwargs["pulse_optimize"] = self._pulse_optimize
            if method.supports_gate_lengths:
                _gate_lengths = _gate_lengths or _build_gate_lengths(
                    self._backend_props, self._target)
                kwargs["gate_lengths"] = _gate_lengths
            if method.supports_gate_errors:
                _gate_errors = _gate_errors or _build_gate_errors(
                    self._backend_props, self._target)
                kwargs["gate_errors"] = _gate_errors
            supported_bases = method.supported_bases
            if supported_bases is not None:
                kwargs["matched_basis"] = _choose_bases(
                    self._basis_gates, supported_bases)
            if method.supports_target:
                kwargs["target"] = self._target

        # Handle approximation degree as a special case for backwards compatibility, it's
        # not part of the plugin interface and only something needed for the default
        # pass.
        default_method._approximation_degree = self._approximation_degree
        if self.method == "default":
            plugin_method._approximation_degree = self._approximation_degree

        for node in dag.named_nodes(*self._synth_gates):
            if self._min_qubits is not None and len(
                    node.qargs) < self._min_qubits:
                continue
            synth_dag = None
            unitary = node.op.to_matrix()
            n_qubits = len(node.qargs)
            if (plugin_method.max_qubits is not None
                    and n_qubits > plugin_method.max_qubits) or (
                        plugin_method.min_qubits is not None
                        and n_qubits < plugin_method.min_qubits):
                method, kwargs = default_method, default_kwargs
            else:
                method, kwargs = plugin_method, plugin_kwargs
            if method.supports_coupling_map:
                kwargs["coupling_map"] = (
                    self._coupling_map,
                    [dag_bit_indices[x] for x in node.qargs],
                )
            synth_dag = method.run(unitary, **kwargs)
            if synth_dag is not None:
                if isinstance(synth_dag, tuple):
                    dag.substitute_node_with_dag(node,
                                                 synth_dag[0],
                                                 wires=synth_dag[1])
                else:
                    dag.substitute_node_with_dag(node, synth_dag)
        return dag