Skip to content

Commit 67561b0

Browse files
viathorrht
authored andcommitted
Improve consistency between code and docstrings for XEB (quantumlib#4853)
Closes quantumlib#2757. The "exp" suffix may be interpreted as either "experimental" or "expected" (as in "theoretically expected") which causes confusion that led to quantumlib#2757. This PR changes the suffix to "th" (for "theoretical") which happens to be what is already used in the docstring. Also, added some missing docstrings.
1 parent 1abc52c commit 67561b0

File tree

1 file changed

+32
-16
lines changed

1 file changed

+32
-16
lines changed

cirq-core/cirq/experiments/cross_entropy_benchmarking.py

+32-16
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ def cross_entropy_benchmarking(
320320
Then, take the average of $f_{mn}^{meas}$ over all circuit_mn with fixed
321321
n to obtain:
322322
323-
$f_{n} ^ {meas} = (\sum_m f_{mn}^{meas}) / M$
323+
$f_{n}^{meas} = (\sum_m f_{mn}^{meas}) / M$
324324
325325
4) Compute a theoretical XEB function for each circuit_mn:
326326
@@ -332,7 +332,7 @@ def cross_entropy_benchmarking(
332332
Similarly, we then average $f_m^{th}$ over all circuit_mn with fixed n to
333333
obtain:
334334
335-
$f_{n} ^ {th} = (\sum_m f_{mn}^{th}) / M$
335+
$f_{n}^{th} = (\sum_m f_{mn}^{th}) / M$
336336
337337
5) Calculate the XEB fidelity $\alpha_n$ at fixed n:
338338
@@ -383,7 +383,7 @@ def cross_entropy_benchmarking(
383383
# numbers of cycles. The values are 2D arrays with each row being the
384384
# probabilities obtained from a single trial.
385385
probs_meas = {n: np.zeros((num_circuits, 2 ** num_qubits)) for n in cycle_range}
386-
probs_exp = {n: np.zeros((num_circuits, 2 ** num_qubits)) for n in cycle_range}
386+
probs_th = {n: np.zeros((num_circuits, 2 ** num_qubits)) for n in cycle_range}
387387

388388
for k in range(num_circuits):
389389

@@ -402,17 +402,17 @@ def cross_entropy_benchmarking(
402402
# Simulate each circuit with the Cirq simulator to obtain the
403403
# state vector at the end of each circuit, from which the
404404
# theoretically expected bit-string probabilities are obtained.
405-
probs_exp_k: List[np.ndarray] = []
405+
probs_th_k: List[np.ndarray] = []
406406
for circ_k in circuits_k:
407407
res = simulator.simulate(circ_k, qubit_order=qubits)
408408
state_probs = value.state_vector_to_probabilities(np.asarray(res.final_state_vector))
409-
probs_exp_k.append(state_probs)
409+
probs_th_k.append(state_probs)
410410

411411
for i, num_cycle in enumerate(cycle_range):
412-
probs_exp[num_cycle][k, :] = probs_exp_k[i]
412+
probs_th[num_cycle][k, :] = probs_th_k[i]
413413
probs_meas[num_cycle][k, :] = probs_meas_k[i]
414414

415-
fidelity_vals = _xeb_fidelities(probs_exp, probs_meas)
415+
fidelity_vals = _xeb_fidelities(probs_th, probs_meas)
416416
xeb_data = [CrossEntropyPair(c, k) for (c, k) in zip(cycle_range, fidelity_vals)]
417417
return CrossEntropyResult(data=xeb_data, repetitions=repetitions) # type: ignore
418418

@@ -527,19 +527,35 @@ def _measure_prob_distribution(
527527

528528

529529
def _xeb_fidelities(
530-
ideal_probs: Dict[int, np.ndarray], actual_probs: Dict[int, np.ndarray]
530+
probs_th: Dict[int, np.ndarray], probs_meas: Dict[int, np.ndarray]
531531
) -> List[float]:
532-
num_cycles = sorted(list(ideal_probs.keys()))
533-
return [_compute_fidelity(ideal_probs[n], actual_probs[n]) for n in num_cycles]
532+
"""Compute XEB fidelity estimates for all circuit depths.
533+
534+
Args:
535+
probs_th: Theoretical output probabilities by cycle number.
536+
probs_meas: Experimental output probabilities by cycle number.
537+
Returns:
538+
List of fidelity estimates for each circuit depth.
539+
"""
540+
num_cycles = sorted(list(probs_th.keys()))
541+
return [_compute_fidelity(probs_th[n], probs_meas[n]) for n in num_cycles]
534542

535543

536-
def _compute_fidelity(probs_exp: np.ndarray, probs_meas: np.ndarray) -> float:
537-
_, num_states = probs_exp.shape
538-
pp_cross = probs_exp * probs_meas
539-
pp_exp = probs_exp ** 2
544+
def _compute_fidelity(probs_th: np.ndarray, probs_meas: np.ndarray) -> float:
545+
"""Compute XEB fidelity estimate.
546+
547+
Args:
548+
probs_th: Theoretical output probabilities.
549+
probs_meas: Experimental output probabilities.
550+
Returns:
551+
XEB fidelity estimate.
552+
"""
553+
_, num_states = probs_th.shape
554+
pp_cross = probs_th * probs_meas
555+
pp_th = probs_th ** 2
540556
f_meas = np.mean(num_states * np.sum(pp_cross, axis=1) - 1.0)
541-
f_exp = np.mean(num_states * np.sum(pp_exp, axis=1) - 1.0)
542-
return float(f_meas / f_exp)
557+
f_th = np.mean(num_states * np.sum(pp_th, axis=1) - 1.0)
558+
return float(f_meas / f_th)
543559

544560

545561
def _random_half_rotations(qubits: Sequence[ops.Qid], num_layers: int) -> List[List[ops.OP_TREE]]:

0 commit comments

Comments
 (0)