"""Optimization configuration for Guppy compilation.Guppy applies a predefined set of optimization passes when compiling a programusing the TKET compiler.These passes clean up artifacts introduced by the compiler and may simplify bothclassical and quantum operations when calling ``compile()``,``compile_function()``, or ``emulator()``.Use ``with_opt_level()`` before compiling or creating an emulator to select adifferent :py:class:`OptimizationLevel`. The method can be chained beforecompiling or creating an emulator.Choosing an optimization level------------------------------Pass a member of :py:class:`OptimizationLevel` to ``with_opt_level()``:.. code-block:: python from guppylang import OptimizationLevel, guppy from guppylang.std.builtins import output from guppylang.std.quantum import h, measure, qubit @guppy def main() -> None: q = qubit() h(q) h(q) if measure(q): output("result", 2 + 2) else: output("result", 3 + 3) # Classical optimization will keep the self-inverse Hadamard gates. package = main.with_opt_level(OptimizationLevel.Classical).compile()The available levels are:* :py:attr:`OptimizationLevel.Default` applies Guppy's standard optimization level. This may include both classical and quantum optimizations that do not alter the program's gateset. Calling ``main.compile()`` or ``main.emulator(...)`` directly uses this level.* :py:attr:`OptimizationLevel.Classical` restricts optimization to classical operations. The program will execute the same quantum operations as the original source, but may have a simplified control flow structure.* :py:attr:`OptimizationLevel.Minimal` applies only structural rewrites needed to produce executable output. This is useful for low-level program analysis or when more control over the optimization passes is desired.See :py:class:`OptimizationLevel` for more details.Note that gate rebasing or other program transformations may still be performedfurther down the compilation pipeline where required. For example, emulators mayrequire a specific gateset when targeting a particular architecture.``with_minimal_opt()`` is shorthand for selecting :py:attr:`OptimizationLevel.Minimal`.It disables optional optimizations on the program... code-block:: python emulator = main.with_minimal_opt().emulator(n_qubits=1)Running custom passes---------------------Use :py:meth:`OptimizerInstance.with_optimization` to append any HUGR``ComposablePass`` to an optimization pipeline. For example, the followingstarts with minimal optimization and then runs tket's function-inlining pass:.. code-block:: python from tket.passes import InlineFunctions # Apply a tket pass to inline Guppy functions package = main.with_minimal_opt().with_optimization(InlineFunctions()).compile() package = ( main.with_minimal_opt().with_optimization(passes.InlineFunctions()) .compile() )Multiple custom passes can be added by chaining ``with_optimization()`` calls.They run in the order they are added, after the passes supplied by the selectedoptimization level:.. code-block:: python package = ( main.with_opt_level(OptimizationLevel.Classical) .with_optimization(first_pass) .with_optimization(second_pass) .compile() )"""from__future__importannotationsimportfunctoolsfromdataclassesimportdataclass,fieldfromenumimportEnumfromtypingimport(TYPE_CHECKING,Generic,ParamSpec,TypeVar,)ifTYPE_CHECKING:fromcollections.abcimportSequencefromhugr.packageimportPackagefromhugr.passes.composableimportComposablePassfromguppylang.defsimportGuppyFunctionDefinitionfromguppylang.emulatorimportEmulatorBuilder,EmulatorInstance,Platform__all__=("OptimizationLevel","OptimizerInstance",)P=ParamSpec("P")Out=TypeVar("Out")
[docs]classOptimizationLevel(Enum):"""Optimization level used when compiling a Guppy program."""Default="default"""" Guppy's standard optimization level. This may include both classical and quantum optimizations that do not alter the program's gateset. Calling ``main.compile()`` or ``main.emulator(...)`` directly uses this level. Currently, this applies pytket's `RemoveRedundancies` after the optimizations in :py:attr:`OptimizationLevel.Classical`. This may be modified in future versions. """Classical="classical"""" Restricts optimization to classical operations. The program will execute the same quantum operations as the original source, but may have a simplified control flow structure. Currently, this runs tket's `Normalize <https://quantinuum.github.io/tket2/generated/tket.passes.Normalize.html#tket.passes.Normalize>`_ pass to simplify classical control flow and remove redundant classical operations. This set may be modified in future versions. """Minimal="minimal"""" Applies only structural rewrites needed to produce executable output. This is useful for low-level program analysis or when more control over the optimization passes is desired. """
[docs]defpasses(self)->list[ComposablePass]:"""Return the list of HUGR passes ran by this optimization level."""matchself:caseOptimizationLevel.Default:# The pytket dependency could be bypassed by using the json# encoding of the passes rather than the pytket objects# themselves.frompytket.passesimportRemoveRedundanciesfromtketimportpassesreturn[passes.Normalize(),passes.PytketHugrPass(RemoveRedundancies())]caseOptimizationLevel.Classical:fromtketimportpassesreturn[passes.Normalize()]caseOptimizationLevel.Minimal:return[]
def_apply_passes(package:Package,passes:Sequence[ComposablePass])->Package:ifnotpasses:returnpackage# Compose the passes to trigger any cross-pass optimizations that may be possible.composed=functools.reduce(lambdax,y:x.then(y),passes)formoduleinpackage.modules:composed.run(module,inplace=True)returnpackage
[docs]@dataclass(frozen=True)classOptimizerInstance(Generic[P,Out]):"""Builder used to configure optimizations for compiling a Guppy program. Obtained by calling :py:meth:`GuppyFunctionDefinition.with_opt_level` or :py:meth:`GuppyFunctionDefinition.with_minimal_opt`. See :py:mod:`guppylang.optimizer` for usage examples. """definition:GuppyFunctionDefinition[P,Out]passes:list[ComposablePass]=field(default_factory=list)
[docs]defwith_optimization(self,optimization:ComposablePass)->OptimizerInstance[P,Out]:"""Add an additional optimization pass to run while compiling the program."""returnOptimizerInstance(self.definition,[*self.passes,optimization])
[docs]defemulator(self,n_qubits:int|None=None,builder:EmulatorBuilder|None=None,libs:list[Package]|None=None,platform:Platform="helios",)->EmulatorInstance:"""Compile this function for emulation with the configured optimizations."""returnself.definition._emulator(self.compile_function(),n_qubits,builder,libs,platform)
defcompile(self)->Package:"""Compile an execution entrypoint with the configured optimizations. Alias for :py:meth:`compile_entrypoint`. """returnself.compile_entrypoint()
[docs]defcompile_entrypoint(self)->Package:"""Compile an entrypoint with the configured optimizations."""return_apply_passes(self.definition._compile_entrypoint(),self.passes)
[docs]defcompile_function(self)->Package:"""Compile a function with the configured optimizations."""return_apply_passes(self.definition._compile_function(),self.passes)