What additional options are available when using TREX?#

Overview#

The main options when using TREX control the number of randomizations and the random state for reproducibility. Unlike REM, TREX does not require the user to provide a confusion matrix.

Number of randomizations#

The num_randomizations parameter controls how many random readout twirling patterns are used. More randomizations give better accuracy but require more circuit executions.

from functools import partial

import numpy as np
from cirq import LineQubit, Circuit, X
from cirq.experiments.single_qubit_readout_calibration_test import (
    NoisySingleQubitReadoutSampler,
)

from mitiq import MeasurementResult
from mitiq.observable.observable import Observable
from mitiq.observable.pauli import PauliString
from mitiq.experimental.trex import execute_with_trex

qreg = [LineQubit(i) for i in range(2)]
circuit = Circuit(X.on_each(*qreg))
observable = Observable(PauliString("ZI"), PauliString("IZ"))

def noisy_readout_executor(circuit, p0, p1, shots=8192) -> MeasurementResult:
    simulator = NoisySingleQubitReadoutSampler(p0, p1)
    result = simulator.run(circuit, repetitions=shots)
    bitstrings = np.column_stack(list(result.measurements.values()))
    return MeasurementResult(bitstrings, qubit_indices=(0, 1))

noisy_executor = partial(noisy_readout_executor, p0=0.15, p1=0.15)
ideal_value = -2.0

for num_rand in [4, 8, 16, 32, 64]:
    result = execute_with_trex(
        circuit,
        noisy_executor,
        observable,
        num_randomizations=num_rand,
        random_state=42,
    )
    error = abs(ideal_value - result)
    print(f"num_randomizations={num_rand:3d}: result={result:.4f}, error={error:.4f}")
num_randomizations=  4: result=-1.9986, error=0.0014
num_randomizations=  8: result=-2.0011, error=0.0011
num_randomizations= 16: result=-2.0040, error=0.0040
num_randomizations= 32: result=-1.9999, error=0.0001
num_randomizations= 64: result=-1.9988, error=0.0012

Note

On small circuits like this 2-qubit example, the improvement from additional randomizations may not be monotonic due to finite sampling noise. The benefits of more randomizations become clearer on larger circuits with more qubits.

Random state for reproducibility#

The random_state parameter accepts an integer seed or a np.random.RandomState object, allowing reproducible results. Note that random_state controls the TREX twirling patterns; for full reproducibility the executor must also be deterministic (e.g., a noiseless simulator).

def deterministic_executor(circuit, shots=8192) -> MeasurementResult:
    """Noiseless executor for reproducibility demonstration."""
    simulator = NoisySingleQubitReadoutSampler(0, 0)
    result = simulator.run(circuit, repetitions=shots)
    bitstrings = np.column_stack(list(result.measurements.values()))
    return MeasurementResult(bitstrings, qubit_indices=(0, 1))

result1 = execute_with_trex(
    circuit, deterministic_executor, observable,
    num_randomizations=16, random_state=123,
)
result2 = execute_with_trex(
    circuit, deterministic_executor, observable,
    num_randomizations=16, random_state=123,
)
print(f"Result 1: {result1:.6f}")
print(f"Result 2: {result2:.6f}")
print(f"Reproducible: {result1 == result2}")
Result 1: -2.000000
Result 2: -2.000000
Reproducible: True

Full output#

Setting full_output=True returns a dictionary containing all intermediate data from the TREX process, which can be useful for debugging or analysis.

result, data = execute_with_trex(
    circuit, noisy_executor, observable,
    num_randomizations=8, random_state=42,
    full_output=True,
)

print(f"TREX value: {result:.4f}")
print(f"Keys: {list(data.keys())}")
for key, value in data.items():
    if isinstance(value, list):
        print(f"  {key}: list of {len(value)} items")
    else:
        print(f"  {key}: {value}")
TREX value: -2.0013
Keys: ['trex_value', 'twirled_circuits', 'calibration_circuits', 'twirled_results', 'calibration_results', 'randomization_strings']
  trex_value: -2.0013472422215974
  twirled_circuits: list of 8 items
  calibration_circuits: list of 8 items
  twirled_results: list of 8 items
  calibration_results: list of 8 items
  randomization_strings: [[0 1]
 [0 0]
 [0 1]
 [0 0]
 [0 1]
 [0 0]
 [0 0]
 [1 0]]