Skip to content

Commit 00b8246

Browse files
dstrain115rht
authored andcommittedMay 1, 2023
Remove deprecated experiments (quantumlib#5674)
- Removes deprecated functions, classes, and modules from experiments. - CrossEntropyResult and CrossEntropyResult are still there since they need json backwards compatibility. Will follow up with later PR for it.
1 parent df422e2 commit 00b8246

10 files changed

+26
-1759
lines changed
 

‎cirq-core/cirq/__init__.py

-5
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,10 @@
110110
estimate_parallel_single_qubit_readout_errors,
111111
estimate_single_qubit_readout_errors,
112112
hog_score_xeb_fidelity_from_probabilities,
113-
least_squares_xeb_fidelity_from_expectations,
114-
least_squares_xeb_fidelity_from_probabilities,
115113
linear_xeb_fidelity,
116114
linear_xeb_fidelity_from_probabilities,
117115
log_xeb_fidelity,
118116
log_xeb_fidelity_from_probabilities,
119-
generate_boixo_2018_supremacy_circuits_v2,
120-
generate_boixo_2018_supremacy_circuits_v2_bristlecone,
121-
generate_boixo_2018_supremacy_circuits_v2_grid,
122117
measure_confusion_matrix,
123118
xeb_fidelity,
124119
)

‎cirq-core/cirq/experiments/__init__.py

+2-20
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@
1313
# limitations under the License.
1414
"""Experiments and tools for characterizing quantum operations."""
1515

16-
from cirq.experiments.google_v2_supremacy_circuit import (
17-
generate_boixo_2018_supremacy_circuits_v2,
18-
generate_boixo_2018_supremacy_circuits_v2_bristlecone,
19-
generate_boixo_2018_supremacy_circuits_v2_grid,
20-
)
21-
2216
from cirq.experiments.qubit_characterizations import (
2317
RandomizedBenchMarkResult,
2418
single_qubit_randomized_benchmarking,
@@ -28,29 +22,17 @@
2822
two_qubit_state_tomography,
2923
)
3024

31-
from cirq.experiments.cross_entropy_benchmarking import (
32-
build_entangling_layers,
33-
cross_entropy_benchmarking,
34-
CrossEntropyResult,
35-
CrossEntropyResultDict,
36-
)
25+
from cirq.experiments.cross_entropy_benchmarking import CrossEntropyResult, CrossEntropyResultDict
3726

3827
from cirq.experiments.fidelity_estimation import (
3928
hog_score_xeb_fidelity_from_probabilities,
40-
least_squares_xeb_fidelity_from_expectations,
41-
least_squares_xeb_fidelity_from_probabilities,
42-
linear_xeb_fidelity,
4329
linear_xeb_fidelity_from_probabilities,
30+
linear_xeb_fidelity,
4431
log_xeb_fidelity,
4532
log_xeb_fidelity_from_probabilities,
4633
xeb_fidelity,
4734
)
4835

49-
from cirq.experiments.grid_parallel_two_qubit_xeb import (
50-
collect_grid_parallel_two_qubit_xeb_data,
51-
compute_grid_parallel_two_qubit_xeb_results,
52-
)
53-
5436
from cirq.experiments.purity_estimation import purity_from_probabilities
5537

5638
from cirq.experiments.random_quantum_circuit_generation import (

‎cirq-core/cirq/experiments/cross_entropy_benchmarking.py

+2-356
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,11 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from typing import (
16-
Any,
17-
Dict,
18-
Iterable,
19-
List,
20-
Mapping,
21-
NamedTuple,
22-
Optional,
23-
Sequence,
24-
Set,
25-
TYPE_CHECKING,
26-
Tuple,
27-
Union,
28-
)
15+
from typing import Any, Dict, List, Mapping, NamedTuple, Optional, Sequence, TYPE_CHECKING, Tuple
2916
import dataclasses
3017
import numpy as np
3118
from matplotlib import pyplot as plt
32-
from cirq import _compat, _import, circuits, devices, ops, protocols, sim, value, work
19+
from cirq import _compat, _import, protocols
3320

3421
if TYPE_CHECKING:
3522
import cirq
@@ -280,344 +267,3 @@ def __iter__(self):
280267

281268
def __len__(self):
282269
return len(self.results)
283-
284-
285-
@_compat.deprecated(
286-
deadline='v0.16', fix=('Use cirq.experiments.xeb_fitting.benchmark_2q_xeb_fidelities instead')
287-
)
288-
def cross_entropy_benchmarking(
289-
sampler: work.Sampler,
290-
qubits: Sequence[ops.Qid],
291-
*,
292-
benchmark_ops: Sequence[circuits.Moment] = None,
293-
num_circuits: int = 20,
294-
repetitions: int = 1000,
295-
cycles: Union[int, Iterable[int]] = range(2, 103, 10),
296-
scrambling_gates_per_cycle: List[List[ops.Gate]] = None,
297-
simulator: sim.Simulator = None,
298-
) -> CrossEntropyResult:
299-
r"""Cross-entropy benchmarking (XEB) of multiple qubits.
300-
301-
A total of M random circuits are generated, each of which comprises N
302-
layers where N = max('cycles') or 'cycles' if a single value is specified
303-
for the 'cycles' parameter. Every layer contains randomly generated
304-
single-qubit gates applied to each qubit, followed by a set of
305-
user-defined benchmarking operations (e.g. a set of two-qubit gates).
306-
307-
Each circuit (circuit_m) from the M random circuits is further used to
308-
generate a set of circuits {circuit_mn}, where circuit_mn is built from the
309-
first n cycles of circuit_m. n spans all the values in 'cycles'.
310-
311-
For each fixed value n, the experiment performs the following:
312-
313-
1) Experimentally collect a number of bit-strings for each circuit_mn via
314-
projective measurements in the z-basis.
315-
316-
2) Theoretically compute the expected bit-string probabilities
317-
$P^{th, mn}_|...00>$, $P^{th, mn}_|...01>$, $P^{th, mn}_|...10>$,
318-
$P^{th, mn}_|...11>$ ... at the end of circuit_mn for all m and for all
319-
possible bit-strings in the Hilbert space.
320-
321-
3) Compute an experimental XEB function for each circuit_mn:
322-
323-
$f_{mn}^{meas} = \langle D * P^{th, mn}_q - 1 \rangle$
324-
325-
where D is the number of states in the Hilbert space, $P^{th, mn}_q$ is the
326-
theoretical probability of a bit-string q at the end of circuit_mn, and
327-
$\langle \rangle$ corresponds to the ensemble average over all measured
328-
bit-strings.
329-
330-
Then, take the average of $f_{mn}^{meas}$ over all circuit_mn with fixed
331-
n to obtain:
332-
333-
$f_{n}^{meas} = (\sum_m f_{mn}^{meas}) / M$
334-
335-
4) Compute a theoretical XEB function for each circuit_mn:
336-
337-
$f_{mn}^{th} = D \sum_q (P^{th, mn}_q) ** 2 - 1$
338-
339-
where the summation goes over all possible bit-strings q in the Hilbert
340-
space.
341-
342-
Similarly, we then average $f_m^{th}$ over all circuit_mn with fixed n to
343-
obtain:
344-
345-
$f_{n}^{th} = (\sum_m f_{mn}^{th}) / M$
346-
347-
5) Calculate the XEB fidelity $\alpha_n$ at fixed n:
348-
349-
$\alpha_n = f_{n} ^ {meas} / f_{n} ^ {th}$
350-
351-
Args:
352-
sampler: The quantum engine or simulator to run the circuits.
353-
qubits: The qubits included in the XEB experiment.
354-
benchmark_ops: A sequence of circuits.Moment containing gate operations
355-
between specific qubits which are to be benchmarked for fidelity.
356-
If more than one circuits.Moment is specified, the random circuits
357-
will rotate between the circuits.Moment's. As an example,
358-
if benchmark_ops = [Moment([ops.CZ(q0, q1), ops.CZ(q2, q3)]),
359-
Moment([ops.CZ(q1, q2)]) where q0, q1, q2 and q3 are instances of
360-
Qid (such as GridQubits), each random circuit will apply CZ gate
361-
between q0 and q1 plus CZ between q2 and q3 for the first cycle,
362-
CZ gate between q1 and q2 for the second cycle, CZ between q0 and
363-
q1 and CZ between q2 and q3 for the third cycle and so on. If
364-
None, the circuits will consist only of single-qubit gates.
365-
num_circuits: The total number of random circuits to be used.
366-
repetitions: The number of measurements for each circuit to estimate
367-
the bit-string probabilities.
368-
cycles: The different numbers of circuit layers in the XEB study.
369-
Could be a single or a collection of values.
370-
scrambling_gates_per_cycle: If None (by default), the single-qubit
371-
gates are chosen from X/2 ($\pi/2$ rotation around the X axis),
372-
Y/2 ($\pi/2$ rotation around the Y axis) and (X + Y)/2 ($\pi/2$
373-
rotation around an axis $\pi/4$ away from the X on the equator of
374-
the Bloch sphere). Otherwise the single-qubit gates for each layer
375-
are chosen from a list of possible choices (each choice is a list
376-
of one or more single-qubit gates).
377-
simulator: A simulator that calculates the bit-string probabilities
378-
of the ideal circuit. By default, this is set to sim.Simulator().
379-
380-
Returns:
381-
A CrossEntropyResult object that stores and plots the result.
382-
"""
383-
simulator = sim.Simulator() if simulator is None else simulator
384-
num_qubits = len(qubits)
385-
386-
if isinstance(cycles, int):
387-
cycle_range = [cycles]
388-
else:
389-
cycle_range = list(cycles)
390-
391-
# These store the measured and simulated bit-string probabilities from
392-
# all trials in two dictionaries. The keys of the dictionaries are the
393-
# numbers of cycles. The values are 2D arrays with each row being the
394-
# probabilities obtained from a single trial.
395-
probs_meas = {n: np.zeros((num_circuits, 2**num_qubits)) for n in cycle_range}
396-
probs_th = {n: np.zeros((num_circuits, 2**num_qubits)) for n in cycle_range}
397-
398-
for k in range(num_circuits):
399-
400-
# Generates one random XEB circuit with max(num_cycle_range) cycles.
401-
# Then the first n cycles of the circuit are taken to generate
402-
# shorter circuits with n cycles (n taken from cycles). All of these
403-
# circuits are stored in circuits_k.
404-
circuits_k = _build_xeb_circuits(
405-
qubits, cycle_range, scrambling_gates_per_cycle, benchmark_ops
406-
)
407-
408-
# Run each circuit with the sampler to obtain a collection of
409-
# bit-strings, from which the bit-string probabilities are estimated.
410-
probs_meas_k = _measure_prob_distribution(sampler, repetitions, qubits, circuits_k)
411-
412-
# Simulate each circuit with the Cirq simulator to obtain the
413-
# state vector at the end of each circuit, from which the
414-
# theoretically expected bit-string probabilities are obtained.
415-
probs_th_k: List[np.ndarray] = []
416-
for circ_k in circuits_k:
417-
res = simulator.simulate(circ_k, qubit_order=qubits)
418-
state_probs = value.state_vector_to_probabilities(np.asarray(res.final_state_vector))
419-
probs_th_k.append(state_probs)
420-
421-
for i, num_cycle in enumerate(cycle_range):
422-
probs_th[num_cycle][k, :] = probs_th_k[i]
423-
probs_meas[num_cycle][k, :] = probs_meas_k[i]
424-
425-
fidelity_vals = _xeb_fidelities(probs_th, probs_meas)
426-
xeb_data = [CrossEntropyPair(c, k) for (c, k) in zip(cycle_range, fidelity_vals)]
427-
return CrossEntropyResult(data=xeb_data, repetitions=repetitions) # type: ignore
428-
429-
430-
@_compat.deprecated(
431-
deadline='v0.16', fix=('Use cirq.experiments.random_quantum_circuit_generation instead')
432-
)
433-
def build_entangling_layers(
434-
qubits: Sequence[devices.GridQubit], two_qubit_gate: ops.Gate
435-
) -> List[circuits.Moment]:
436-
"""Builds a sequence of gates that entangle all pairs of qubits on a grid.
437-
438-
The qubits are restricted to be physically on a square grid with distinct
439-
row and column indices (not every node of the grid needs to have a
440-
qubit). To entangle all pairs of qubits, a user-specified two-qubit gate
441-
is applied between each and every pair of qubit that are next to each
442-
other. In general, a total of four sets of parallel operations are needed to
443-
perform all possible two-qubit gates. We proceed as follows:
444-
445-
The first layer applies two-qubit gates to qubits (i, j) and (i, j + 1)
446-
where i is any integer and j is an even integer. The second layer
447-
applies two-qubit gates to qubits (i, j) and (i + 1, j) where i is an even
448-
integer and j is any integer. The third layer applies two-qubit gates
449-
to qubits (i, j) and (i, j + 1) where i is any integer and j is an odd
450-
integer. The fourth layer applies two-qubit gates to qubits (i, j) and
451-
(i + 1, j) where i is an odd integer and j is any integer.
452-
453-
After the layers are built as above, any empty layer is ejected.:
454-
455-
Cycle 1: Cycle 2:
456-
q00 ── q01 q02 ── q03 q00 q01 q02 q03
457-
| | | |
458-
q10 ── q11 q12 ── q13 q10 q11 q12 q13
459-
460-
q20 ── q21 q22 ── q23 q20 q21 q22 q23
461-
| | | |
462-
q30 ── q31 q32 ── q33 q30 q31 q32 q33
463-
464-
Cycle 3: Cycle 4:
465-
q00 q01 ── q02 q03 q00 q01 q02 q03
466-
467-
q10 q11 ── q12 q13 q10 q11 q12 q13
468-
| | | |
469-
q20 q21 ── q22 q23 q20 q21 q22 q23
470-
471-
q30 q31 ── q32 q33 q30 q31 q32 q33
472-
473-
Args:
474-
qubits: The grid qubits included in the entangling operations.
475-
two_qubit_gate: The two-qubit gate to be applied between all
476-
neighboring pairs of qubits.
477-
478-
Returns:
479-
A list of circuits.Moment, with a maximum length of 4. Each circuits.Moment
480-
includes two-qubit gates which can be performed at the same time.
481-
482-
Raises:
483-
ValueError: two-qubit gate is not used.
484-
"""
485-
if protocols.num_qubits(two_qubit_gate) != 2:
486-
raise ValueError('Input must be a two-qubit gate')
487-
interaction_sequence = _default_interaction_sequence(qubits)
488-
return [
489-
circuits.Moment([two_qubit_gate(q_a, q_b) for (q_a, q_b) in pairs])
490-
for pairs in interaction_sequence
491-
]
492-
493-
494-
def _build_xeb_circuits(
495-
qubits: Sequence[ops.Qid],
496-
cycles: Sequence[int],
497-
single_qubit_gates: List[List[ops.Gate]] = None,
498-
benchmark_ops: Sequence[circuits.Moment] = None,
499-
) -> List[circuits.Circuit]:
500-
if benchmark_ops is not None:
501-
num_d = len(benchmark_ops)
502-
else:
503-
num_d = 0
504-
max_cycles = max(cycles)
505-
506-
if single_qubit_gates is None:
507-
single_rots = _random_half_rotations(qubits, max_cycles)
508-
else:
509-
single_rots = _random_any_gates(qubits, single_qubit_gates, max_cycles)
510-
all_circuits: List[circuits.Circuit] = []
511-
for num_cycles in cycles:
512-
circuit_exp = circuits.Circuit()
513-
for i in range(num_cycles):
514-
circuit_exp.append(single_rots[i])
515-
if benchmark_ops is not None:
516-
for op_set in benchmark_ops[i % num_d]:
517-
circuit_exp.append(op_set)
518-
all_circuits.append(circuit_exp)
519-
return all_circuits
520-
521-
522-
def _measure_prob_distribution(
523-
sampler: work.Sampler,
524-
repetitions: int,
525-
qubits: Sequence[ops.Qid],
526-
circuit_list: List[circuits.Circuit],
527-
) -> List[np.ndarray]:
528-
all_probs: List[np.ndarray] = []
529-
num_states = 2 ** len(qubits)
530-
for circuit in circuit_list:
531-
trial_circuit = circuit.copy()
532-
trial_circuit.append(ops.measure(*qubits, key='z'))
533-
res = sampler.run(trial_circuit, repetitions=repetitions)
534-
res_hist = dict(res.histogram(key='z'))
535-
probs = np.zeros(num_states, dtype=float)
536-
for k, v in res_hist.items():
537-
probs[k] = float(v) / float(repetitions)
538-
all_probs.append(probs)
539-
return all_probs
540-
541-
542-
def _xeb_fidelities(
543-
probs_th: Dict[int, np.ndarray], probs_meas: Dict[int, np.ndarray]
544-
) -> List[float]:
545-
"""Compute XEB fidelity estimates for all circuit depths.
546-
547-
Args:
548-
probs_th: Theoretical output probabilities by cycle number.
549-
probs_meas: Experimental output probabilities by cycle number.
550-
Returns:
551-
List of fidelity estimates for each circuit depth.
552-
"""
553-
num_cycles = sorted(list(probs_th.keys()))
554-
return [_compute_fidelity(probs_th[n], probs_meas[n]) for n in num_cycles]
555-
556-
557-
def _compute_fidelity(probs_th: np.ndarray, probs_meas: np.ndarray) -> float:
558-
"""Compute XEB fidelity estimate.
559-
560-
Args:
561-
probs_th: Theoretical output probabilities.
562-
probs_meas: Experimental output probabilities.
563-
Returns:
564-
XEB fidelity estimate.
565-
"""
566-
_, num_states = probs_th.shape
567-
pp_cross = probs_th * probs_meas
568-
pp_th = probs_th**2
569-
f_meas = np.mean(num_states * np.sum(pp_cross, axis=1) - 1.0)
570-
f_th = np.mean(num_states * np.sum(pp_th, axis=1) - 1.0)
571-
return float(f_meas / f_th)
572-
573-
574-
def _random_half_rotations(qubits: Sequence[ops.Qid], num_layers: int) -> List[List[ops.OP_TREE]]:
575-
rot_ops = [ops.X**0.5, ops.Y**0.5, ops.PhasedXPowGate(phase_exponent=0.25, exponent=0.5)]
576-
num_qubits = len(qubits)
577-
rand_nums = np.random.choice(3, (num_qubits, num_layers))
578-
single_q_layers: List[List[ops.OP_TREE]] = []
579-
for i in range(num_layers):
580-
single_q_layers.append([rot_ops[rand_nums[j, i]](qubits[j]) for j in range(num_qubits)])
581-
return single_q_layers
582-
583-
584-
def _random_any_gates(
585-
qubits: Sequence[ops.Qid], op_list: List[List[ops.Gate]], num_layers: int
586-
) -> List[List[ops.OP_TREE]]:
587-
num_ops = len(op_list)
588-
num_qubits = len(qubits)
589-
rand_nums = np.random.choice(num_ops, (num_qubits, num_layers))
590-
single_q_layers: List[List[ops.OP_TREE]] = []
591-
for i in range(num_layers):
592-
rots_i: List[ops.OP_TREE] = []
593-
for j in range(num_qubits):
594-
rots_i.extend([rot(qubits[j]) for rot in op_list[rand_nums[j, i]]])
595-
single_q_layers.append(rots_i)
596-
return single_q_layers
597-
598-
599-
def _default_interaction_sequence(
600-
qubits: Sequence[devices.GridQubit],
601-
) -> List[Set[Tuple[devices.GridQubit, devices.GridQubit]]]:
602-
qubit_dict = {(qubit.row, qubit.col): qubit for qubit in qubits}
603-
qubit_locs = set(qubit_dict)
604-
num_rows = max([q.row for q in qubits]) + 1
605-
num_cols = max([q.col for q in qubits]) + 1
606-
607-
l_s: List[Set[Tuple[devices.GridQubit, devices.GridQubit]]] = [set() for _ in range(4)]
608-
for i in range(num_rows):
609-
for j in range(num_cols - 1):
610-
if (i, j) in qubit_locs and (i, j + 1) in qubit_locs:
611-
l_s[j % 2 * 2].add((qubit_dict[(i, j)], qubit_dict[(i, j + 1)]))
612-
613-
for i in range(num_rows - 1):
614-
for j in range(num_cols):
615-
if (i, j) in qubit_locs and (i + 1, j) in qubit_locs:
616-
l_s[i % 2 * 2 + 1].add((qubit_dict[(i, j)], qubit_dict[(i + 1, j)]))
617-
618-
l_final: List[Set[Tuple[devices.GridQubit, devices.GridQubit]]] = []
619-
for gate_set in l_s:
620-
if len(gate_set) != 0:
621-
l_final.append(gate_set)
622-
623-
return l_final

‎cirq-core/cirq/experiments/cross_entropy_benchmarking_test.py

+2-89
Original file line numberDiff line numberDiff line change
@@ -12,105 +12,17 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import matplotlib.pyplot as plt
1615
import numpy as np
1716
import pytest
1817
import cirq
1918

20-
from cirq.experiments import (
21-
CrossEntropyResult,
22-
CrossEntropyResultDict,
23-
cross_entropy_benchmarking,
24-
build_entangling_layers,
25-
)
19+
from cirq.experiments import CrossEntropyResult, CrossEntropyResultDict
2620
from cirq.experiments.cross_entropy_benchmarking import CrossEntropyPair, SpecklePurityPair
2721

2822
_DEPRECATION_MESSAGE = 'Use cirq.experiments.xeb_fitting.XEBCharacterizationResult instead'
2923
_DEPRECATION_RANDOM_CIRCUIT = 'Use cirq.experiments.random_quantum_circuit_generation instead'
3024

3125

32-
@pytest.mark.usefixtures('closefigures')
33-
def test_cross_entropy_benchmarking():
34-
# Check that the fidelities returned from a four-qubit XEB simulation are
35-
# close to 1 (deviations from 1 is expected due to finite number of
36-
# measurements).
37-
simulator = cirq.Simulator()
38-
qubits = cirq.GridQubit.square(2)
39-
40-
# Sanity check single-qubit-gate causes error
41-
with pytest.raises(ValueError):
42-
with cirq.testing.assert_deprecated(_DEPRECATION_RANDOM_CIRCUIT, deadline='v0.16'):
43-
build_entangling_layers(qubits, cirq.Z**0.91)
44-
45-
# Build a sequence of CZ gates.
46-
with cirq.testing.assert_deprecated(_DEPRECATION_RANDOM_CIRCUIT, deadline='v0.16'):
47-
interleaved_ops = build_entangling_layers(qubits, cirq.CZ**0.91)
48-
49-
# Specify a set of single-qubit rotations. Pick prime numbers for the
50-
# exponent to avoid evolving the system into a basis state.
51-
single_qubit_rots = [
52-
[cirq.X**0.37],
53-
[cirq.Y**0.73, cirq.X**0.53],
54-
[cirq.Z**0.61, cirq.X**0.43],
55-
[cirq.Y**0.19],
56-
]
57-
58-
# Simulate XEB using the default single-qubit gate set without two-qubit
59-
# gates, XEB using the specified single-qubit gate set without two-qubit
60-
# gates, and XEB using the specified single-qubit gate set with two-qubit
61-
# gate. Check that the fidelities are close to 1.0 in all cases. Also,
62-
# check that a single XEB fidelity is returned if a single cycle number
63-
# is specified.
64-
65-
# Each of theese has one ideprecation for cross_entropy_benchmarking
66-
# and one deprecation for CrossEntropyResult
67-
with cirq.testing.assert_deprecated(_DEPRECATION_MESSAGE, deadline='v0.16', count=2):
68-
results_0 = cross_entropy_benchmarking(
69-
simulator, qubits, num_circuits=3, repetitions=1000, cycles=range(4, 20, 5)
70-
)
71-
with cirq.testing.assert_deprecated(_DEPRECATION_MESSAGE, deadline='v0.16', count=2):
72-
results_1 = cross_entropy_benchmarking(
73-
simulator,
74-
qubits,
75-
num_circuits=3,
76-
repetitions=1000,
77-
cycles=[4, 8, 12],
78-
scrambling_gates_per_cycle=single_qubit_rots,
79-
)
80-
with cirq.testing.assert_deprecated(_DEPRECATION_MESSAGE, deadline='v0.16', count=2):
81-
results_2 = cross_entropy_benchmarking(
82-
simulator,
83-
qubits,
84-
benchmark_ops=interleaved_ops,
85-
num_circuits=3,
86-
repetitions=1000,
87-
cycles=[4, 8, 12],
88-
scrambling_gates_per_cycle=single_qubit_rots,
89-
)
90-
with cirq.testing.assert_deprecated(_DEPRECATION_MESSAGE, deadline='v0.16', count=2):
91-
results_3 = cross_entropy_benchmarking(
92-
simulator,
93-
qubits,
94-
benchmark_ops=interleaved_ops,
95-
num_circuits=3,
96-
repetitions=1000,
97-
cycles=15,
98-
scrambling_gates_per_cycle=single_qubit_rots,
99-
)
100-
fidelities_0 = [datum.xeb_fidelity for datum in results_0.data]
101-
fidelities_1 = [datum.xeb_fidelity for datum in results_1.data]
102-
fidelities_2 = [datum.xeb_fidelity for datum in results_2.data]
103-
fidelities_3 = [datum.xeb_fidelity for datum in results_3.data]
104-
assert np.isclose(np.mean(fidelities_0), 1.0, atol=0.1)
105-
assert np.isclose(np.mean(fidelities_1), 1.0, atol=0.1)
106-
assert np.isclose(np.mean(fidelities_2), 1.0, atol=0.1)
107-
assert len(fidelities_3) == 1
108-
109-
# Sanity test that plot runs.
110-
ax = plt.subplot()
111-
results_1.plot(ax)
112-
113-
11426
def test_cross_entropy_result_depolarizing_models():
11527
with cirq.testing.assert_deprecated(_DEPRECATION_MESSAGE, deadline='v0.16'):
11628
prng = np.random.RandomState(59566)
@@ -156,6 +68,7 @@ def test_cross_entropy_result_dict_repr():
15668
)
15769
with cirq.testing.assert_deprecated(_DEPRECATION_MESSAGE, deadline='v0.16'):
15870
result_dict = CrossEntropyResultDict(results={pair: result})
71+
assert len(result_dict) == 1
15972
with cirq.testing.assert_deprecated(_DEPRECATION_MESSAGE, deadline='v0.16', count=6):
16073
cirq.testing.assert_equivalent_repr(result_dict)
16174

‎cirq-core/cirq/experiments/fidelity_estimation.py

+1-161
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,10 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
"""Estimation of fidelity associated with experimental circuit executions."""
15-
from typing import Callable, List, Mapping, Optional, Sequence, Tuple, cast
15+
from typing import Callable, Mapping, Optional, Sequence
1616

1717
import numpy as np
1818

19-
from cirq import _compat
2019
from cirq.circuits import Circuit
2120
from cirq.ops import QubitOrder, QubitOrderOrList
2221
from cirq.sim import final_state_vector
@@ -223,162 +222,3 @@ def log_xeb_fidelity(
223222
return xeb_fidelity(
224223
circuit, bitstrings, qubit_order, amplitudes, estimator=log_xeb_fidelity_from_probabilities
225224
)
226-
227-
228-
@_compat.deprecated(
229-
deadline='v0.16',
230-
fix=(
231-
'Use cirq.experiments.xeb_fitting '
232-
'(benchmark_2q_xeb_fidelities and fit_exponential_decays) instead.'
233-
),
234-
)
235-
def least_squares_xeb_fidelity_from_expectations(
236-
measured_expectations: Sequence[float],
237-
exact_expectations: Sequence[float],
238-
uniform_expectations: Sequence[float],
239-
) -> Tuple[float, List[float]]:
240-
"""Least squares fidelity estimator.
241-
242-
An XEB experiment collects data from the execution of random circuits
243-
subject to noise. The effect of applying a random circuit with unitary U is
244-
modeled as U followed by a depolarizing channel. The result is that the
245-
initial state |𝜓⟩ is mapped to a density matrix ρ_U as follows:
246-
247-
|𝜓⟩ → ρ_U = f |𝜓_U⟩⟨𝜓_U| + (1 - f) I / D
248-
249-
where |𝜓_U⟩ = U|𝜓⟩, D is the dimension of the Hilbert space, I / D is the
250-
maximally mixed state, and f is the fidelity with which the circuit is
251-
applied. Let O_U be an observable that is diagonal in the computational
252-
basis. Then the expectation of O_U on ρ_U is given by
253-
254-
Tr(ρ_U O_U) = f ⟨𝜓_U|O_U|𝜓_U⟩ + (1 - f) Tr(O_U / D).
255-
256-
This equation shows how f can be estimated, since Tr(ρ_U O_U) can be
257-
estimated from experimental data, and ⟨𝜓_U|O_U|𝜓_U⟩ and Tr(O_U / D) can be
258-
computed numerically.
259-
260-
Let e_U = ⟨𝜓_U|O_U|𝜓_U⟩, u_U = Tr(O_U / D), and m_U denote the experimental
261-
estimate of Tr(ρ_U O_U). Then we estimate f by performing least squares
262-
minimization of the quantity
263-
264-
f (e_U - u_U) - (m_U - u_U)
265-
266-
over different random circuits (giving different U). The solution to the
267-
least squares problem is given by
268-
269-
f = (∑_U (m_U - u_U) * (e_U - u_U)) / (∑_U (e_U - u_U)^2).
270-
271-
Args:
272-
measured_expectations: A sequence of the m_U, the experimental estimates
273-
of the observable, one for each circuit U.
274-
exact_expectations: A sequence of the e_U, the exact value of the
275-
observable. The order should match the order of the
276-
`measured_expectations` argument.
277-
uniform_expectations: A sequence of the u_U, the expectation of the
278-
observable on a uniformly random bitstring. The order should match
279-
the order in the other arguments.
280-
281-
Returns:
282-
A tuple of two values. The first value is the estimated fidelity.
283-
The second value is a list of the residuals
284-
285-
f (e_U - u_U) - (m_U - u_U)
286-
287-
of the least squares minimization.
288-
289-
Raises:
290-
ValueError: The lengths of the input sequences are not all the same.
291-
"""
292-
if not (len(measured_expectations) == len(exact_expectations) == len(uniform_expectations)):
293-
raise ValueError(
294-
'The lengths of measured_expectations, '
295-
'exact_expectations, and uniform_expectations must '
296-
'all be the same. Got lengths '
297-
f'{len(measured_expectations)}, '
298-
f'{len(exact_expectations)}, and '
299-
f'{len(uniform_expectations)}.'
300-
)
301-
numerator = 0.0
302-
denominator = 0.0
303-
for m, e, u in zip(measured_expectations, exact_expectations, uniform_expectations):
304-
numerator += (m - u) * (e - u)
305-
denominator += (e - u) ** 2
306-
fidelity = numerator / denominator
307-
residuals = [
308-
fidelity * (e - u) - (m - u)
309-
for m, e, u in zip(measured_expectations, exact_expectations, uniform_expectations)
310-
]
311-
return fidelity, residuals
312-
313-
314-
@_compat.deprecated(
315-
deadline='v0.16',
316-
fix=(
317-
'Use cirq.experiments.xeb_fitting '
318-
'(benchmark_2q_xeb_fidelities and fit_exponential_decays) instead.'
319-
),
320-
)
321-
def least_squares_xeb_fidelity_from_probabilities(
322-
hilbert_space_dimension: int,
323-
observed_probabilities: Sequence[Sequence[float]],
324-
all_probabilities: Sequence[Sequence[float]],
325-
observable_from_probability: Optional[Callable[[float], float]] = None,
326-
normalize_probabilities: bool = True,
327-
) -> Tuple[float, List[float]]:
328-
"""Least squares fidelity estimator with observable based on probabilities.
329-
330-
Using the notation from the docstring of
331-
`least_squares_xeb_fidelity_from_expectations`, this function computes the
332-
least squares fidelity estimate when the observable O_U has eigenvalue
333-
corresponding to the computational basis state |z⟩ given by g(p(z)), where
334-
p(z) = |⟨z|𝜓_U⟩|^2 and g is a function that can be specified. By default,
335-
g is the identity function, but other choices, such as the logarithm, are
336-
useful. By default, the probability p(z) is actually multiplied by the
337-
Hilbert space dimension D, so that the observable is actually g(D * p(z)).
338-
This behavior can be disabled by setting `normalize_probabilities` to
339-
False.
340-
341-
Args:
342-
hilbert_space_dimension: Dimension of the Hilbert space on which
343-
the channel whose fidelity is being estimated is defined.
344-
observed_probabilities: Ideal probabilities of bitstrings observed in
345-
experiments. A list of lists, where each inner list contains the
346-
probabilities for a single circuit.
347-
all_probabilities: Ideal probabilities of all possible bitstrings.
348-
A list of lists, where each inner list contains the probabilities
349-
for a single circuit, and should have length equal to the Hilbert
350-
space dimension. The order of the lists should correspond to that
351-
of `observed_probabilities`.
352-
observable_from_probability: Function that computes the observable from
353-
a given probability.
354-
normalize_probabilities: Whether to multiply the probabilities by the
355-
Hilbert space dimension before computing the observable.
356-
357-
Returns:
358-
A tuple of two values. The first value is the estimated fidelity.
359-
The second value is a list of the residuals
360-
361-
f (e_U - u_U) - (m_U - u_U)
362-
363-
of the least squares minimization.
364-
"""
365-
if not isinstance(observable_from_probability, np.ufunc):
366-
if observable_from_probability is None:
367-
observable_from_probability = lambda p: p
368-
else:
369-
observable_from_probability = np.frompyfunc(observable_from_probability, 1, 1)
370-
observable_from_probability = cast(Callable, observable_from_probability)
371-
measured_expectations = []
372-
exact_expectations = []
373-
uniform_expectations = []
374-
prefactor = hilbert_space_dimension if normalize_probabilities else 1.0
375-
for observed_probs, all_probs in zip(observed_probabilities, all_probabilities):
376-
observable = observable_from_probability(prefactor * np.array(all_probs))
377-
measured_expectations.append(
378-
np.mean(observable_from_probability(prefactor * np.array(observed_probs)))
379-
)
380-
exact_expectations.append(np.sum(all_probs * observable))
381-
uniform_expectations.append(np.sum(observable) / hilbert_space_dimension)
382-
return least_squares_xeb_fidelity_from_expectations(
383-
measured_expectations, exact_expectations, uniform_expectations
384-
)

‎cirq-core/cirq/experiments/fidelity_estimation_test.py

-106
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414
import itertools
15-
import math
1615
from typing import Sequence
1716

1817
import numpy as np
@@ -143,108 +142,3 @@ def test_xeb_fidelity_tuple_input():
143142
f1 = cirq.xeb_fidelity(circuit, bitstrings, (q0, q1))
144143
f2 = cirq.xeb_fidelity(circuit, tuple(bitstrings), (q0, q1))
145144
assert f1 == f2
146-
147-
148-
def test_least_squares_xeb_fidelity_from_expectations():
149-
prng_state = np.random.get_state()
150-
np.random.seed(0)
151-
152-
depolarization = 0.5
153-
154-
n_qubits = 5
155-
dim = 2**n_qubits
156-
n_circuits = 10
157-
qubits = cirq.LineQubit.range(n_qubits)
158-
159-
measured_expectations_lin = []
160-
exact_expectations_lin = []
161-
measured_expectations_log = []
162-
exact_expectations_log = []
163-
uniform_expectations_log = []
164-
for _ in range(n_circuits):
165-
circuit = make_random_quantum_circuit(qubits, depth=12)
166-
bitstrings = sample_noisy_bitstrings(
167-
circuit, qubits, depolarization=depolarization, repetitions=5000
168-
)
169-
amplitudes = cirq.final_state_vector(circuit)
170-
probabilities = cirq.state_vector_to_probabilities(amplitudes)
171-
172-
measured_expectations_lin.append(dim * np.mean(probabilities[bitstrings]))
173-
exact_expectations_lin.append(dim * np.sum(probabilities**2))
174-
175-
measured_expectations_log.append(np.mean(np.log(dim * probabilities[bitstrings])))
176-
exact_expectations_log.append(np.sum(probabilities * np.log(dim * probabilities)))
177-
uniform_expectations_log.append(np.mean(np.log(dim * probabilities)))
178-
179-
with cirq.testing.assert_deprecated(
180-
'Use cirq.experiments.xeb_fitting', deadline='v0.16', count=2
181-
):
182-
f_lin, r_lin = cirq.experiments.least_squares_xeb_fidelity_from_expectations(
183-
measured_expectations_lin, exact_expectations_lin, [1.0] * n_circuits
184-
)
185-
f_log, r_log = cirq.experiments.least_squares_xeb_fidelity_from_expectations(
186-
measured_expectations_log, exact_expectations_log, uniform_expectations_log
187-
)
188-
189-
assert np.isclose(f_lin, 1 - depolarization, atol=0.01)
190-
assert np.isclose(f_log, 1 - depolarization, atol=0.01)
191-
np.testing.assert_allclose(np.sum(np.array(r_lin) ** 2), 0.0, atol=1e-2)
192-
np.testing.assert_allclose(np.sum(np.array(r_log) ** 2), 0.0, atol=1e-2)
193-
194-
np.random.set_state(prng_state)
195-
196-
197-
def test_least_squares_xeb_fidelity_from_expectations_bad_length():
198-
with pytest.raises(ValueError, match='1, 1, and 2'):
199-
with cirq.testing.assert_deprecated('Use cirq.experiments.xeb_fitting', deadline='v0.16'):
200-
_ = cirq.experiments.least_squares_xeb_fidelity_from_expectations(
201-
[1.0], [1.0], [1.0, 2.0]
202-
)
203-
204-
205-
def test_least_squares_xeb_fidelity_from_probabilities():
206-
prng_state = np.random.get_state()
207-
np.random.seed(0)
208-
209-
depolarization = 0.5
210-
211-
n_qubits = 5
212-
dim = 2**n_qubits
213-
n_circuits = 10
214-
qubits = cirq.LineQubit.range(n_qubits)
215-
216-
all_probabilities = []
217-
observed_probabilities = []
218-
for _ in range(n_circuits):
219-
circuit = make_random_quantum_circuit(qubits, depth=12)
220-
bitstrings = sample_noisy_bitstrings(
221-
circuit, qubits, depolarization=depolarization, repetitions=5000
222-
)
223-
amplitudes = cirq.final_state_vector(circuit)
224-
probabilities = cirq.state_vector_to_probabilities(amplitudes)
225-
226-
all_probabilities.append(probabilities)
227-
observed_probabilities.append(probabilities[bitstrings])
228-
229-
# 2 deprecation warnings for each of the following
230-
with cirq.testing.assert_deprecated(
231-
'Use cirq.experiments.xeb_fitting', deadline='v0.16', count=6
232-
):
233-
f_lin, r_lin = cirq.least_squares_xeb_fidelity_from_probabilities(
234-
dim, observed_probabilities, all_probabilities, None, True
235-
)
236-
f_log_np, r_log_np = cirq.least_squares_xeb_fidelity_from_probabilities(
237-
dim, observed_probabilities, all_probabilities, np.log, True
238-
)
239-
f_log_math, r_log_math = cirq.least_squares_xeb_fidelity_from_probabilities(
240-
dim, observed_probabilities, all_probabilities, math.log, False
241-
)
242-
243-
assert np.isclose(f_lin, 1 - depolarization, atol=0.01)
244-
assert np.isclose(f_log_np, 1 - depolarization, atol=0.01)
245-
assert np.isclose(f_log_math, 1 - depolarization, atol=0.01)
246-
np.testing.assert_allclose(np.sum(np.array(r_lin) ** 2), 0.0, atol=1e-2)
247-
np.testing.assert_allclose(np.sum(np.array(r_log_np) ** 2), 0.0, atol=1e-2)
248-
np.testing.assert_allclose(np.sum(np.array(r_log_math) ** 2), 0.0, atol=1e-2)
249-
250-
np.random.set_state(prng_state)

‎cirq-core/cirq/experiments/google_v2_supremacy_circuit.py

-331
This file was deleted.

‎cirq-core/cirq/experiments/google_v2_supremacy_circuit_test.py

-84
This file was deleted.

‎cirq-core/cirq/experiments/grid_parallel_two_qubit_xeb.py

+5-496
Large diffs are not rendered by default.

‎cirq-core/cirq/experiments/grid_parallel_two_qubit_xeb_test.py

+14-111
Original file line numberDiff line numberDiff line change
@@ -1,115 +1,18 @@
1-
# pylint: disable=wrong-or-nonexistent-copyright-notice
2-
import os
3-
import numpy as np
4-
import cirq
5-
from cirq.experiments import (
6-
collect_grid_parallel_two_qubit_xeb_data,
7-
compute_grid_parallel_two_qubit_xeb_results,
8-
)
1+
# Copyright 2022 The Cirq Developers
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
914
from cirq.experiments.grid_parallel_two_qubit_xeb import GridParallelXEBMetadata, LAYER_A, LAYER_B
10-
11-
ALIGNED_HORIZONTAL = cirq.experiments.GridInteractionLayer(
12-
col_offset=0, vertical=False, stagger=False
13-
)
14-
ALIGNED_VERTICAL = cirq.experiments.GridInteractionLayer(col_offset=0, vertical=True, stagger=False)
15-
16-
17-
_DEPRECATION_MESSAGE = 'Use cirq.experiments.xeb_fitting.XEBCharacterizationResult instead'
18-
_DEPRECATION_RECIRQ = 'Use recirq.benchmarks.xeb.collect_grid_parallel_two_qubit_xeb_data instead.'
19-
20-
21-
def test_estimate_parallel_two_qubit_xeb_fidelity_on_grid_no_noise(tmpdir):
22-
# No noise, fidelities should be close to 1
23-
base_dir = os.path.abspath(tmpdir)
24-
qubits = cirq.GridQubit.square(2)
25-
two_qubit_gate = cirq.ISWAP**0.5
26-
cycles = [5, 10, 15]
27-
with cirq.testing.assert_deprecated(_DEPRECATION_RECIRQ, deadline='v0.16'):
28-
data_collection_id = collect_grid_parallel_two_qubit_xeb_data(
29-
sampler=cirq.Simulator(seed=34310, split_untangled_states=False),
30-
qubits=qubits,
31-
two_qubit_gate=two_qubit_gate,
32-
num_circuits=2,
33-
repetitions=1_000,
34-
cycles=cycles,
35-
layers=(ALIGNED_HORIZONTAL, ALIGNED_VERTICAL),
36-
seed=43435,
37-
num_workers=1,
38-
base_dir=base_dir,
39-
)
40-
with cirq.testing.assert_deprecated(_DEPRECATION_MESSAGE, deadline='v0.16', count=6):
41-
results = compute_grid_parallel_two_qubit_xeb_results(data_collection_id, base_dir=base_dir)
42-
43-
assert len(results) == 4
44-
for result in results.values():
45-
depolarizing_model = result.depolarizing_model()
46-
np.testing.assert_allclose(depolarizing_model.cycle_depolarization, 1.0, atol=1e-2)
47-
purity_depolarizing_model = result.purity_depolarizing_model()
48-
np.testing.assert_allclose(
49-
depolarizing_model.cycle_depolarization,
50-
purity_depolarizing_model.cycle_depolarization,
51-
atol=3e-2,
52-
)
53-
54-
55-
def test_estimate_parallel_two_qubit_xeb_fidelity_on_grid_depolarizing(tmpdir):
56-
# With depolarizing probability e
57-
base_dir = os.path.abspath(tmpdir)
58-
qubits = cirq.GridQubit.square(2)
59-
two_qubit_gate = cirq.ISWAP**0.5
60-
cycles = [5, 10, 15]
61-
e = 0.01
62-
with cirq.testing.assert_deprecated(_DEPRECATION_MESSAGE, deadline='v0.16', count=7):
63-
data_collection_id = collect_grid_parallel_two_qubit_xeb_data(
64-
sampler=cirq.DensityMatrixSimulator(
65-
noise=cirq.depolarize(e), seed=65008, split_untangled_states=False
66-
),
67-
qubits=qubits,
68-
two_qubit_gate=two_qubit_gate,
69-
num_circuits=2,
70-
repetitions=1_000,
71-
cycles=cycles,
72-
layers=(ALIGNED_HORIZONTAL, ALIGNED_VERTICAL),
73-
seed=np.random.RandomState(14948),
74-
num_workers=1,
75-
base_dir=base_dir,
76-
)
77-
results = compute_grid_parallel_two_qubit_xeb_results(
78-
data_collection_id, num_processors=4, base_dir=base_dir
79-
)
80-
81-
assert len(results) == 4
82-
for result in results.values():
83-
depolarizing_model = result.depolarizing_model()
84-
purity_depolarizing_model = result.purity_depolarizing_model()
85-
cycle_pauli_error = (1 - depolarizing_model.cycle_depolarization) * 15 / 16
86-
purity_error = (1 - purity_depolarizing_model.cycle_depolarization) * 15 / 16
87-
np.testing.assert_allclose(1 - cycle_pauli_error, (1 - e) ** 4, atol=1e-2)
88-
np.testing.assert_allclose(1 - purity_error, (1 - e) ** 4, atol=5e-2)
89-
90-
91-
def test_estimate_parallel_two_qubit_xeb_fidelity_on_grid_concurrent(tmpdir):
92-
# Use multiple threads during data collection
93-
base_dir = os.path.abspath(tmpdir)
94-
qubits = cirq.GridQubit.square(2)
95-
two_qubit_gate = cirq.ISWAP**0.5
96-
cycles = [5, 10, 15]
97-
with cirq.testing.assert_deprecated(_DEPRECATION_MESSAGE, deadline='v0.16', count=7):
98-
data_collection_id = collect_grid_parallel_two_qubit_xeb_data(
99-
sampler=cirq.Simulator(seed=34310),
100-
qubits=qubits,
101-
two_qubit_gate=two_qubit_gate,
102-
num_circuits=2,
103-
repetitions=1_000,
104-
cycles=cycles,
105-
layers=(ALIGNED_HORIZONTAL, ALIGNED_VERTICAL),
106-
seed=43435,
107-
num_workers=4,
108-
base_dir=base_dir,
109-
)
110-
results = compute_grid_parallel_two_qubit_xeb_results(data_collection_id, base_dir=base_dir)
111-
112-
assert len(results) == 4
15+
import cirq
11316

11417

11518
def test_grid_parallel_xeb_metadata_repr():

0 commit comments

Comments
 (0)
Please sign in to comment.