random_circuit(
n_qubits,
n_gates,
seed=None,
gate_set=None,
two_qubit_prob=0.4,
)
Build a random circuit for benchmarking or fuzz-testing.
Parameters
n_qubits : int
Number of qubits, must be >= 1.
n_gates : int
Number of gate operations to generate, must be >= 0.
seed : int | numpy.random.Generator, optional
Seed (or an existing Generator) for reproducible circuits.
gate_set : iterable of str, optional
Restrict generation to this set of gate names, mixing 1- and
2-qubit gates freely (default spans both: h, x, y, z, s, sdg, t,
tdg, sx, rx, ry, rz, cx, cz, cy, swap). Unrecognized names raise
immediately rather than failing later inside run_circuit.
two_qubit_prob : float
Probability in [0, 1] of picking a 2-qubit gate at each step.
Ignored (forced to single-qubit gates) once n_qubits < 2, or once
gate_set excludes every 2-qubit gate name.
Returns
list[tuple]
Source code in dense_evolution/random_circuit.py
| def random_circuit(n_qubits, n_gates, seed=None, gate_set=None, two_qubit_prob=0.4):
"""
Build a random circuit for benchmarking or fuzz-testing.
Parameters
----------
n_qubits : int
Number of qubits, must be >= 1.
n_gates : int
Number of gate operations to generate, must be >= 0.
seed : int | numpy.random.Generator, optional
Seed (or an existing Generator) for reproducible circuits.
gate_set : iterable of str, optional
Restrict generation to this set of gate names, mixing 1- and
2-qubit gates freely (default spans both: h, x, y, z, s, sdg, t,
tdg, sx, rx, ry, rz, cx, cz, cy, swap). Unrecognized names raise
immediately rather than failing later inside run_circuit.
two_qubit_prob : float
Probability in [0, 1] of picking a 2-qubit gate at each step.
Ignored (forced to single-qubit gates) once n_qubits < 2, or once
gate_set excludes every 2-qubit gate name.
Returns
-------
list[tuple]
"""
if n_qubits < 1:
raise ValueError(f"random_circuit needs at least 1 qubit, got {n_qubits}")
if n_gates < 0:
raise ValueError(f"n_gates must be >= 0, got {n_gates}")
if not (0.0 <= two_qubit_prob <= 1.0):
raise ValueError(f"two_qubit_prob must be in [0, 1], got {two_qubit_prob}")
rng = seed if isinstance(seed, np.random.Generator) else np.random.default_rng(seed)
if gate_set is not None:
gate_set = list(gate_set)
unknown = set(gate_set) - _ALL_KNOWN
if unknown:
raise ValueError(f"unknown gate name(s) in gate_set: {sorted(unknown)}")
one_q_static = [g for g in gate_set if g in _1Q_STATIC]
one_q_param = [g for g in gate_set if g in _1Q_PARAMETRIC]
two_q = [g for g in gate_set if g in _2Q_STATIC]
else:
one_q_static = list(_1Q_STATIC)
one_q_param = list(_1Q_PARAMETRIC)
two_q = list(_2Q_STATIC) if n_qubits >= 2 else []
one_q_pool = one_q_static + one_q_param
if not one_q_pool and not two_q:
raise ValueError("gate_set leaves no usable gates for this n_qubits")
ops = []
for _ in range(n_gates):
use_two_qubit = (
bool(two_q) and n_qubits >= 2
and (not one_q_pool or rng.random() < two_qubit_prob)
)
if use_two_qubit:
name = two_q[rng.integers(len(two_q))]
a, b = rng.choice(n_qubits, size=2, replace=False)
ops.append((name, int(a), int(b)))
else:
name = one_q_pool[rng.integers(len(one_q_pool))]
q = int(rng.integers(n_qubits))
if name in _1Q_PARAMETRIC:
theta = float(rng.uniform(0, 2 * np.pi))
ops.append((name, q, theta))
else:
ops.append((name, q))
return ops
|