A framework for creating, editing, and invoking Noisy Intermediate Scale Quantum (NISQ) circuits.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
The study module provides tools for parameterized quantum circuits and parameter sweeps, enabling systematic exploration of quantum algorithms and optimization of quantum circuit parameters.
Resolves symbolic parameters to concrete values.
class ParamResolver:
"""Resolves symbolic parameters to values."""
def __init__(self, param_dict: Optional[Dict[Union[str, sympy.Symbol], Any]] = None) -> None:
"""Initialize parameter resolver.
Args:
param_dict: Mapping from parameter names/symbols to values
"""
def resolve(self, value: Any) -> Any:
"""Resolve a parameterized value.
Args:
value: Value that may contain parameters
Returns:
Value with parameters substituted
"""
@property
def param_dict(self) -> Dict[Union[str, sympy.Symbol], Any]:
"""Dictionary mapping parameters to values."""
def __getitem__(self, key: Union[str, sympy.Symbol]) -> Any:
"""Get parameter value by key."""
def __contains__(self, key: Union[str, sympy.Symbol]) -> bool:
"""Check if parameter is defined."""
def __bool__(self) -> bool:
"""True if resolver contains any parameters."""
def __len__(self) -> int:
"""Number of parameters in resolver."""
def keys(self) -> KeysView[Union[str, sympy.Symbol]]:
"""Parameter names/symbols."""
def values(self) -> ValuesView[Any]:
"""Parameter values."""
def items(self) -> ItemsView[Union[str, sympy.Symbol], Any]:
"""Parameter name-value pairs."""Maps expressions to values for parameter resolution.
class ExpressionMap:
"""Maps expressions to values."""
def __init__(self, param_dict: Optional[Dict] = None) -> None:
"""Initialize expression map."""
def transform_dicts(self, dict_list: Iterable[Dict]) -> List[Dict]:
"""Transform list of parameter dictionaries."""
def zip_with(self, *expr_maps: 'ExpressionMap') -> 'ExpressionMap':
"""Zip with other expression maps."""Abstract base class for parameter sweeps.
class Sweep:
"""Abstract base class for parameter sweeps."""
@abc.abstractmethod
def __len__(self) -> int:
"""Number of parameter configurations in sweep."""
@abc.abstractmethod
def __getitem__(self, index: int) -> ParamResolver:
"""Get parameter resolver at given index."""
def __iter__(self) -> Iterator[ParamResolver]:
"""Iterate over parameter resolvers."""
@property
def keys(self) -> AbstractSet[Union[str, sympy.Symbol]]:
"""Set of parameter keys swept over."""
def param_tuples(self) -> Iterator[Tuple[Tuple[Union[str, sympy.Symbol], Any], ...]]:
"""Yield parameter tuples for each configuration."""Sweep containing a single parameter configuration.
class UnitSweep(Sweep):
"""Sweep with a single parameter configuration."""
def __init__(self, param_resolver: Optional[ParamResolver] = None) -> None:
"""Initialize unit sweep."""
UNIT_SWEEP: UnitSweep
"""Default unit sweep with no parameters."""Sweep over an explicit list of parameter configurations.
class ListSweep(Sweep):
"""Sweep over explicit list of parameter configurations."""
def __init__(self, param_resolvers: Sequence[ParamResolver]) -> None:
"""Initialize list sweep.
Args:
param_resolvers: List of parameter resolvers to sweep over
"""
def __len__(self) -> int:
"""Number of configurations."""
def __getitem__(self, index: int) -> ParamResolver:
"""Get parameter resolver at index."""Linear spacing of parameter values between start and stop.
class Linspace(Sweep):
"""Linear spacing parameter sweep."""
def __init__(self, key: Union[str, sympy.Symbol], start: float, stop: float, length: int) -> None:
"""Initialize linear space sweep.
Args:
key: Parameter name or symbol
start: Starting value
stop: Ending value
length: Number of points in sweep
"""
@property
def key(self) -> Union[str, sympy.Symbol]:
"""Parameter being swept."""
@property
def start(self) -> float:
"""Starting value."""
@property
def stop(self) -> float:
"""Ending value."""
@property
def length(self) -> int:
"""Number of points."""Sweep over discrete parameter values.
class Points(Sweep):
"""Discrete points parameter sweep."""
def __init__(self, key: Union[str, sympy.Symbol], points: Sequence[Any]) -> None:
"""Initialize points sweep.
Args:
key: Parameter name or symbol
points: Sequence of parameter values
"""
@property
def key(self) -> Union[str, sympy.Symbol]:
"""Parameter being swept."""
@property
def points(self) -> Tuple[Any, ...]:
"""Parameter values."""Sweeps that combine multiple parameter sweeps.
class Product(Sweep):
"""Cartesian product of parameter sweeps."""
def __init__(self, *sweeps: Sweep) -> None:
"""Initialize product sweep.
Args:
*sweeps: Sweeps to take Cartesian product of
"""
@property
def factors(self) -> Tuple[Sweep, ...]:
"""Factor sweeps in the product."""
class Zip(Sweep):
"""Zip multiple parameter sweeps together."""
def __init__(self, *sweeps: Sweep) -> None:
"""Initialize zip sweep.
Args:
*sweeps: Sweeps to zip together (must have same length)
"""
class ZipLongest(Sweep):
"""Zip sweeps with different lengths using longest."""
def __init__(self, *sweeps: Sweep, fillvalue: ParamResolver = None) -> None:
"""Initialize zip longest sweep."""
class Concat(Sweep):
"""Concatenate multiple parameter sweeps."""
def __init__(self, *sweeps: Sweep) -> None:
"""Initialize concatenated sweep."""Utility functions for creating parameter sweeps.
def dict_to_product_sweep(param_dict: Dict[Union[str, sympy.Symbol], Sequence[Any]]) -> Product:
"""Create product sweep from dictionary.
Args:
param_dict: Dictionary mapping parameter names to sequences of values
Returns:
Product sweep over all parameter combinations
Example:
>>> sweep = dict_to_product_sweep({'theta': [0, π/2, π], 'phi': [0, π/4]})
>>> len(sweep) # 3 * 2 = 6 combinations
6
"""
def dict_to_zip_sweep(param_dict: Dict[Union[str, sympy.Symbol], Sequence[Any]]) -> Zip:
"""Create zip sweep from dictionary.
Args:
param_dict: Dictionary mapping parameter names to equal-length sequences
Returns:
Zip sweep pairing corresponding values
"""Functions for converting various objects to sweeps.
def to_resolvers(sweepable: 'Sweepable') -> List[ParamResolver]:
"""Convert sweepable object to list of parameter resolvers.
Args:
sweepable: Object that can be converted to parameter resolvers
Returns:
List of parameter resolvers
"""
def to_sweep(sweep_or_resolver_or_params: 'Sweepable') -> Sweep:
"""Convert object to parameter sweep.
Args:
sweep_or_resolver_or_params: Object to convert to sweep
Returns:
Parameter sweep
"""
def to_sweeps(sweepable: 'Sweepable') -> List[Sweep]:
"""Convert to list of sweeps."""Container for circuit execution results.
class Result:
"""Result of running a quantum circuit."""
def __init__(self, *,
params: ParamResolver,
measurements: Dict[str, np.ndarray],
records: Optional[Dict[str, np.ndarray]] = None) -> None:
"""Initialize result.
Args:
params: Parameters used for this execution
measurements: Measurement outcomes keyed by measurement key
records: Raw measurement records
"""
@property
def params(self) -> ParamResolver:
"""Parameters used in this execution."""
@property
def measurements(self) -> Dict[str, np.ndarray]:
"""Measurement results keyed by measurement key."""
@property
def records(self) -> Dict[str, np.ndarray]:
"""Raw measurement records."""
def histogram(self, *, key: str, fold_func: Optional[Callable] = None) -> Dict[Any, int]:
"""Get histogram of measurement outcomes.
Args:
key: Measurement key to histogram
fold_func: Function to fold multi-qubit outcomes
Returns:
Dictionary mapping outcomes to counts
"""
def multi_measurement_histogram(self, *, keys: Sequence[str],
fold_func: Optional[Callable] = None) -> Dict[Tuple[Any, ...], int]:
"""Get histogram over multiple measurement keys."""
def data(self, *, name: str = None) -> pd.DataFrame:
"""Get measurement data as pandas DataFrame."""
def __getitem__(self, key: str) -> np.ndarray:
"""Get measurement outcomes for key."""
def __contains__(self, key: str) -> bool:
"""Check if measurement key is present."""
def __len__(self) -> int:
"""Number of repetitions in result."""
def __iter__(self) -> Iterator[str]:
"""Iterate over measurement keys."""
def __bool__(self) -> bool:
"""True if result contains measurements."""Enhanced result access with dictionary-like interface.
class ResultDict:
"""Dictionary-like access to circuit results."""
def __init__(self, params_to_results: Dict[ParamResolver, Result]) -> None:
"""Initialize result dictionary."""
def __getitem__(self, params: ParamResolver) -> Result:
"""Get result for parameter configuration."""
def __contains__(self, params: ParamResolver) -> bool:
"""Check if parameters are in results."""
def __iter__(self) -> Iterator[ParamResolver]:
"""Iterate over parameter configurations."""
def __len__(self) -> int:
"""Number of parameter configurations."""
def keys(self) -> KeysView[ParamResolver]:
"""Parameter configurations."""
def values(self) -> ValuesView[Result]:
"""Results for each configuration."""
def items(self) -> ItemsView[ParamResolver, Result]:
"""Parameter-result pairs."""Utilities for flattening nested expressions with parameters.
def flatten(sweep_or_resolver_or_params: 'Sweepable') -> List[ParamResolver]:
"""Flatten sweepable to list of parameter resolvers."""
def flatten_with_params(program: 'cirq.CIRCUIT_LIKE',
params: 'Sweepable') -> List[Tuple['cirq.CIRCUIT_LIKE', ParamResolver]]:
"""Flatten program with parameters to (program, resolver) pairs."""
def flatten_with_sweep(program: 'cirq.CIRCUIT_LIKE',
params: 'Sweepable') -> List[Tuple['cirq.CIRCUIT_LIKE', ParamResolver]]:
"""Flatten program with sweep to (program, resolver) pairs."""Type aliases and hints used throughout the study module.
ParamDictType = Mapping[Union[str, sympy.Symbol], Any]
"""Type for parameter dictionaries."""
ParamMappingType = Mapping[Union[str, sympy.Symbol], Any]
"""Type for parameter mappings."""
ParamResolverOrSimilarType = Union[ParamResolver, ParamDictType, None, Iterable[Any]]
"""Type for parameter resolver-like objects."""
Sweepable = Union[Sweep, ParamResolver, ParamDictType, Iterable[Any]]
"""Type for objects that can be converted to sweeps."""import cirq
import sympy
import numpy as np
# Create parameterized circuit
theta, phi = sympy.symbols('theta phi')
qubits = cirq.LineQubit.range(2)
circuit = cirq.Circuit([
cirq.rx(theta)(qubits[0]),
cirq.ry(phi)(qubits[1]),
cirq.CNOT(qubits[0], qubits[1]),
cirq.measure(*qubits, key='result')
])
print(f"Original circuit parameters: {cirq.parameter_names(circuit)}")
# Resolve parameters
resolver = cirq.ParamResolver({'theta': np.pi/4, 'phi': np.pi/3})
resolved_circuit = cirq.resolve_parameters(circuit, resolver)
print("Resolved circuit:")
print(resolved_circuit)import cirq
import sympy
import numpy as np
# Create parameterized rotation circuit
theta = sympy.Symbol('theta')
qubit = cirq.LineQubit(0)
circuit = cirq.Circuit([
cirq.rx(theta)(qubit),
cirq.measure(qubit, key='result')
])
# Create linear sweep over rotation angle
sweep = cirq.Linspace('theta', start=0, stop=2*np.pi, length=8)
print(f"Sweep length: {len(sweep)}")
print("Parameter values:")
for i, resolver in enumerate(sweep):
print(f" Point {i}: theta = {resolver['theta']:.3f}")
# Simulate over sweep
simulator = cirq.Simulator()
results = simulator.run_sweep(circuit, sweep, repetitions=100)
print("\nSweep results:")
for i, result in enumerate(results):
theta_val = sweep[i]['theta']
prob_zero = result.histogram(key='result').get(0, 0) / 100
print(f"θ = {theta_val:.3f}: P(|0⟩) = {prob_zero:.3f}")import cirq
import sympy
import numpy as np
# Two-parameter circuit
theta, phi = sympy.symbols('theta phi')
qubits = cirq.LineQubit.range(2)
circuit = cirq.Circuit([
cirq.rx(theta)(qubits[0]),
cirq.ry(phi)(qubits[1]),
cirq.CNOT(qubits[0], qubits[1]),
cirq.measure(*qubits, key='result')
])
# Create product sweep over both parameters
theta_sweep = cirq.Linspace('theta', 0, np.pi, 3)
phi_sweep = cirq.Linspace('phi', 0, np.pi/2, 2)
product_sweep = cirq.Product(theta_sweep, phi_sweep)
print(f"Product sweep length: {len(product_sweep)} = {len(theta_sweep)} × {len(phi_sweep)}")
# Alternative: create from dictionary
param_dict = {
'theta': [0, np.pi/2, np.pi],
'phi': [0, np.pi/4]
}
dict_sweep = cirq.dict_to_product_sweep(param_dict)
print(f"Dictionary sweep length: {len(dict_sweep)}")
# Run the sweep
results = cirq.sample_sweep(circuit, product_sweep, repetitions=50)
print("\nProduct sweep results:")
for i, result in enumerate(results):
params = product_sweep[i]
theta_val = params['theta']
phi_val = params['phi']
outcomes = result.histogram(key='result')
print(f"θ={theta_val:.2f}, φ={phi_val:.2f}: {outcomes}")import cirq
import sympy
import numpy as np
# Circuit with two correlated parameters
alpha, beta = sympy.symbols('alpha beta')
qubit = cirq.LineQubit(0)
circuit = cirq.Circuit([
cirq.rx(alpha)(qubit),
cirq.rz(beta)(qubit),
cirq.measure(qubit, key='result')
])
# Create paired parameter sweep
alpha_values = np.linspace(0, np.pi, 5)
beta_values = 2 * alpha_values # β = 2α correlation
alpha_sweep = cirq.Points('alpha', alpha_values)
beta_sweep = cirq.Points('beta', beta_values)
zip_sweep = cirq.Zip(alpha_sweep, beta_sweep)
print("Zip sweep - correlated parameters:")
for i, resolver in enumerate(zip_sweep):
alpha_val = resolver['alpha']
beta_val = resolver['beta']
print(f" Point {i}: α = {alpha_val:.3f}, β = {beta_val:.3f}")
# Alternative: from dictionary with equal-length lists
param_dict = {
'alpha': alpha_values,
'beta': beta_values
}
dict_zip_sweep = cirq.dict_to_zip_sweep(param_dict)
# Run zip sweep
results = cirq.sample_sweep(circuit, zip_sweep, repetitions=100)
print(f"\nRan zip sweep with {len(results)} parameter configurations")import cirq
import numpy as np
# Create and run a simple circuit
qubits = cirq.LineQubit.range(2)
circuit = cirq.Circuit([
cirq.H(qubits[0]),
cirq.CNOT(qubits[0], qubits[1]),
cirq.measure(*qubits, key='bell_pair')
])
simulator = cirq.Simulator()
result = simulator.run(circuit, repetitions=1000)
# Analyze results
print("Result analysis:")
print(f"Number of repetitions: {len(result)}")
print(f"Measurement keys: {list(result.measurements.keys())}")
print(f"Bell pair histogram: {result.histogram(key='bell_pair')}")
# Access raw measurement data
bell_measurements = result['bell_pair']
print(f"Measurement array shape: {bell_measurements.shape}")
print(f"First 10 outcomes: {bell_measurements[:10]}")
# Convert to DataFrame for analysis
import pandas as pd
df = result.data()
print(f"\nDataFrame shape: {df.shape}")
print(df.head())
# Multi-key measurements
multi_circuit = cirq.Circuit([
cirq.H(qubits[0]),
cirq.measure(qubits[0], key='first'),
cirq.CNOT(qubits[0], qubits[1]),
cirq.measure(qubits[1], key='second')
])
multi_result = simulator.run(multi_circuit, repetitions=100)
multi_hist = multi_result.multi_measurement_histogram(keys=['first', 'second'])
print(f"\nMulti-key histogram: {multi_hist}")import cirq
import sympy
import numpy as np
# Complex parameter sweep combining multiple sweep types
theta, phi, gamma = sympy.symbols('theta phi gamma')
qubits = cirq.LineQubit.range(2)
circuit = cirq.Circuit([
cirq.rx(theta)(qubits[0]),
cirq.ry(phi)(qubits[0]),
cirq.rz(gamma)(qubits[1]),
cirq.CNOT(qubits[0], qubits[1]),
cirq.measure(*qubits, key='result')
])
# Combine different sweep types
theta_sweep = cirq.Linspace('theta', 0, np.pi, 3)
phi_points = cirq.Points('phi', [0, np.pi/4, np.pi/2])
gamma_sweep = cirq.Linspace('gamma', 0, 2*np.pi, 4)
# First combine theta and phi as product
theta_phi_product = cirq.Product(theta_sweep, phi_points)
# Then zip with gamma (need to match lengths)
# Repeat gamma sweep to match product length
repeated_gamma = cirq.Concat(*[gamma_sweep] * (len(theta_phi_product) // len(gamma_sweep) + 1))
truncated_gamma = cirq.ListSweep([repeated_gamma[i] for i in range(len(theta_phi_product))])
final_sweep = cirq.Zip(theta_phi_product, truncated_gamma)
print(f"Complex sweep length: {len(final_sweep)}")
print("First few parameter combinations:")
for i in range(min(5, len(final_sweep))):
params = final_sweep[i]
print(f" {i}: θ={params['theta']:.2f}, φ={params['phi']:.2f}, γ={params['gamma']:.2f}")This comprehensive parameter study system enables systematic exploration and optimization of quantum algorithms through structured parameter sweeps and result analysis.
Install with Tessl CLI
npx tessl i tessl/pypi-cirq