@@ -78,7 +78,7 @@ class CircuitSummary:
7878
7979 def to_dict (self ) -> dict [str , Any ]:
8080 """
81- Convert to dictionary.
81+ Convert to dictionary for serialization .
8282
8383 Returns
8484 -------
@@ -94,7 +94,7 @@ def to_dict(self) -> dict[str, Any]:
9494 "gate_count_multi" : self .gate_count_multi ,
9595 "gate_count_measure" : self .gate_count_measure ,
9696 "gate_count_total" : self .gate_count_total ,
97- "gate_types" : self .gate_types ,
97+ "gate_types" : self .gate_types . copy () ,
9898 "has_parameters" : self .has_parameters ,
9999 "parameter_count" : self .parameter_count ,
100100 "is_clifford" : self .is_clifford ,
@@ -103,13 +103,13 @@ def to_dict(self) -> dict[str, Any]:
103103 }
104104
105105 @classmethod
106- def from_dict (cls , d : dict [str , Any ]) -> CircuitSummary :
106+ def from_dict (cls , data : dict [str , Any ]) -> CircuitSummary :
107107 """
108- Create from dictionary.
108+ Create instance from dictionary.
109109
110110 Parameters
111111 ----------
112- d : dict
112+ data : dict
113113 Dictionary with summary fields.
114114
115115 Returns
@@ -118,24 +118,24 @@ def from_dict(cls, d: dict[str, Any]) -> CircuitSummary:
118118 Reconstructed summary.
119119 """
120120 return cls (
121- num_qubits = int (d .get ("num_qubits" , 0 )),
122- num_clbits = int (d .get ("num_clbits" , 0 )),
123- depth = int (d .get ("depth" , 0 )),
124- gate_count_1q = int (d .get ("gate_count_1q" , 0 )),
125- gate_count_2q = int (d .get ("gate_count_2q" , 0 )),
126- gate_count_multi = int (d .get ("gate_count_multi" , 0 )),
127- gate_count_measure = int (d .get ("gate_count_measure" , 0 )),
128- gate_count_total = int (d .get ("gate_count_total" , 0 )),
129- gate_types = dict (d .get ("gate_types" , {})),
130- has_parameters = bool (d .get ("has_parameters" , False )),
131- parameter_count = int (d .get ("parameter_count" , 0 )),
132- is_clifford = d .get ("is_clifford" ),
133- source_format = CircuitFormat (d .get ("source_format" , "unknown" )),
134- sdk = SDK (d .get ("sdk" , "unknown" )),
121+ num_qubits = int (data .get ("num_qubits" , 0 )),
122+ num_clbits = int (data .get ("num_clbits" , 0 )),
123+ depth = int (data .get ("depth" , 0 )),
124+ gate_count_1q = int (data .get ("gate_count_1q" , 0 )),
125+ gate_count_2q = int (data .get ("gate_count_2q" , 0 )),
126+ gate_count_multi = int (data .get ("gate_count_multi" , 0 )),
127+ gate_count_measure = int (data .get ("gate_count_measure" , 0 )),
128+ gate_count_total = int (data .get ("gate_count_total" , 0 )),
129+ gate_types = dict (data .get ("gate_types" , {})),
130+ has_parameters = bool (data .get ("has_parameters" , False )),
131+ parameter_count = int (data .get ("parameter_count" , 0 )),
132+ is_clifford = data .get ("is_clifford" ),
133+ source_format = CircuitFormat (data .get ("source_format" , "unknown" )),
134+ sdk = SDK (data .get ("sdk" , "unknown" )),
135135 )
136136
137137 def __repr__ (self ) -> str :
138- """Return string representation."""
138+ """Return concise string representation."""
139139 return (
140140 f"CircuitSummary(qubits={ self .num_qubits } , depth={ self .depth } , "
141141 f"gates={ self .gate_count_total } , sdk={ self .sdk .value } )"
@@ -172,7 +172,7 @@ class CircuitDiff:
172172
173173 def to_dict (self ) -> dict [str , Any ]:
174174 """
175- Convert to dictionary.
175+ Convert to dictionary for serialization .
176176
177177 Returns
178178 -------
@@ -181,14 +181,14 @@ def to_dict(self) -> dict[str, Any]:
181181 """
182182 return {
183183 "match" : self .match ,
184- "changes" : self .changes ,
185- "metrics" : self .metrics ,
184+ "changes" : self .changes . copy () ,
185+ "metrics" : self .metrics . copy () ,
186186 "summary_a" : self .summary_a .to_dict (),
187187 "summary_b" : self .summary_b .to_dict (),
188188 }
189189
190190 def __repr__ (self ) -> str :
191- """Return string representation."""
191+ """Return concise string representation."""
192192 status = "match" if self .match else f"{ len (self .changes )} changes"
193193 return f"CircuitDiff({ status } )"
194194
@@ -241,7 +241,7 @@ def summarize_circuit_data(data: CircuitData) -> CircuitSummary:
241241
242242def summarize_circuit (circuit : Any , sdk : SDK | None = None ) -> CircuitSummary :
243243 """
244- Extract summary from SDK-native circuit.
244+ Extract summary from SDK-native circuit object .
245245
246246 Parameters
247247 ----------
@@ -310,6 +310,26 @@ def _detect_sdk_from_circuit(circuit: Any) -> SDK:
310310 )
311311
312312
313+ # =============================================================================
314+ # Diff functions
315+ # =============================================================================
316+
317+
318+ # Label width for aligned diff output
319+ _DIFF_LABEL_WIDTH = 14
320+
321+ # Fields to compare with optional percentage display
322+ _NUMERIC_DIFF_FIELDS = (
323+ ("num_qubits" , "qubits" , False ),
324+ ("num_clbits" , "clbits" , False ),
325+ ("depth" , "depth" , True ),
326+ ("gate_count_1q" , "1Q gates" , True ),
327+ ("gate_count_2q" , "2Q gates" , True ),
328+ ("gate_count_total" , "total gates" , True ),
329+ ("parameter_count" , "parameters" , False ),
330+ )
331+
332+
313333def diff_summaries (
314334 summary_a : CircuitSummary ,
315335 summary_b : CircuitSummary ,
@@ -336,41 +356,26 @@ def diff_summaries(
336356 metrics : dict [str , Any ] = {}
337357
338358 # Compare numeric fields
339- _NUMERIC_FIELDS = (
340- ("num_qubits" , "qubits" , False ),
341- ("num_clbits" , "clbits" , False ),
342- ("depth" , "depth" , True ),
343- ("gate_count_1q" , "1Q gates" , True ),
344- ("gate_count_2q" , "2Q gates" , True ),
345- ("gate_count_total" , "total gates" , True ),
346- ("parameter_count" , "parameters" , False ),
347- )
348-
349- for field_name , label , show_pct in _NUMERIC_FIELDS :
359+ for field_name , label , show_pct in _NUMERIC_DIFF_FIELDS :
350360 val_a = getattr (summary_a , field_name )
351361 val_b = getattr (summary_b , field_name )
352- _compare_numeric (field_name , label , val_a , val_b , show_pct , changes , metrics )
362+ _record_numeric_diff (
363+ field_name , label , val_a , val_b , show_pct , changes , metrics
364+ )
353365
354- # Clifford status change
366+ # Compare Clifford status
355367 if summary_a .is_clifford != summary_b .is_clifford :
368+ label = "is_clifford"
356369 changes .append (
357- f"is_clifford: { summary_a .is_clifford } → { summary_b .is_clifford } "
370+ f"{ label :<{_DIFF_LABEL_WIDTH }} "
371+ f"{ summary_a .is_clifford } => { summary_b .is_clifford } "
358372 )
359373 metrics ["is_clifford_changed" ] = True
360374 metrics ["is_clifford_a" ] = summary_a .is_clifford
361375 metrics ["is_clifford_b" ] = summary_b .is_clifford
362376
363- # Gate type changes
364- types_a = set (summary_a .gate_types .keys ())
365- types_b = set (summary_b .gate_types .keys ())
366-
367- if new_gates := types_b - types_a :
368- changes .append (f"new gate types: { ', ' .join (sorted (new_gates ))} " )
369- metrics ["new_gate_types" ] = sorted (new_gates )
370-
371- if removed_gates := types_a - types_b :
372- changes .append (f"removed gate types: { ', ' .join (sorted (removed_gates ))} " )
373- metrics ["removed_gate_types" ] = sorted (removed_gates )
377+ # Compare gate types
378+ _record_gate_type_diff (summary_a , summary_b , changes , metrics )
374379
375380 logger .debug (
376381 "Compared summaries: %s" ,
@@ -386,7 +391,7 @@ def diff_summaries(
386391 )
387392
388393
389- def _compare_numeric (
394+ def _record_numeric_diff (
390395 metric_key : str ,
391396 label : str ,
392397 val_a : int ,
@@ -395,7 +400,26 @@ def _compare_numeric(
395400 changes : list [str ],
396401 metrics : dict [str , Any ],
397402) -> None :
398- """Compare two numeric values and record changes."""
403+ """
404+ Compare two numeric values and record changes.
405+
406+ Parameters
407+ ----------
408+ metric_key : str
409+ Key for metrics dict.
410+ label : str
411+ Human-readable label.
412+ val_a : int
413+ Baseline value.
414+ val_b : int
415+ Comparison value.
416+ show_pct : bool
417+ Whether to show percentage change.
418+ changes : list of str
419+ List to append change descriptions to.
420+ metrics : dict
421+ Dict to record numeric metrics to.
422+ """
399423 if val_a == val_b :
400424 return
401425
@@ -405,6 +429,42 @@ def _compare_numeric(
405429 if show_pct and val_a > 0 :
406430 pct = (delta / val_a ) * 100
407431 metrics [f"{ metric_key } _delta_pct" ] = pct
408- changes .append (f"{ label } : { val_a } → { val_b } ({ pct :+.1f} %)" )
432+ changes .append (
433+ f"{ label :<{_DIFF_LABEL_WIDTH }} { val_a } => { val_b } ({ pct :+.1f} %)"
434+ )
409435 else :
410- changes .append (f"{ label } : { val_a } → { val_b } " )
436+ changes .append (f"{ label :<{_DIFF_LABEL_WIDTH }} { val_a } => { val_b } " )
437+
438+
439+ def _record_gate_type_diff (
440+ summary_a : CircuitSummary ,
441+ summary_b : CircuitSummary ,
442+ changes : list [str ],
443+ metrics : dict [str , Any ],
444+ ) -> None :
445+ """
446+ Compare gate types between summaries.
447+
448+ Parameters
449+ ----------
450+ summary_a : CircuitSummary
451+ Baseline summary.
452+ summary_b : CircuitSummary
453+ Comparison summary.
454+ changes : list of str
455+ List to append change descriptions to.
456+ metrics : dict
457+ Dict to record gate type changes to.
458+ """
459+ types_a = set (summary_a .gate_types .keys ())
460+ types_b = set (summary_b .gate_types .keys ())
461+
462+ if new_gates := types_b - types_a :
463+ sorted_gates = ", " .join (sorted (new_gates ))
464+ changes .append (f"{ '+ gates' :<{_DIFF_LABEL_WIDTH }} { sorted_gates } " )
465+ metrics ["new_gate_types" ] = sorted (new_gates )
466+
467+ if removed_gates := types_a - types_b :
468+ sorted_gates = ", " .join (sorted (removed_gates ))
469+ changes .append (f"{ '- gates' :<{_DIFF_LABEL_WIDTH }} { sorted_gates } " )
470+ metrics ["removed_gate_types" ] = sorted (removed_gates )
0 commit comments