Source code for mindquantum.algorithm.compiler.rules.basic_rule

# Copyright 2021 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""Basic compiler rule."""
import typing
from abc import ABC, abstractmethod

from mindquantum.core.circuit import Circuit

from ..dag import DAGCircuit
from .compiler_logger import CompileLog as CLog
from .compiler_logger import LogIndentation


# pylint: disable=too-few-public-methods,invalid-name
[docs]class BasicCompilerRule(ABC): """ The basic compiler rule class. Compiler rule will handle a :class:`~.algorithm.compiler.DAGCircuit` and compile it following the rule in the ``do`` method. You must implement the ``do`` method when inheritance a child compiler rule. Please make sure that the ``do`` method will return a bool, which will tell whether the compiler successful compiled the circuit. Args: rule_name (str): The name of this compiler rule. log_level (int): The display log level. If ``0``, log will be disabled. If ``1``, a brief log will be displayed. If ``2``, a detail log will be displayed. Default: ``0``. """ def __init__(self, rule_name="BasicCompilerRule", log_level=0): """Initialize a basic compiler rule.""" self.rule_name = rule_name self.log_level = log_level def __repr__(self): """Get string expression of rule.""" return f"{self.rule_name}<>"
[docs] def set_log_level(self, log_level: int): """ Set display log level. Args: log_level (int): the display log level. Could be ``0``, ``1`` or ``2``. For more explanation of log level, please refers to :class:`~.algorithm.compiler.BasicCompilerRule`. """ self.log_level = log_level return self
[docs] @abstractmethod def do(self, dag_circuit: DAGCircuit) -> bool: """ Inplace applying this compiler rule to the :class:`~.algorithm.compiler.DAGCircuit`. Args: dag_circuit (:class:`~.algorithm.compiler.DAGCircuit`): The DAG graph of quantum circuit. """
[docs]class SequentialCompiler(BasicCompilerRule): """ A sequential of compiler. Every compiler rule in this sequence will be execute one by one. Args: compilers (List[:class:`~.algorithm.compiler.BasicCompilerRule`]): all compiler rules you want. rule_name (str): name of this compiler. Default: ``"SequentialCompiler"``. log_level (int): the display log level. Could be ``0``, ``1`` or ``2``. For more explanation of log level, please refers to :class:`~.algorithm.compiler.BasicCompilerRule`. Default: ``0``. """ def __init__(self, compilers: typing.List[BasicCompilerRule], rule_name="SequentialCompiler", log_level=0): """Initialize a sequential compiler rule.""" self.compilers = compilers super().__init__(rule_name, log_level) def __repr__(self): """Get string expression of rule.""" strs = [f'{self.rule_name}<'] for compiler in self.compilers: for i in compiler.__repr__().split('\n'): strs.append(" " + i) strs.append('>') return '\n'.join(strs)
[docs] def set_all_log_level(self, log_level: int): """ Set log level for all compiler rule in this sequence. Args: log_level (int): the display log level. Could be ``0``, ``1`` or ``2``. For more explanation of log level, please refers to :class:`~.algorithm.compiler.BasicCompilerRule`. """ self.log_level = log_level for compiler in self.compilers: if hasattr(compiler, "set_all_log_level"): compiler.set_all_log_level(log_level) else: compiler.set_log_level(log_level) return self
[docs] def do(self, dag_circuit: DAGCircuit) -> bool: """ Apply sequential compiler to dag circuit. Args: dag_circuit (:class:`~.algorithm.compiler.DAGCircuit`): The DAG graph of quantum circuit. """ compiled = False child_name = ', '.join(CLog.R2(compiler.rule_name) for compiler in self.compilers) CLog.log(f"Running {CLog.R1(self.rule_name)}: {len(self.compilers)} child ({child_name}, ).", 1, self.log_level) with LogIndentation() as _: states = [compiler.do(dag_circuit) for compiler in self.compilers] CLog.log(f"{CLog.R1(self.rule_name)}: state for each rule -> {CLog.ShowState(states)}", 2, self.log_level) compiled = any(states) if compiled: CLog.log(f"{CLog.R1(self.rule_name)}: {CLog.P('successfully compiled')}.", 1, self.log_level) else: CLog.log(f"{CLog.R1(self.rule_name)}: nothing happened.", 1, self.log_level) return compiled
[docs]class KroneckerSeqCompiler(SequentialCompiler): """ Kronecker sequential compiler. Every compiler rule in this KroneckerSeqCompiler will be execute until they do not compile any gate. Args: compilers (List[:class:`~.algorithm.compiler.BasicCompilerRule`]): compiler rules. rule_name(str): the name of compiler rule. Default: ``"KroneckerSeqCompiler"``. log_level (int): the display log level. Could be ``0``, ``1`` or ``2``. Default: ``0``. For more explanation of log level, please refers to :class:`~.algorithm.compiler.BasicCompilerRule`. """ def __init__(self, compilers: typing.List[BasicCompilerRule], rule_name="KroneckerSeqCompiler", log_level=0): """Initialize a KroneckerSeqCompiler.""" super().__init__(compilers, rule_name, log_level)
[docs] def do(self, dag_circuit: DAGCircuit) -> bool: """ Apply kronecker compiler to dag circuit. Args: dag_circuit (:class:`~.algorithm.compiler.DAGCircuit`): The DAG graph of quantum circuit. """ compiled = False child_name = ', '.join(CLog.R2(compiler.rule_name) for compiler in self.compilers) CLog.log(f"Running {CLog.R1(self.rule_name)}: {len(self.compilers)} child ({child_name}, ).", 1, self.log_level) with LogIndentation() as _: while True: states = [compiler.do(dag_circuit) for compiler in self.compilers] CLog.log( f"{CLog.R1(self.rule_name)}: state for each rule -> {CLog.ShowState(states)}", 2, self.log_level ) if any(states): compiled = True else: break if compiled: CLog.log(f"{CLog.R1(self.rule_name)}: {CLog.P('successfully compiled')}.", 1, self.log_level) else: CLog.log(f"{CLog.R1(self.rule_name)}: nothing happened.", 1, self.log_level) return compiled
[docs]def compile_circuit(compiler: BasicCompilerRule, circ: Circuit) -> Circuit: """ Directly compile a given circuit and return the result. Args: compiler (:class:`~.algorithm.compiler.BasicCompilerRule`): compile rules. circ (:class:`~.core.circuit.Circuit`): the input quantum circuit. Returns: :class:`~.core.circuit.Circuit`, the final circuit compiled by given compiler. Examples: >>> from mindquantum.algorithm.compiler import compile_circuit, BasicDecompose >>> from mindquantum.core import gates as G >>> from mindquantum.core.circuit import Circuit >>> circ = Circuit([G.Rxx('a').on([0, 1]), G.X(0, [1, 2])]) >>> circ ┏━━━━━━━━┓ ┏━━━┓ q0: ──┨ ┠─┨╺╋╸┠─── ┃ ┃ ┗━┳━┛ ┃ Rxx(a) ┃ ┃ q1: ──┨ ┠───■───── ┗━━━━━━━━┛ ┃ q2: ───────────────■───── >>> compile_circuit(BasicDecompose(), circ) ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━━┓ ┏━━━┓ q0: ──┨ H ┠───■───────────────■───┨ H ┠─┨ H ┠─┨╺╋╸┠─┨ T† ┠─┨╺╋╸┠─┨ T ┠─┨╺╋╸┠─┨ T† ┠─┨╺╋╸┠─↯─ ┗━━━┛ ┃ ┃ ┗━━━┛ ┗━━━┛ ┗━┳━┛ ┗━━━━┛ ┗━┳━┛ ┗━━━┛ ┗━┳━┛ ┗━━━━┛ ┗━┳━┛ ┏━━━┓ ┏━┻━┓ ┏━━━━━━━┓ ┏━┻━┓ ┏━━━┓ ┃ ┃ ┃ ┃ q1: ──┨ H ┠─┨╺╋╸┠─┨ RZ(a) ┠─┨╺╋╸┠─┨ H ┠─────────■────────────╂───────────■────────────╂───↯─ ┗━━━┛ ┗━━━┛ ┗━━━━━━━┛ ┗━━━┛ ┗━━━┛ ┃ ┃ ┃ ┃ q2: ─────────────────────────────────────────────────────────■────────────────────────■───↯─ ┏━━━┓ ┏━━━┓ q0: ──┨ T ┠─┨ H ┠──────────────── ┗━━━┛ ┗━━━┛ ┏━━━┓ ┏━━━┓ ┏━━━━┓ ┏━━━┓ q1: ──┨ T ┠─┨╺╋╸┠─┨ T† ┠─┨╺╋╸┠─── ┗━━━┛ ┗━┳━┛ ┗━━━━┛ ┗━┳━┛ ┃ ┏━━━┓ ┃ q2: ──────────■───┨ T ┠────■───── ┗━━━┛ """ dag_circ = DAGCircuit(circ) compiler.do(dag_circ) return dag_circ.to_circuit()