@@ -53,6 +53,46 @@ def _manhattan_distance(qubit1: 'cirq.GridQubit', qubit2: 'cirq.GridQubit') -> i
5353 return abs (qubit1 .row - qubit2 .row ) + abs (qubit1 .col - qubit2 .col )
5454
5555
56+ def qubits_and_pairs (
57+ sampler : 'cirq.Sampler' ,
58+ qubits : Optional [Sequence ['cirq.GridQubit' ]] = None ,
59+ pairs : Optional [Sequence [tuple ['cirq.GridQubit' , 'cirq.GridQubit' ]]] = None ,
60+ ) -> Tuple [Sequence ['cirq.GridQubit' ], Sequence [tuple ['cirq.GridQubit' , 'cirq.GridQubit' ]]]:
61+ """Extract qubits and pairs from sampler.
62+
63+
64+ If qubits are not provided, then they are extracted from the pairs (if given) or the sampler.
65+ If pairs are not provided then all pairs of adjacent qubits are used.
66+
67+ Args:
68+ sampler: The quantum engine or simulator to run the circuits.
69+ qubits: Optional list of qubits.
70+ pairs: Optional list of pair to use.
71+
72+ Returns:
73+ - Qubits to use.
74+ - Pairs of qubits to use.
75+
76+ Raises:
77+ ValueError: If qubits are not specified and can't be deduced from other arguments.
78+ """
79+ if qubits is None :
80+ if pairs is None :
81+ qubits = _grid_qubits_for_sampler (sampler )
82+ if qubits is None :
83+ raise ValueError ("Couldn't determine qubits from sampler. Please specify them." )
84+ else :
85+ qubits_set = set (itertools .chain (* pairs ))
86+ qubits = list (qubits_set )
87+
88+ if pairs is None :
89+ pairs = [
90+ pair for pair in itertools .combinations (qubits , 2 ) if _manhattan_distance (* pair ) == 1
91+ ]
92+
93+ return qubits , pairs
94+
95+
5696@dataclass (frozen = True )
5797class TwoQubitXEBResult :
5898 """Results from an XEB experiment."""
@@ -359,6 +399,7 @@ def parallel_xeb_workflow(
359399 cycle_depths : Sequence [int ] = (5 , 25 , 50 , 100 , 200 , 300 ),
360400 random_state : 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None ,
361401 ax : Optional [plt .Axes ] = None ,
402+ pairs : Optional [Sequence [tuple ['cirq.GridQubit' , 'cirq.GridQubit' ]]] = None ,
362403 pool : Optional ['multiprocessing.pool.Pool' ] = None ,
363404 ** plot_kwargs ,
364405) -> Tuple [pd .DataFrame , Sequence ['cirq.Circuit' ], pd .DataFrame ]:
@@ -375,6 +416,7 @@ def parallel_xeb_workflow(
375416 random_state: The random state to use.
376417 ax: the plt.Axes to plot the device layout on. If not given,
377418 no plot is created.
419+ pairs: Pairs to use. If not specified, use all pairs between adjacent qubits.
378420 pool: An optional multiprocessing pool.
379421 **plot_kwargs: Arguments to be passed to 'plt.Axes.plot'.
380422
@@ -391,14 +433,8 @@ def parallel_xeb_workflow(
391433 """
392434 rs = value .parse_random_state (random_state )
393435
394- if qubits is None :
395- qubits = _grid_qubits_for_sampler (sampler )
396- if qubits is None :
397- raise ValueError ("Couldn't determine qubits from sampler. Please specify them." )
398-
399- graph = nx .Graph (
400- pair for pair in itertools .combinations (qubits , 2 ) if _manhattan_distance (* pair ) == 1
401- )
436+ qubits , pairs = qubits_and_pairs (sampler , qubits , pairs )
437+ graph = nx .Graph (pairs )
402438
403439 if ax is not None :
404440 nx .draw_networkx (graph , pos = {q : (q .row , q .col ) for q in qubits }, ax = ax )
@@ -445,6 +481,7 @@ def parallel_two_qubit_xeb(
445481 cycle_depths : Sequence [int ] = (5 , 25 , 50 , 100 , 200 , 300 ),
446482 random_state : 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None ,
447483 ax : Optional [plt .Axes ] = None ,
484+ pairs : Optional [Sequence [tuple ['cirq.GridQubit' , 'cirq.GridQubit' ]]] = None ,
448485 ** plot_kwargs ,
449486) -> TwoQubitXEBResult :
450487 """A convenience method that runs the full XEB workflow.
@@ -460,6 +497,7 @@ def parallel_two_qubit_xeb(
460497 random_state: The random state to use.
461498 ax: the plt.Axes to plot the device layout on. If not given,
462499 no plot is created.
500+ pairs: Pairs to use. If not specified, use all pairs between adjacent qubits.
463501 **plot_kwargs: Arguments to be passed to 'plt.Axes.plot'.
464502 Returns:
465503 A TwoQubitXEBResult object representing the results of the experiment.
@@ -469,6 +507,7 @@ def parallel_two_qubit_xeb(
469507 fids , * _ = parallel_xeb_workflow (
470508 sampler = sampler ,
471509 qubits = qubits ,
510+ pairs = pairs ,
472511 entangling_gate = entangling_gate ,
473512 n_repetitions = n_repetitions ,
474513 n_combinations = n_combinations ,
@@ -493,6 +532,7 @@ def run_rb_and_xeb(
493532 depths_xeb : Sequence [int ] = (5 , 25 , 50 , 100 , 200 , 300 ),
494533 xeb_combinations : int = 10 ,
495534 random_state : 'cirq.RANDOM_STATE_OR_SEED_LIKE' = None ,
535+ pairs : Optional [Sequence [tuple ['cirq.GridQubit' , 'cirq.GridQubit' ]]] = None ,
496536) -> InferredXEBResult :
497537 """A convenience method that runs both RB and XEB workflows.
498538
@@ -506,6 +546,7 @@ def run_rb_and_xeb(
506546 depths_xeb: The cycle depths to use for XEB.
507547 xeb_combinations: The number of combinations to generate for XEB.
508548 random_state: The random state to use.
549+ pairs: Pairs to use. If not specified, use all pairs between adjacent qubits.
509550
510551 Returns:
511552 An InferredXEBResult object representing the results of the experiment.
@@ -514,10 +555,7 @@ def run_rb_and_xeb(
514555 ValueError: If qubits are not specified and the sampler has no device.
515556 """
516557
517- if qubits is None :
518- qubits = _grid_qubits_for_sampler (sampler )
519- if qubits is None :
520- raise ValueError ("Couldn't determine qubits from sampler. Please specify them." )
558+ qubits , pairs = qubits_and_pairs (sampler , qubits , pairs )
521559
522560 rb = parallel_single_qubit_randomized_benchmarking (
523561 sampler = sampler ,
@@ -530,6 +568,7 @@ def run_rb_and_xeb(
530568 xeb = parallel_two_qubit_xeb (
531569 sampler = sampler ,
532570 qubits = qubits ,
571+ pairs = pairs ,
533572 entangling_gate = entangling_gate ,
534573 n_repetitions = repetitions ,
535574 n_circuits = num_circuits ,
0 commit comments