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 11:30 +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. 

14 

15from typing import cast 

16 

17from lark import Lark, Transformer 

18 

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 

54 

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 ")" 

98 

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" 

137 

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" 

158 

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""" 

166 

167 

168class PassTransformer(Transformer): 

169 def start(self, t: list[BasePass]) -> BasePass: 

170 return t[0] 

171 

172 def comp_pass(self, t: list[BasePass]) -> BasePass: 

173 return t[0] 

174 

175 def basic_pass(self, t: list[BasePass]) -> BasePass: 

176 return t[0] 

177 

178 def seq_pass(self, t: list[BasePass]) -> BasePass: 

179 return t[0] 

180 

181 def pass_list(self, t: list[BasePass]) -> BasePass: 

182 return SequencePass(t) 

183 

184 def repeat_pass(self, t: list[BasePass]) -> BasePass: 

185 return RepeatPass(t[0]) 

186 

187 def clifford_simp(self, t: list) -> BasePass: 

188 return CliffordSimp() 

189 

190 def clifford_simp_no_swaps(self, t: list) -> BasePass: 

191 return CliffordSimp(allow_swaps=False) 

192 

193 def commute_through_multis(self, t: list) -> BasePass: 

194 return CommuteThroughMultis() 

195 

196 def context_simp(self, t: list) -> BasePass: 

197 return ContextSimp() 

198 

199 def context_simp_no_classical(self, t: list) -> BasePass: 

200 return ContextSimp(allow_classical=False) 

201 

202 def decompose_arbitrarily_controlled_gates(self, t: list) -> BasePass: 

203 return DecomposeArbitrarilyControlledGates() 

204 

205 def decompose_boxes(self, t: list) -> BasePass: 

206 return DecomposeBoxes() 

207 

208 def decompose_classical_exp(self, t: list) -> BasePass: 

209 return DecomposeClassicalExp() 

210 

211 def decompose_multi_qubits_cx(self, t: list) -> BasePass: 

212 return DecomposeMultiQubitsCX() 

213 

214 def decompose_single_qubits_tk1(self, t: list) -> BasePass: 

215 return DecomposeSingleQubitsTK1() 

216 

217 def delay_measures(self, t: list) -> BasePass: 

218 return DelayMeasures(False) 

219 

220 def delay_measures_try(self, t: list) -> BasePass: 

221 return DelayMeasures(True) 

222 

223 def euler_angle_reduction(self, t: list[OpType]) -> BasePass: 

224 return EulerAngleReduction(t[0], t[1]) 

225 

226 def flatten_registers(self, t: list) -> BasePass: 

227 return FlattenRegisters() 

228 

229 def full_peephole_optimise(self, t: list) -> BasePass: 

230 return FullPeepholeOptimise() 

231 

232 def full_peephole_optimise_no_swaps(self, t: list) -> BasePass: 

233 return FullPeepholeOptimise(allow_swaps=False) 

234 

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]) 

239 

240 def guided_pauli_simp_default(self, t: list) -> BasePass: 

241 return GuidedPauliSimp() 

242 

243 def kak_decomposition(self, t: list) -> BasePass: 

244 return KAKDecomposition() 

245 

246 def optimise_phase_gadgets(self, t: list) -> BasePass: 

247 assert isinstance(t[0], CXConfigType) 

248 return OptimisePhaseGadgets(cx_config=t[0]) 

249 

250 def optimise_phase_gadgets_default(self, t: list) -> BasePass: 

251 return OptimisePhaseGadgets() 

252 

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]) 

257 

258 def pauli_exponentials_default(self, t: list) -> BasePass: 

259 return PauliExponentials() 

260 

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]) 

265 

266 def pauli_simp_default(self, t: list) -> BasePass: 

267 return PauliSimp() 

268 

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]) 

273 

274 def pauli_squash_default(self, t: list) -> BasePass: 

275 return PauliSquash() 

276 

277 def peephole_optimise_2q(self, t: list) -> BasePass: 

278 return PeepholeOptimise2Q() 

279 

280 def rebase_tket(self, t: list) -> BasePass: 

281 return RebaseTket() 

282 

283 def remove_barriers(self, t: list) -> BasePass: 

284 return RemoveBarriers() 

285 

286 def remove_discarded(self, t: list) -> BasePass: 

287 return RemoveDiscarded() 

288 

289 def remove_phase_ops(self, t: list) -> BasePass: 

290 return RemovePhaseOps() 

291 

292 def remove_redundancies(self, t: list) -> BasePass: 

293 return RemoveRedundancies() 

294 

295 def simplify_initial(self, t: list) -> BasePass: 

296 return SimplifyInitial() 

297 

298 def simplify_initial_no_classical(self, t: list) -> BasePass: 

299 return SimplifyInitial(allow_classical=False) 

300 

301 def simplify_measured(self, t: list) -> BasePass: 

302 return SimplifyMeasured() 

303 

304 def synthesise_tket(self, t: list) -> BasePass: 

305 return SynthesiseTket() 

306 

307 def three_qubit_squash(self, t: list) -> BasePass: 

308 return ThreeQubitSquash() 

309 

310 def cx_config_type(self, t: list[CXConfigType]) -> CXConfigType: 

311 return t[0] 

312 

313 def cx_config_type_snake(self, t: list) -> CXConfigType: 

314 return CXConfigType.Snake 

315 

316 def cx_config_type_star(self, t: list) -> CXConfigType: 

317 return CXConfigType.Star 

318 

319 def cx_config_type_tree(self, t: list) -> CXConfigType: 

320 return CXConfigType.Tree 

321 

322 def cx_config_type_multi_q_gate(self, t: list) -> CXConfigType: 

323 return CXConfigType.MultiQGate 

324 

325 def op_type(self, t: list[OpType]) -> OpType: 

326 return t[0] 

327 

328 def op_type_rx(self, t: list) -> OpType: 

329 return OpType.Rx 

330 

331 def op_type_ry(self, t: list) -> OpType: 

332 return OpType.Ry 

333 

334 def op_type_rz(self, t: list) -> OpType: 

335 return OpType.Rz 

336 

337 def pauli_synth_strat(self, t: list[PauliSynthStrat]) -> PauliSynthStrat: 

338 return t[0] 

339 

340 def pauli_synth_strat_individual(self, t: list) -> PauliSynthStrat: 

341 return PauliSynthStrat.Individual 

342 

343 def pauli_synth_strat_pairwise(self, t: list) -> PauliSynthStrat: 

344 return PauliSynthStrat.Pairwise 

345 

346 def pauli_synth_strat_sets(self, t: list) -> PauliSynthStrat: 

347 return PauliSynthStrat.Sets 

348 

349 

350parser = Lark(pass_grammar) 

351transformer = PassTransformer() 

352 

353 

354def compilation_pass_from_script(script: str) -> BasePass: 

355 """Generate a compilation pass from a specification. 

356 

357 The specification must conform to a simple grammar. For example, the following are 

358 valid specifications: 

359 

360 * "RemoveRedundancies" 

361 * "[RemoveBarriers, RemoveRedundancies]" (a sequence of passes) 

362 * "repeat(FullPeepholeOptimise)" (repeat a pass until it doesn't change the circuit) 

363 

364 Sequences and repeats can be nested arbitrarily. Whitespace is ignored. 

365 

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: 

368 

369 * "PauliSimp" (default parameters) 

370 * "PauliSimp(Pairwise, Tree)" 

371 * "EulerAngleReduction(Ry, Rz)" 

372 

373 For some passes with optional boolean parameters the name can be modified as 

374 follows: 

375 

376 * "CliffordSimp" (default parameters) 

377 * "CliffordSimpNoSwaps" 

378 * "SimplifyInitial" (default parameters) 

379 * "SimplifyInitialNoClassical" 

380 

381 There is currently no support for passes requiring more complex parameters such as 

382 lambdas or circuits. 

383 

384 The full formal grammar can be inspected using :py:meth:`compilation_pass_grammar`. 

385 

386 :param script: specification of pass 

387 """ 

388 tree = parser.parse(script) 

389 return cast(BasePass, transformer.transform(tree)) 

390 

391 

392def compilation_pass_grammar() -> str: 

393 """Formal grammar for specifying compilation passes. 

394 

395 This is the grammar assumed by :py:meth:`complilation_pass_from_script`. 

396 

397 :return: grammar in extended Backus--Naur form""" 

398 return pass_grammar