@@ -60,6 +60,13 @@ def __init__(
6060 ``max_singular_values`` and ``max_truncation_err``.
6161 :type split: Optional[Dict[str, Any]]
6262 """
63+
64+ super ().__init__ (
65+ nqubits = nqubits , inputs = inputs , mps_inputs = mps_inputs , split = split
66+ )
67+ self .calibrations = []
68+ self .calibration_invokes = []
69+
6370 self .inputs = inputs
6471 self .mps_inputs = mps_inputs
6572 self .split = split
@@ -112,6 +119,55 @@ def __init__(
112119 self ._qir : List [Dict [str , Any ]] = []
113120 self ._extra_qir : List [Dict [str , Any ]] = []
114121
122+
123+ def def_calibration (
124+ self , name : str , parameters : List [str ], instructions : List [Dict ]
125+ ) -> None :
126+ self .calibrations .append ({
127+ "name" : name ,
128+ "parameters" : parameters ,
129+ "instructions" : instructions
130+ })
131+
132+ def add_calibration (
133+ self , name : str , parameters : List [str ]
134+ ) -> None :
135+ self .calibration_invokes .append ({
136+ "name" : name ,
137+ "parameters" : parameters
138+ })
139+
140+ def to_tqasm (self ) -> str :
141+ qasm_lines = []
142+ qasm_lines .append ("TQASM 0.2;" )
143+ qasm_lines .append (f"QREG q[{ self ._nqubits } ];" )
144+
145+ for gate in self ._qir :
146+ gname = gate ["name" ]
147+ targets = ", " .join (f"q[{ i } ]" for i in gate ["target" ])
148+ qasm_lines .append (f"{ gname } { targets } ;" )
149+
150+ for cal in getattr (self , "calibrations" , []):
151+ pname = ", " .join (cal ["parameters" ])
152+ qasm_lines .append (f"\n defcal { cal ['name' ]} { pname } {{" )
153+ for inst in cal ["instructions" ]:
154+ if inst ["type" ] == "frame" :
155+ qasm_lines .append (f" frame { inst ['frame' ]} = newframe({ inst ['qubit' ]} );" )
156+ elif inst ["type" ] == "play" :
157+ args_str = ", " .join (str (x ) for x in inst ["args" ])
158+ wf_type = inst ["waveform_type" ]
159+ qasm_lines .append (f" play({ inst ['frame' ]} , { wf_type } ({ args_str } ));" )
160+ qasm_lines .append ("}" )
161+
162+ for cal in getattr (self , "calibration_invokes" , []):
163+ pname = ", " .join (cal ["parameters" ])
164+ qasm_lines .append (f"\n { cal ['name' ]} { pname } ;" )
165+
166+ return "\n " .join (qasm_lines )
167+
168+ def calibrate (self , name : str , parameters : List ["Param" ]) -> "DefcalBuilder" :
169+ return DefcalBuilder (self , name , parameters )
170+
115171 def replace_mps_inputs (self , mps_inputs : QuOperator ) -> None :
116172 """
117173 Replace the input state in MPS representation while keep the circuit structure unchanged.
@@ -998,3 +1054,46 @@ def expectation(
9981054 else :
9991055 den = 1.0
10001056 return num / den
1057+
1058+ class Param :
1059+ def __init__ (self , name : str ):
1060+ self .name = name
1061+
1062+ class DefcalBuilder :
1063+ def __init__ (self , circuit , name : str , parameters : List ["Param" ]):
1064+ self .circuit = circuit
1065+ self .name = name
1066+ self .parameters = parameters
1067+ self .instructions = []
1068+
1069+ def new_frame (self , frame_name : str , param : "Param" ):
1070+ self .instructions .append ({
1071+ "type" : "frame" ,
1072+ "frame" : frame_name ,
1073+ "qubit" : param .name ,
1074+ })
1075+ return self
1076+
1077+ def play (self , frame_name : str , waveform : Any , start_time : int = None ):
1078+ if not hasattr (waveform , "__dataclass_fields__" ):
1079+ raise TypeError ("Unsupported waveform type" )
1080+
1081+ waveform_type = waveform .qasm_name ()
1082+ args = waveform .to_args ()
1083+ if start_time is not None :
1084+ args = [start_time ] + args
1085+
1086+ self .instructions .append ({
1087+ "type" : "play" ,
1088+ "frame" : frame_name ,
1089+ "waveform_type" : waveform_type ,
1090+ "args" : args ,
1091+ })
1092+ return self
1093+
1094+ def build (self ):
1095+ self .circuit .def_calibration (
1096+ name = self .name ,
1097+ parameters = [p .name for p in self .parameters ],
1098+ instructions = self .instructions ,
1099+ )
0 commit comments