1use std::{collections::HashMap, ops::Range, vec};
5
6use indexmap::{IndexMap, IndexSet};
7
8use crate::{
9 expression::Expression,
10 instruction::{
11 DefGateSequenceExpansionError, GateDefinition, GateSignature, GateSpecification,
12 Instruction,
13 },
14 program::{InstructionIndex, SourceMap, SourceMapEntry},
15};
16
17use super::source_map::{ExpansionResult, SourceMapIndexable};
18
19#[derive(Clone, Debug, PartialEq)]
21pub struct DefGateSequenceExpansion<'a> {
22 source_signature: crate::instruction::GateSignature<'a>,
30
31 range: Range<InstructionIndex>,
33
34 nested_expansions: SourceMap<InstructionIndex, ExpansionResult<DefGateSequenceExpansion<'a>>>,
38}
39
40#[cfg(feature = "python")]
41impl<'a> DefGateSequenceExpansion<'a> {
42 pub(crate) fn source_signature(&self) -> &GateSignature<'a> {
44 &self.source_signature
45 }
46}
47
48impl<'a> DefGateSequenceExpansion<'a> {
49 pub fn range(&self) -> &Range<InstructionIndex> {
51 &self.range
52 }
53
54 pub fn nested_expansions(
56 &self,
57 ) -> &SourceMap<InstructionIndex, ExpansionResult<DefGateSequenceExpansion<'a>>> {
58 &self.nested_expansions
59 }
60}
61
62impl SourceMapIndexable<InstructionIndex> for DefGateSequenceExpansion<'_> {
63 fn contains(&self, other: &InstructionIndex) -> bool {
64 self.range.contains(other)
65 }
66}
67
68impl<'a> SourceMapIndexable<GateSignature<'a>> for DefGateSequenceExpansion<'a> {
69 fn contains(&self, other: &GateSignature) -> bool {
70 &self.source_signature == other
71 }
72}
73
74type SequenceGateDefinitionSourceMap<'a> =
75 SourceMap<InstructionIndex, ExpansionResult<DefGateSequenceExpansion<'a>>>;
76
77#[derive(Clone, Debug, PartialEq)]
79pub(crate) struct ProgramDefGateSequenceExpander<'a, F> {
80 gate_definitions: &'a IndexMap<String, GateDefinition>,
81 filter: F,
82}
83
84#[derive(Clone, Debug, PartialEq)]
85pub(crate) struct ExpandedInstructionsWithSourceMap<'a> {
86 pub(crate) instructions: Vec<Instruction>,
87 pub(crate) source_map: SequenceGateDefinitionSourceMap<'a>,
88}
89
90struct ExpansionStack(IndexSet<String>);
91
92impl ExpansionStack {
93 fn new() -> Self {
94 Self(IndexSet::new())
95 }
96
97 fn check(&self, name: impl AsRef<str>) -> Result<(), DefGateSequenceExpansionError> {
99 if self.0.contains(name.as_ref()) {
100 let cycle = self.0.iter().cloned().collect();
101 Err(DefGateSequenceExpansionError::CyclicSequenceGateDefinition(
102 cycle,
103 ))
104 } else {
105 Ok(())
106 }
107 }
108
109 fn with_gate_sequence<F, R>(&mut self, name: String, f: F) -> R
111 where
112 F: FnOnce(&mut Self) -> R,
113 {
114 let must_pop = self.0.insert(name);
115 let result = f(self);
116 if must_pop {
117 self.0.pop();
118 }
119 result
120 }
121}
122
123impl<'a, F> ProgramDefGateSequenceExpander<'a, F>
124where
125 F: Fn(&str) -> bool,
126{
127 pub(crate) fn new(gate_definitions: &'a IndexMap<String, GateDefinition>, filter: F) -> Self {
135 Self {
136 gate_definitions,
137 filter,
138 }
139 }
140
141 pub(crate) fn expand(
143 &self,
144 source_instructions: &[Instruction],
145 ) -> Result<Vec<Instruction>, DefGateSequenceExpansionError> {
146 self.expand_without_source_map_impl(source_instructions, &mut ExpansionStack::new())
147 }
148
149 pub(crate) fn expand_with_source_map(
152 &self,
153 source_instructions: &'a [Instruction],
154 ) -> Result<ExpandedInstructionsWithSourceMap<'a>, DefGateSequenceExpansionError> {
155 let mut source_map = SourceMap::default();
156 self.expand_with_source_map_impl(
157 source_instructions,
158 &mut source_map,
159 &mut ExpansionStack::new(),
160 )
161 .map(|instructions| ExpandedInstructionsWithSourceMap {
162 instructions,
163 source_map,
164 })
165 }
166
167 fn expand_with_source_map_impl(
168 &self,
169 source_instructions: &[Instruction],
170 source_map: &mut SequenceGateDefinitionSourceMap<'a>,
171 stack: &mut ExpansionStack,
172 ) -> Result<Vec<Instruction>, DefGateSequenceExpansionError> {
173 let mut target_instructions = vec![];
174 for (source_instruction_index, source_instruction) in source_instructions.iter().enumerate()
175 {
176 if let Some((target_gate_instructions, gate_sequence_signature)) =
177 self.gate_sequence_from_instruction(source_instruction, stack)?
178 {
179 let mut nested_expansions = SourceMap::default();
184 let recursive_target_gate_instructions = stack.with_gate_sequence(
185 gate_sequence_signature.name().to_string(),
186 |stack| {
187 self.expand_with_source_map_impl(
188 &target_gate_instructions,
189 &mut nested_expansions,
190 stack,
191 )
192 },
193 )?;
194
195 let target_instruction_start_index = InstructionIndex(target_instructions.len());
196 let target_instruction_end_index = InstructionIndex(
197 target_instruction_start_index.0 + recursive_target_gate_instructions.len(),
198 );
199 source_map.entries.push(SourceMapEntry {
200 source_location: InstructionIndex(source_instruction_index),
201 target_location: ExpansionResult::Rewritten(DefGateSequenceExpansion {
202 source_signature: gate_sequence_signature,
203 range: target_instruction_start_index..target_instruction_end_index,
204 nested_expansions,
205 }),
206 });
207 target_instructions.extend(recursive_target_gate_instructions);
208 } else {
209 target_instructions.push(source_instruction.clone());
210 source_map.entries.push(SourceMapEntry {
211 source_location: InstructionIndex(source_instruction_index),
212 target_location: ExpansionResult::Unmodified(InstructionIndex(
213 target_instructions.len() - 1,
214 )),
215 });
216 }
217 }
218 Ok(target_instructions)
219 }
220
221 fn expand_without_source_map_impl(
222 &self,
223 source_instructions: &[Instruction],
224 stack: &mut ExpansionStack,
225 ) -> Result<Vec<Instruction>, DefGateSequenceExpansionError> {
226 let mut target_instructions = vec![];
227 for source_instruction in source_instructions {
228 if let Some((target_gate_instructions, source)) =
229 self.gate_sequence_from_instruction(source_instruction, stack)?
230 {
231 let recursive_target_gate_instructions = stack
236 .with_gate_sequence(source.name().to_string(), |stack| {
237 self.expand_without_source_map_impl(&target_gate_instructions, stack)
238 })?;
239 target_instructions.extend(recursive_target_gate_instructions);
240 } else {
241 target_instructions.push(source_instruction.clone());
242 }
243 }
244 Ok(target_instructions)
245 }
246
247 fn gate_sequence_from_instruction(
255 &self,
256 instruction: &Instruction,
257 stack: &ExpansionStack,
258 ) -> Result<Option<(Vec<Instruction>, GateSignature<'a>)>, DefGateSequenceExpansionError> {
259 if let Instruction::Gate(gate) = instruction {
260 if let Some(gate_definition) = self.gate_definitions.get(&gate.name) {
261 if let GateSpecification::Sequence(gate_sequence) = &gate_definition.specification {
262 if (self.filter)(&gate.name) {
263 if gate_definition.parameters.len() != gate.parameters.len() {
264 return Err(DefGateSequenceExpansionError::ParameterCount {
265 expected: gate_definition.parameters.len(),
266 found: gate.parameters.len(),
267 });
268 }
269 let gate_parameter_arguments = gate_definition
270 .parameters
271 .iter()
272 .cloned()
273 .zip(gate.parameters.iter().cloned())
274 .collect::<HashMap<String, Expression>>();
275
276 if !gate.modifiers.is_empty() {
277 return Err(DefGateSequenceExpansionError::GateModifiersUnsupported(
278 gate.modifiers.clone(),
279 ));
280 }
281 let source = gate_definition.signature();
282 stack.check(source.name())?;
283
284 let target_gate_instructions = gate_sequence
285 .expand(gate_parameter_arguments, gate.qubits.clone())?
286 .into_iter()
287 .map(Instruction::Gate)
288 .collect::<Vec<_>>();
289
290 return Ok(Some((target_gate_instructions, source)));
291 }
292 }
293 }
294 }
295 Ok(None)
296 }
297}
298
299#[cfg(test)]
300mod tests {
301 use std::str::FromStr;
302
303 use crate::{instruction::GateSignature, Program};
304
305 use super::*;
306 use rstest::*;
307
308 struct DefGateSequenceExpansionTestCase {
310 program: &'static str,
311 filter: Box<dyn Fn(&str) -> bool>,
312 expected: Result<&'static str, DefGateSequenceExpansionError>,
313 source_map_entry_builders:
314 Vec<SourceMapEntry<InstructionIndex, ExpansionResult<DefGateSequenceExpansionBuilder>>>,
315 }
316
317 impl DefGateSequenceExpansionTestCase {
325 fn to_source_map(
326 &self,
327 ) -> SourceMap<InstructionIndex, ExpansionResult<DefGateSequenceExpansion<'_>>> {
328 SourceMap {
329 entries: self
330 .source_map_entry_builders
331 .iter()
332 .map(|builder| SourceMapEntry {
333 source_location: builder.source_location,
334 target_location: match &builder.target_location {
335 ExpansionResult::Rewritten(expansion) => expansion.build(),
336 ExpansionResult::Unmodified(index) => {
337 ExpansionResult::Unmodified(*index)
338 }
339 },
340 })
341 .collect(),
342 }
343 }
344
345 fn simple_1q_expansions() -> Self {
346 const QUIL: &str = r"
347DEFGATE seq2(%param1, %param2) a b AS SEQUENCE:
348 seq1(%param1) a
349 seq1(%param2) b
350
351DEFGATE seq1(%param1) a AS SEQUENCE:
352 RZ(%param1) a
353 RX(pi/2) a
354 RZ(%param1) a
355
356seq2(pi, pi/2) 0 1
357";
358 const EXPECTED_QUIL: &str = r"
359RZ(pi) 0
360RX(pi/2) 0
361RZ(pi) 0
362RZ(pi/2) 1
363RX(pi/2) 1
364RZ(pi/2) 1
365";
366 let source_map_entry_builders = vec![build_source_map_entry(
367 0,
368 DefGateSequenceExpansionBuilder::new(
369 "seq2",
370 &["param1", "param2"],
371 &["a", "b"],
372 0..6,
373 vec![
374 build_source_map_entry(
375 0,
376 DefGateSequenceExpansionBuilder::new(
377 "seq1",
378 &["param1"],
379 &["a"],
380 0..3,
381 vec![
382 build_source_map_entry_copy(0, 0),
383 build_source_map_entry_copy(1, 1),
384 build_source_map_entry_copy(2, 2),
385 ],
386 ),
387 ),
388 build_source_map_entry(
389 1,
390 DefGateSequenceExpansionBuilder::new(
391 "seq1",
392 &["param1"],
393 &["a"],
394 3..6,
395 vec![
396 build_source_map_entry_copy(0, 0),
397 build_source_map_entry_copy(1, 1),
398 build_source_map_entry_copy(2, 2),
399 ],
400 ),
401 ),
402 ],
403 ),
404 )];
405 Self {
406 program: QUIL,
407 filter: Box::new(|_| true),
408 expected: Ok(EXPECTED_QUIL),
409 source_map_entry_builders,
410 }
411 }
412
413 #[expect(clippy::too_many_lines)]
414 fn triple_recursize() -> Self {
415 const QUIL: &str = r"
416DEFGATE some_u2_cycle(%param1, %param2, %param3, %param4, %param5, %param6) a b AS SEQUENCE:
417 pmw3(%param1, %param2, %param3) a
418 pmw3(%param4, %param5, %param6) b
419
420DEFGATE pmw3(%param1, %param2, %param3) a AS SEQUENCE:
421 pmw(%param1) a
422 pmw(%param2) a
423 pmw(%param3) a
424
425DEFGATE pmw(%param1) a AS SEQUENCE:
426 RZ(%param1) a
427 RX(pi/2) a
428 RZ(-%param1) a
429
430some_u2_cycle(-pi, -pi/2, -pi/4, pi/4, pi/2, pi) 0 1
431";
432 const EXPECTED_QUIL: &str = r"
433RZ(-pi) 0
434RX(pi/2) 0
435RZ(-(-pi)) 0
436RZ(-pi/2) 0
437RX(pi/2) 0
438RZ(-(-pi/2)) 0
439RZ(-pi/4) 0
440RX(pi/2) 0
441RZ(-(-pi/4)) 0
442
443RZ(pi/4) 1
444RX(pi/2) 1
445RZ(-(pi/4)) 1
446RZ(pi/2) 1
447RX(pi/2) 1
448RZ(-(pi/2)) 1
449RZ(pi) 1
450RX(pi/2) 1
451RZ(-(pi)) 1
452";
453 let source_map_entry_builders = vec![build_source_map_entry(
454 0,
455 DefGateSequenceExpansionBuilder::new(
456 "some_u2_cycle",
457 &["param1", "param2", "param3", "param4", "param5", "param6"],
458 &["a", "b"],
459 0..18,
460 vec![
461 build_source_map_entry(
462 0,
463 DefGateSequenceExpansionBuilder::new(
464 "pmw3",
465 &["param1", "param2", "param3"],
466 &["a"],
467 0..9,
468 vec![
469 build_source_map_entry(
470 0,
471 DefGateSequenceExpansionBuilder::new(
472 "pmw",
473 &["param1"],
474 &["a"],
475 0..3,
476 vec![
477 build_source_map_entry_copy(0, 0),
478 build_source_map_entry_copy(1, 1),
479 build_source_map_entry_copy(2, 2),
480 ],
481 ),
482 ),
483 build_source_map_entry(
484 1,
485 DefGateSequenceExpansionBuilder::new(
486 "pmw",
487 &["param1"],
488 &["a"],
489 3..6,
490 vec![
491 build_source_map_entry_copy(0, 0),
492 build_source_map_entry_copy(1, 1),
493 build_source_map_entry_copy(2, 2),
494 ],
495 ),
496 ),
497 build_source_map_entry(
498 2,
499 DefGateSequenceExpansionBuilder::new(
500 "pmw",
501 &["param1"],
502 &["a"],
503 6..9,
504 vec![
505 build_source_map_entry_copy(0, 0),
506 build_source_map_entry_copy(1, 1),
507 build_source_map_entry_copy(2, 2),
508 ],
509 ),
510 ),
511 ],
512 ),
513 ),
514 build_source_map_entry(
515 1,
516 DefGateSequenceExpansionBuilder::new(
517 "pmw3",
518 &["param1", "param2", "param3"],
519 &["a"],
520 9..18,
521 vec![
522 build_source_map_entry(
523 0,
524 DefGateSequenceExpansionBuilder::new(
525 "pmw",
526 &["param1"],
527 &["a"],
528 0..3,
529 vec![
530 build_source_map_entry_copy(0, 0),
531 build_source_map_entry_copy(1, 1),
532 build_source_map_entry_copy(2, 2),
533 ],
534 ),
535 ),
536 build_source_map_entry(
537 1,
538 DefGateSequenceExpansionBuilder::new(
539 "pmw",
540 &["param1"],
541 &["a"],
542 3..6,
543 vec![
544 build_source_map_entry_copy(0, 0),
545 build_source_map_entry_copy(1, 1),
546 build_source_map_entry_copy(2, 2),
547 ],
548 ),
549 ),
550 build_source_map_entry(
551 2,
552 DefGateSequenceExpansionBuilder::new(
553 "pmw",
554 &["param1"],
555 &["a"],
556 6..9,
557 vec![
558 build_source_map_entry_copy(0, 0),
559 build_source_map_entry_copy(1, 1),
560 build_source_map_entry_copy(2, 2),
561 ],
562 ),
563 ),
564 ],
565 ),
566 ),
567 ],
568 ),
569 )];
570 Self {
571 program: QUIL,
572 filter: Box::new(|_| true),
573 expected: Ok(EXPECTED_QUIL),
574 source_map_entry_builders,
575 }
576 }
577
578 fn unexpanded_instructions() -> Self {
580 const QUIL: &str = r"
581DEFGATE seq2(%param1, %param2) a b AS SEQUENCE:
582 X a
583 seq1(%param2) b
584 H b
585 ISWAP a b
586
587DEFGATE seq1(%param1) a AS SEQUENCE:
588 RZ(%param1) a
589 RX(pi/2) a
590 RZ(%param1) a
591
592ISWAP 0 1
593seq2(pi, pi/2) 0 1
594MEASURE 0 ro[0]
595MEASURE 1 ro[1]
596";
597 const EXPECTED_QUIL: &str = r"
598ISWAP 0 1
599X 0
600RZ(pi/2) 1
601RX(pi/2) 1
602RZ(pi/2) 1
603H 1
604ISWAP 0 1
605MEASURE 0 ro[0]
606MEASURE 1 ro[1]
607";
608 let source_map_entry_builders = vec![
609 build_source_map_entry(0, ExpansionResult::Unmodified(InstructionIndex(0))),
610 build_source_map_entry(
611 1,
612 DefGateSequenceExpansionBuilder::new(
613 "seq2",
614 &["param1", "param2"],
615 &["a", "b"],
616 1..7,
617 vec![
618 build_source_map_entry_copy(0, 0),
619 build_source_map_entry(
620 1,
621 DefGateSequenceExpansionBuilder::new(
622 "seq1",
623 &["param1"],
624 &["a"],
625 1..4,
626 vec![
627 build_source_map_entry_copy(0, 0),
628 build_source_map_entry_copy(1, 1),
629 build_source_map_entry_copy(2, 2),
630 ],
631 ),
632 ),
633 build_source_map_entry_copy(2, 4),
634 build_source_map_entry_copy(3, 5),
635 ],
636 ),
637 ),
638 build_source_map_entry_copy(2, 7),
639 build_source_map_entry_copy(3, 8),
640 ];
641 Self {
642 program: QUIL,
643 filter: Box::new(|_| true),
644 expected: Ok(EXPECTED_QUIL),
645 source_map_entry_builders,
646 }
647 }
648
649 fn unused_instruction() -> Self {
655 const QUIL: &str = r"
656DEFGATE seq1(%param1) a b AS SEQUENCE:
657 RZ(%param1) a
658 RX(pi/2) a
659 RZ(%param1) a
660
661seq1(pi) 0 1
662";
663 const EXPECTED_QUIL: &str = r"
664RZ(pi) 0
665RX(pi/2) 0
666RZ(pi) 0
667";
668 let source_map_entry_builders = vec![build_source_map_entry(
669 0,
670 DefGateSequenceExpansionBuilder::new(
671 "seq1",
672 &["param1"],
673 &["a", "b"],
674 0..3,
675 vec![
676 build_source_map_entry_copy(0, 0),
677 build_source_map_entry_copy(1, 1),
678 build_source_map_entry_copy(2, 2),
679 ],
680 ),
681 )];
682 Self {
683 program: QUIL,
684 filter: Box::new(|_| true),
685 expected: Ok(EXPECTED_QUIL),
686 source_map_entry_builders,
687 }
688 }
689
690 fn filtered_sequence() -> Self {
693 const QUIL: &str = r"
694DEFGATE seq1(%param1) a AS SEQUENCE:
695 RZ(%param1) a
696 RX(pi/2) a
697 RZ(%param1) a
698
699DEFGATE seq2(%param1) a AS SEQUENCE:
700 X a
701
702seq1(pi) 0
703seq2(pi/2) 0
704";
705 const EXPECTED_QUIL: &str = r"
706RZ(pi) 0
707RX(pi/2) 0
708RZ(pi) 0
709seq2(pi/2) 0
710";
711 let source_map_entry_builders = vec![
712 build_source_map_entry(
713 0,
714 DefGateSequenceExpansionBuilder::new(
715 "seq1",
716 &["param1"],
717 &["a"],
718 0..3,
719 vec![
720 build_source_map_entry_copy(0, 0),
721 build_source_map_entry_copy(1, 1),
722 build_source_map_entry_copy(2, 2),
723 ],
724 ),
725 ),
726 build_source_map_entry_copy(1, 3),
727 ];
728 Self {
729 program: QUIL,
730 filter: Box::new(|k| k == "seq1"),
731 expected: Ok(EXPECTED_QUIL),
732 source_map_entry_builders,
733 }
734 }
735
736 fn error_parameter_count() -> Self {
737 const QUIL: &str = r"
738DEFGATE seq1(%param1) a AS SEQUENCE:
739 RZ(%param1) a
740seq1() 0
741";
742 let expected = Err(DefGateSequenceExpansionError::ParameterCount {
743 expected: 1,
744 found: 0,
745 });
746 Self {
747 program: QUIL,
748 filter: Box::new(|_| true),
749 expected,
750 source_map_entry_builders: vec![],
751 }
752 }
753
754 fn error_cyclic_sequence_gate_definition() -> Self {
755 const QUIL: &str = r"
756DEFGATE seq1(%param1) a AS SEQUENCE:
757 seq2(%param1) a
758
759DEFGATE seq2(%param1) a AS SEQUENCE:
760 seq3(%param1) a
761
762DEFGATE seq3(%param1) a AS SEQUENCE:
763 seq1(%param1) a
764
765seq1(pi) 0
766";
767 let expected = Err(DefGateSequenceExpansionError::CyclicSequenceGateDefinition(
768 vec!["seq1".to_string(), "seq2".to_string(), "seq3".to_string()],
769 ));
770 Self {
771 program: QUIL,
772 filter: Box::new(|_| true),
773 expected,
774 source_map_entry_builders: vec![],
775 }
776 }
777
778 fn error_qubit_count() -> Self {
779 const QUIL: &str = r"
780DEFGATE seq1(%param1) a AS SEQUENCE:
781 RZ(%param1) a
782
783seq1(pi/2) 0 1
784";
785 let expected = Err(DefGateSequenceExpansionError::QubitCount {
786 expected: 1,
787 found: 2,
788 });
789 Self {
790 program: QUIL,
791 filter: Box::new(|_| true),
792 expected,
793 source_map_entry_builders: vec![],
794 }
795 }
796
797 fn error_gate_qubit_argument() -> Self {
798 const QUIL: &str = r"
799DEFGATE seq1(%param1) a AS SEQUENCE:
800 RZ(%param1) a
801
802seq1(pi/2) %q1
803";
804 let expected = Err(DefGateSequenceExpansionError::NonFixedQubitArgument(
805 crate::instruction::Qubit::Variable("q1".to_string()),
806 ));
807 Self {
808 program: QUIL,
809 filter: Box::new(|_| true),
810 expected,
811 source_map_entry_builders: vec![],
812 }
813 }
814
815 fn error_gate_modifiers_unsupported() -> Self {
816 const QUIL: &str = r"
817DEFGATE seq1(%param1) a AS SEQUENCE:
818 RZ(%param1) a
819
820
821DAGGER seq1(pi/2) 0
822";
823 let expected = Err(DefGateSequenceExpansionError::GateModifiersUnsupported(
824 vec![crate::instruction::GateModifier::Dagger],
825 ));
826 Self {
827 program: QUIL,
828 filter: Box::new(|_| true),
829 expected,
830 source_map_entry_builders: vec![],
831 }
832 }
833 }
834
835 #[rstest]
836 #[case::simple_1q_expansions(DefGateSequenceExpansionTestCase::simple_1q_expansions())]
837 #[case::triple_recursize(DefGateSequenceExpansionTestCase::triple_recursize())]
838 #[case::unexpanded_instructions(DefGateSequenceExpansionTestCase::unexpanded_instructions())]
839 #[case::unused_instruction(DefGateSequenceExpansionTestCase::unused_instruction())]
840 #[case::filtered_sequence(DefGateSequenceExpansionTestCase::filtered_sequence())]
841 #[case::error_qubit_count(DefGateSequenceExpansionTestCase::error_qubit_count())]
842 #[case::error_gate_qubit_argument(DefGateSequenceExpansionTestCase::error_parameter_count())]
843 #[case::error_gate_qubit_argument(DefGateSequenceExpansionTestCase::error_gate_qubit_argument())]
844 #[case::error_gate_modifiers_unsupported(
845 DefGateSequenceExpansionTestCase::error_gate_modifiers_unsupported()
846 )]
847 #[case::error_cyclic_sequence_gate_definition(
848 DefGateSequenceExpansionTestCase::error_cyclic_sequence_gate_definition()
849 )]
850 fn test_defgate_sequence_expansion(#[case] test_case: DefGateSequenceExpansionTestCase) {
851 let program =
852 crate::Program::from_str(test_case.program).expect("must be a valid Quil program");
853 let program_expansion = ProgramDefGateSequenceExpander {
854 gate_definitions: &program.gate_definitions,
855 filter: &test_case.filter,
856 };
857 let result = program_expansion.expand_with_source_map(&program.instructions);
858
859 match (&test_case.expected, result) {
860 (Ok(expected), Ok(result)) => {
861 let expected_program =
862 Program::from_str(expected).expect("expected program must be valid Quil");
863 let mut actual_program = Program::new();
864 actual_program.add_instructions(result.instructions);
865
866 pretty_assertions::assert_eq!(expected_program, actual_program);
867 pretty_assertions::assert_eq!(test_case.to_source_map(), result.source_map);
868
869 let actual_program_without_source_map = Program::from_instructions(
870 program_expansion
871 .expand(&program.instructions)
872 .expect("expansion without source map should succeed"),
873 );
874 pretty_assertions::assert_eq!(expected_program, actual_program_without_source_map);
875 }
876 (Ok(expected), Err(e)) => {
877 panic!("Expected instructions:\n\n{expected:?}\n\ngot error:\n\n{e:?}");
878 }
879 (Err(expected), Ok(result)) => {
880 panic!(
881 "Expected error:\n\n{expected:?}\n\ngot:\n\n{:?}",
882 result.instructions
883 );
884 }
885 (Err(expected), Err(found)) => {
886 pretty_assertions::assert_eq!(*expected, found);
887 }
888 }
889 }
890
891 struct GateSignatureBuilder {
892 gate_name: String,
893 gate_parameters: Vec<String>,
894 gate_qubits: Vec<String>,
895 }
896
897 impl GateSignatureBuilder {
898 fn new(
899 gate_name: &'static str,
900 gate_parameters: &'static [&'static str],
901 gate_qubits: &'static [&'static str],
902 ) -> Self {
903 Self {
904 gate_name: gate_name.to_string(),
905 gate_parameters: gate_parameters.iter().map(|&s| s.to_string()).collect(),
906 gate_qubits: gate_qubits.iter().map(|&s| s.to_string()).collect(),
907 }
908 }
909
910 fn build(&self) -> GateSignature<'_> {
911 GateSignature::try_new(
912 &self.gate_name,
913 &self.gate_parameters,
914 &self.gate_qubits,
915 crate::instruction::GateType::Sequence,
916 )
917 .expect("must be a valid gate signature")
918 }
919 }
920
921 struct DefGateSequenceExpansionBuilder {
922 signature: GateSignatureBuilder,
923 range: Range<usize>,
924 nested_expansions:
925 Vec<SourceMapEntry<InstructionIndex, ExpansionResult<DefGateSequenceExpansionBuilder>>>,
926 }
927
928 impl DefGateSequenceExpansionBuilder {
929 fn new(
930 gate_name: &'static str,
931 gate_parameters: &'static [&'static str],
932 gate_qubits: &'static [&'static str],
933 range: Range<usize>,
934 entries: Vec<
935 SourceMapEntry<InstructionIndex, ExpansionResult<DefGateSequenceExpansionBuilder>>,
936 >,
937 ) -> ExpansionResult<Self> {
938 ExpansionResult::Rewritten(Self {
939 signature: GateSignatureBuilder::new(gate_name, gate_parameters, gate_qubits),
940 range,
941 nested_expansions: entries,
942 })
943 }
944
945 fn build(&self) -> ExpansionResult<DefGateSequenceExpansion<'_>> {
946 let entries: Vec<_> = self
947 .nested_expansions
948 .iter()
949 .map(|entry| SourceMapEntry {
950 source_location: entry.source_location,
951 target_location: match entry.target_location() {
952 ExpansionResult::Rewritten(expansion) => expansion.build(),
953 ExpansionResult::Unmodified(index) => ExpansionResult::Unmodified(*index),
954 },
955 })
956 .collect();
957 ExpansionResult::Rewritten(DefGateSequenceExpansion {
958 source_signature: self.signature.build(),
959 range: InstructionIndex(self.range.start)..InstructionIndex(self.range.end),
960 nested_expansions: SourceMap { entries },
961 })
962 }
963 }
964
965 fn build_source_map_entry(
966 source_location: usize,
967 target_location: ExpansionResult<DefGateSequenceExpansionBuilder>,
968 ) -> SourceMapEntry<InstructionIndex, ExpansionResult<DefGateSequenceExpansionBuilder>> {
969 SourceMapEntry {
970 source_location: InstructionIndex(source_location),
971 target_location,
972 }
973 }
974
975 fn build_source_map_entry_copy(
976 source_location: usize,
977 target_location: usize,
978 ) -> SourceMapEntry<InstructionIndex, ExpansionResult<DefGateSequenceExpansionBuilder>> {
979 build_source_map_entry(
980 source_location,
981 ExpansionResult::Unmodified(InstructionIndex(target_location)),
982 )
983 }
984}