Coverage for /home/runner/work/tket/tket/pytket/pytket/passes/script.py: 75%
137 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-14 10:02 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-14 10:02 +0000
1# Copyright Quantinuum
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
15from typing import cast
17from lark import Lark, Transformer
19from pytket.circuit import CXConfigType, OpType
20from pytket.passes import (
21 BasePass,
22 CliffordSimp,
23 CommuteThroughMultis,
24 ContextSimp,
25 DecomposeArbitrarilyControlledGates,
26 DecomposeBoxes,
27 DecomposeClassicalExp,
28 DecomposeMultiQubitsCX,
29 DecomposeSingleQubitsTK1,
30 DelayMeasures,
31 EulerAngleReduction,
32 FlattenRegisters,
33 FullPeepholeOptimise,
34 GuidedPauliSimp,
35 KAKDecomposition,
36 OptimisePhaseGadgets,
37 PauliExponentials,
38 PauliSimp,
39 PauliSquash,
40 PeepholeOptimise2Q,
41 RebaseTket,
42 RemoveBarriers,
43 RemoveDiscarded,
44 RemovePhaseOps,
45 RemoveRedundancies,
46 RepeatPass,
47 SequencePass,
48 SimplifyInitial,
49 SimplifyMeasured,
50 SynthesiseTket,
51 ThreeQubitSquash,
52)
53from pytket.transform import PauliSynthStrat
55pass_grammar = """
56start: comp_pass
57comp_pass: ( basic_pass | seq_pass | repeat_pass )
58basic_pass:
59 | clifford_simp
60 | clifford_simp_no_swaps
61 | commute_through_multis
62 | context_simp
63 | context_simp_no_classical
64 | decompose_arbitrarily_controlled_gates
65 | decompose_boxes
66 | decompose_classical_exp
67 | decompose_multi_qubits_cx
68 | decompose_single_qubits_tk1
69 | delay_measures
70 | delay_measures_try
71 | euler_angle_reduction
72 | flatten_registers
73 | full_peephole_optimise
74 | full_peephole_optimise_no_swaps
75 | guided_pauli_simp
76 | guided_pauli_simp_default
77 | kak_decomposition
78 | optimise_phase_gadgets
79 | optimise_phase_gadgets_default
80 | pauli_simp
81 | pauli_simp_default
82 | pauli_squash
83 | pauli_squash_default
84 | peephole_optimise_2q
85 | rebase_tket
86 | remove_barriers
87 | remove_discarded
88 | remove_phase_ops
89 | remove_redundancies
90 | simplify_initial
91 | simplify_initial_no_classical
92 | simplify_measured
93 | synthesise_tket
94 | three_qubit_squash
95seq_pass: "[" pass_list "]"
96pass_list: comp_pass ("," comp_pass)*
97repeat_pass: "repeat" "(" comp_pass ")"
99clifford_simp: "CliffordSimp"
100clifford_simp_no_swaps: "CliffordSimpNoSwaps"
101commute_through_multis: "CommuteThroughMultis"
102context_simp: "ContextSimp"
103context_simp_no_classical: "ContextSimpNoClassical"
104decompose_arbitrarily_controlled_gates: "DecomposeArbitrarilyControlledGates"
105decompose_boxes: "DecomposeBoxes"
106decompose_classical_exp: "DecomposeClassicalExp"
107decompose_multi_qubits_cx: "DecomposeMultiQubitsCX"
108decompose_single_qubits_tk1: "DecomposeSingleQubitsTK1"
109delay_measures: "DelayMeasures"
110delay_measures_try: "TryDelayMeasures"
111euler_angle_reduction: "EulerAngleReduction" "(" op_type "," op_type ")"
112flatten_registers: "FlattenRegisters"
113full_peephole_optimise: "FullPeepholeOptimise"
114full_peephole_optimise_no_swaps: "FullPeepholeOptimiseNoSwaps"
115guided_pauli_simp: "GuidedPauliSimp" "(" pauli_synth_strat "," cx_config_type ")"
116guided_pauli_simp_default: "GuidedPauliSimp"
117kak_decomposition: "KAKDecomposition"
118optimise_phase_gadgets: "OptimisePhaseGadgets" "(" cx_config_type ")"
119optimise_phase_gadgets_default: "OptimisePhaseGadgets"
120pauli_exponentials: "PauliExponentials" "(" pauli_synth_strat "," cx_config_type ")"
121pauli_exponentials_default: "PauliExponentials"
122pauli_simp: "PauliSimp" "(" pauli_synth_strat "," cx_config_type ")"
123pauli_simp_default: "PauliSimp"
124pauli_squash: "PauliSquash" "(" pauli_synth_strat "," cx_config_type ")"
125pauli_squash_default: "PauliSquash"
126peephole_optimise_2q: "PeepholeOptimise2Q"
127rebase_tket: "RebaseTket"
128remove_barriers: "RemoveBarriers"
129remove_discarded: "RemoveDiscarded"
130remove_phase_ops: "RemovePhaseOps"
131remove_redundancies: "RemoveRedundancies"
132simplify_initial: "SimplifyInitial"
133simplify_initial_no_classical: "SimplifyInitialNoClassical"
134simplify_measured: "SimplifyMeasured"
135synthesise_tket: "SynthesiseTket"
136three_qubit_squash: "ThreeQubitSquash"
138cx_config_type:
139 | cx_config_type_snake
140 | cx_config_type_star
141 | cx_config_type_tree
142 | cx_config_type_multi_q_gate
143cx_config_type_snake: "Snake"
144cx_config_type_star: "Star"
145cx_config_type_tree: "Tree"
146cx_config_type_multi_q_gate: "MultiQGate"
147op_type: ( op_type_rx | op_type_ry | op_type_rz )
148op_type_rx: "Rx"
149op_type_ry: "Ry"
150op_type_rz: "Rz"
151pauli_synth_strat:
152 | pauli_synth_strat_individual
153 | pauli_synth_strat_pairwise
154 | pauli_synth_strat_sets
155pauli_synth_strat_individual: "Individual"
156pauli_synth_strat_pairwise: "Pairwise"
157pauli_synth_strat_sets: "Sets"
159%import common.WS_INLINE -> WS
160%import common.CR
161%import common.LF
162_NEWLINE: CR? LF
163%ignore WS
164%ignore _NEWLINE
165"""
168class PassTransformer(Transformer):
169 def start(self, t: list[BasePass]) -> BasePass:
170 return t[0]
172 def comp_pass(self, t: list[BasePass]) -> BasePass:
173 return t[0]
175 def basic_pass(self, t: list[BasePass]) -> BasePass:
176 return t[0]
178 def seq_pass(self, t: list[BasePass]) -> BasePass:
179 return t[0]
181 def pass_list(self, t: list[BasePass]) -> BasePass:
182 return SequencePass(t)
184 def repeat_pass(self, t: list[BasePass]) -> BasePass:
185 return RepeatPass(t[0])
187 def clifford_simp(self, t: list) -> BasePass:
188 return CliffordSimp()
190 def clifford_simp_no_swaps(self, t: list) -> BasePass:
191 return CliffordSimp(allow_swaps=False)
193 def commute_through_multis(self, t: list) -> BasePass:
194 return CommuteThroughMultis()
196 def context_simp(self, t: list) -> BasePass:
197 return ContextSimp()
199 def context_simp_no_classical(self, t: list) -> BasePass:
200 return ContextSimp(allow_classical=False)
202 def decompose_arbitrarily_controlled_gates(self, t: list) -> BasePass:
203 return DecomposeArbitrarilyControlledGates()
205 def decompose_boxes(self, t: list) -> BasePass:
206 return DecomposeBoxes()
208 def decompose_classical_exp(self, t: list) -> BasePass:
209 return DecomposeClassicalExp()
211 def decompose_multi_qubits_cx(self, t: list) -> BasePass:
212 return DecomposeMultiQubitsCX()
214 def decompose_single_qubits_tk1(self, t: list) -> BasePass:
215 return DecomposeSingleQubitsTK1()
217 def delay_measures(self, t: list) -> BasePass:
218 return DelayMeasures(False)
220 def delay_measures_try(self, t: list) -> BasePass:
221 return DelayMeasures(True)
223 def euler_angle_reduction(self, t: list[OpType]) -> BasePass:
224 return EulerAngleReduction(t[0], t[1])
226 def flatten_registers(self, t: list) -> BasePass:
227 return FlattenRegisters()
229 def full_peephole_optimise(self, t: list) -> BasePass:
230 return FullPeepholeOptimise()
232 def full_peephole_optimise_no_swaps(self, t: list) -> BasePass:
233 return FullPeepholeOptimise(allow_swaps=False)
235 def guided_pauli_simp(self, t: list) -> BasePass:
236 assert isinstance(t[0], PauliSynthStrat)
237 assert isinstance(t[1], CXConfigType)
238 return GuidedPauliSimp(strat=t[0], cx_config=t[1])
240 def guided_pauli_simp_default(self, t: list) -> BasePass:
241 return GuidedPauliSimp()
243 def kak_decomposition(self, t: list) -> BasePass:
244 return KAKDecomposition()
246 def optimise_phase_gadgets(self, t: list) -> BasePass:
247 assert isinstance(t[0], CXConfigType)
248 return OptimisePhaseGadgets(cx_config=t[0])
250 def optimise_phase_gadgets_default(self, t: list) -> BasePass:
251 return OptimisePhaseGadgets()
253 def pauli_exponentials(self, t: list) -> BasePass:
254 assert isinstance(t[0], PauliSynthStrat)
255 assert isinstance(t[1], CXConfigType)
256 return PauliExponentials(strat=t[0], cx_config=t[1])
258 def pauli_exponentials_default(self, t: list) -> BasePass:
259 return PauliExponentials()
261 def pauli_simp(self, t: list) -> BasePass:
262 assert isinstance(t[0], PauliSynthStrat)
263 assert isinstance(t[1], CXConfigType)
264 return PauliSimp(strat=t[0], cx_config=t[1])
266 def pauli_simp_default(self, t: list) -> BasePass:
267 return PauliSimp()
269 def pauli_squash(self, t: list) -> BasePass:
270 assert isinstance(t[0], PauliSynthStrat)
271 assert isinstance(t[1], CXConfigType)
272 return PauliSquash(strat=t[0], cx_config=t[1])
274 def pauli_squash_default(self, t: list) -> BasePass:
275 return PauliSquash()
277 def peephole_optimise_2q(self, t: list) -> BasePass:
278 return PeepholeOptimise2Q()
280 def rebase_tket(self, t: list) -> BasePass:
281 return RebaseTket()
283 def remove_barriers(self, t: list) -> BasePass:
284 return RemoveBarriers()
286 def remove_discarded(self, t: list) -> BasePass:
287 return RemoveDiscarded()
289 def remove_phase_ops(self, t: list) -> BasePass:
290 return RemovePhaseOps()
292 def remove_redundancies(self, t: list) -> BasePass:
293 return RemoveRedundancies()
295 def simplify_initial(self, t: list) -> BasePass:
296 return SimplifyInitial()
298 def simplify_initial_no_classical(self, t: list) -> BasePass:
299 return SimplifyInitial(allow_classical=False)
301 def simplify_measured(self, t: list) -> BasePass:
302 return SimplifyMeasured()
304 def synthesise_tket(self, t: list) -> BasePass:
305 return SynthesiseTket()
307 def three_qubit_squash(self, t: list) -> BasePass:
308 return ThreeQubitSquash()
310 def cx_config_type(self, t: list[CXConfigType]) -> CXConfigType:
311 return t[0]
313 def cx_config_type_snake(self, t: list) -> CXConfigType:
314 return CXConfigType.Snake
316 def cx_config_type_star(self, t: list) -> CXConfigType:
317 return CXConfigType.Star
319 def cx_config_type_tree(self, t: list) -> CXConfigType:
320 return CXConfigType.Tree
322 def cx_config_type_multi_q_gate(self, t: list) -> CXConfigType:
323 return CXConfigType.MultiQGate
325 def op_type(self, t: list[OpType]) -> OpType:
326 return t[0]
328 def op_type_rx(self, t: list) -> OpType:
329 return OpType.Rx
331 def op_type_ry(self, t: list) -> OpType:
332 return OpType.Ry
334 def op_type_rz(self, t: list) -> OpType:
335 return OpType.Rz
337 def pauli_synth_strat(self, t: list[PauliSynthStrat]) -> PauliSynthStrat:
338 return t[0]
340 def pauli_synth_strat_individual(self, t: list) -> PauliSynthStrat:
341 return PauliSynthStrat.Individual
343 def pauli_synth_strat_pairwise(self, t: list) -> PauliSynthStrat:
344 return PauliSynthStrat.Pairwise
346 def pauli_synth_strat_sets(self, t: list) -> PauliSynthStrat:
347 return PauliSynthStrat.Sets
350parser = Lark(pass_grammar)
351transformer = PassTransformer()
354def compilation_pass_from_script(script: str) -> BasePass:
355 """Generate a compilation pass from a specification.
357 The specification must conform to a simple grammar. For example, the following are
358 valid specifications:
360 * "RemoveRedundancies"
361 * "[RemoveBarriers, RemoveRedundancies]" (a sequence of passes)
362 * "repeat(FullPeepholeOptimise)" (repeat a pass until it doesn't change the circuit)
364 Sequences and repeats can be nested arbitrarily. Whitespace is ignored.
366 Most passes are specified using their Python names. For those that take enums as
367 parameters, non-default values can be specified using their Python names:
369 * "PauliSimp" (default parameters)
370 * "PauliSimp(Pairwise, Tree)"
371 * "EulerAngleReduction(Ry, Rz)"
373 For some passes with optional boolean parameters the name can be modified as
374 follows:
376 * "CliffordSimp" (default parameters)
377 * "CliffordSimpNoSwaps"
378 * "SimplifyInitial" (default parameters)
379 * "SimplifyInitialNoClassical"
381 There is currently no support for passes requiring more complex parameters such as
382 lambdas or circuits.
384 The full formal grammar can be inspected using :py:meth:`compilation_pass_grammar`.
386 :param script: specification of pass
387 """
388 tree = parser.parse(script)
389 return cast(BasePass, transformer.transform(tree))
392def compilation_pass_grammar() -> str:
393 """Formal grammar for specifying compilation passes.
395 This is the grammar assumed by :py:meth:`complilation_pass_from_script`.
397 :return: grammar in extended Backus--Naur form"""
398 return pass_grammar