@@ -187,8 +187,12 @@ fn recognize_instruction_type(
187187 } else if ControlFlowType :: from_str ( name) . is_ok ( )
188188 || matches ! (
189189 name,
190- // We don't handle old style SwitchCaseOp in rust yet
191- "IfElseOp" | "WhileLoopOp" | "ForLoopOp" | "BreakLoopOp" | "ContinueLoopOp"
190+ "IfElseOp"
191+ | "WhileLoopOp"
192+ | "ForLoopOp"
193+ | "BreakLoopOp"
194+ | "ContinueLoopOp"
195+ | "SwitchCaseOp"
192196 )
193197 {
194198 InstructionType :: ControlFlow
@@ -597,24 +601,52 @@ fn unpack_control_flow(
597601 }
598602 ControlFlowType :: SwitchCase => {
599603 let mut instruction_values = get_instruction_values ( instruction, qpy_data) ?;
600- if instruction_values. len ( ) < 3 {
601- return Err ( QpyError :: MissingData ( format ! (
602- "Switch case instruction has {} parameters, expected at least 3 (target, label_spec, cases)" ,
603- instruction_values. len( )
604- ) ) ) ;
605- }
606- param_values = instruction_values. split_off ( 3 ) ;
607- let mut iter = instruction_values. into_iter ( ) ;
608- let ( ( target_value, label_spec_value) , cases_value) = iter
609- . next ( )
610- . zip ( iter. next ( ) )
611- . zip ( iter. next ( ) )
612- . ok_or_else ( || {
613- QpyError :: MissingData (
614- "Switch case instruction missing some of its parameters" . to_string ( ) ,
615- )
616- } ) ?;
617- let target = match target_value {
604+ let ( target_value, case_label_list) = if instruction_values. len ( ) < 3 {
605+ // we follow the python way of storing switch params
606+ // the first param is the target, the next param is the cases specifier
607+ // the cases specifier is a list of pairs (tuples)
608+ // the second element in each pair is the subcircuit for this case
609+ // the first element is the list of the case labels, or a single case label
610+ // or the special default case label
611+ let [ target_value, cases, ..] = & instruction_values[ ..] else {
612+ return Err ( QpyError :: MissingData (
613+ "Switch case requires at least 2 parameters" . to_string ( ) ,
614+ ) ) ;
615+ } ;
616+ let mut case_label_list = Vec :: new ( ) ;
617+ for case in cases. as_slice ( ) . ok_or ( QpyError :: InvalidInstruction (
618+ "bad parameters for switch statement" . to_string ( ) ,
619+ ) ) ? {
620+ let [ case_labels, case_circuit, ..] =
621+ & case. as_slice ( ) . ok_or ( QpyError :: InvalidInstruction (
622+ "bad parameters for switch statement" . to_string ( ) ,
623+ ) ) ?
624+ else {
625+ return Err ( QpyError :: InvalidInstruction (
626+ "bad parameters for switch statement" . to_string ( ) ,
627+ ) ) ;
628+ } ;
629+ param_values. push ( case_circuit. clone ( ) ) ;
630+ case_label_list. push ( case_labels. clone ( ) ) ;
631+ }
632+ ( target_value, case_label_list)
633+ } else {
634+ param_values = instruction_values. split_off ( 3 ) ;
635+ let [ target_value, label_spec_value, ..] = & instruction_values[ ..] else {
636+ return Err ( QpyError :: MissingData (
637+ "Switch case requires at least 3 parameters" . to_string ( ) ,
638+ ) ) ;
639+ } ;
640+ (
641+ target_value,
642+ label_spec_value. to_vec ( ) . ok_or_else ( || {
643+ QpyError :: InvalidInstruction (
644+ "bad parameters for switch statement" . to_string ( ) ,
645+ )
646+ } ) ?,
647+ )
648+ } ;
649+ let target = match target_value. clone ( ) {
618650 GenericValue :: Expression ( exp) => Ok ( SwitchTarget :: Expr ( exp) ) ,
619651 GenericValue :: Register ( ParamRegisterValue :: Register ( reg) ) => {
620652 Ok ( SwitchTarget :: Register ( reg) )
@@ -627,45 +659,34 @@ fn unpack_control_flow(
627659 ) ) ,
628660 } ?;
629661
630- let GenericValue :: Tuple ( label_spec_tuple_tuple) = label_spec_value else {
631- return Err ( QpyError :: InvalidInstruction (
632- "could not identify switch case label spec" . to_string ( ) ,
633- ) ) ;
634- } ;
635- let label_spec = label_spec_tuple_tuple
636- . iter ( )
637- . map ( |label_spec_tuple_tuple_element| -> Result < _ , QpyError > {
638- let GenericValue :: Tuple ( label_spec_tuple) = label_spec_tuple_tuple_element
639- else {
640- return Err ( QpyError :: InvalidInstruction (
662+ // now split the zipped cases: move the circuits to params, keep the labels for further processing
663+ let mut label_spec = Vec :: new ( ) ;
664+ for case_labels in case_label_list {
665+ // label spec handling
666+ let GenericValue :: Tuple ( label_spec_element_tuple) = case_labels else {
667+ return Err ( QpyError :: InvalidInstruction (
668+ "could not identify switch case label spec" . to_string ( ) ,
669+ ) ) ;
670+ } ;
671+ let label_spec_element = label_spec_element_tuple
672+ . iter ( )
673+ . map ( |label_spec_element| match label_spec_element. as_le ( ) {
674+ GenericValue :: CaseDefault => Ok ( CaseSpecifier :: Default ) ,
675+ GenericValue :: BigInt ( value) => Ok ( CaseSpecifier :: Uint ( value. clone ( ) ) ) ,
676+ GenericValue :: Int64 ( value) => {
677+ Ok ( CaseSpecifier :: Uint ( BigUint :: from ( value as u64 ) ) )
678+ }
679+ _ => Err ( QpyError :: InvalidInstruction (
641680 "could not identify switch case label spec" . to_string ( ) ,
642- ) ) ;
643- } ;
644- label_spec_tuple
645- . iter ( )
646- . map ( |label_spec_element| match label_spec_element {
647- GenericValue :: CaseDefault => Ok ( CaseSpecifier :: Default ) ,
648- GenericValue :: BigInt ( value) => Ok ( CaseSpecifier :: Uint ( value. clone ( ) ) ) ,
649- GenericValue :: Int64 ( value) => {
650- Ok ( CaseSpecifier :: Uint ( BigUint :: from ( * value as u64 ) ) )
651- }
652- _ => Err ( QpyError :: InvalidInstruction (
653- "could not identify switch case label spec" . to_string ( ) ,
654- ) ) ,
655- } )
656- . collect :: < Result < _ , QpyError > > ( )
657- } )
658- . collect :: < Result < _ , QpyError > > ( ) ?;
659- let cases = match cases_value {
660- GenericValue :: Int64 ( value) => Ok ( value as u32 ) ,
661- _ => Err ( QpyError :: InvalidInstruction (
662- "could not identify switch cases" . to_string ( ) ,
663- ) ) ,
664- } ?;
681+ ) ) ,
682+ } )
683+ . collect :: < Result < _ , QpyError > > ( ) ?;
684+ label_spec. push ( label_spec_element) ;
685+ }
665686 ControlFlow :: Switch {
666687 target,
667688 label_spec,
668- cases,
689+ cases : param_values . len ( ) as u32 ,
669690 }
670691 }
671692 } ;
@@ -812,24 +833,6 @@ fn unpack_py_instruction(
812833 // we used the params to construct the loop; they should not be retained as params except the subcircuit
813834 instruction_values. retain ( |value| matches ! ( value, GenericValue :: Circuit ( _) ) ) ;
814835 }
815- if name. as_str ( ) == "SwitchCaseOp" {
816- // switch cases are as the second component of the second parameter
817- // we keep only the circuits and remove everything else from the params
818- if let GenericValue :: Tuple ( cases) = & instruction_values[ 1 ] {
819- instruction_values = cases
820- . iter ( )
821- . map ( |case| -> Result < _ , QpyError > {
822- if let GenericValue :: Tuple ( case_elements) = case {
823- Ok ( case_elements[ 1 ] . clone ( ) )
824- } else {
825- Err ( QpyError :: InvalidInstruction (
826- "Unable to read switch case op" . to_string ( ) ,
827- ) )
828- }
829- } )
830- . collect :: < Result < _ , QpyError > > ( ) ?;
831- }
832- }
833836 gate_class. call1 ( args) ?
834837 }
835838 } ;
0 commit comments