CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-cirq

A framework for creating, editing, and invoking Noisy Intermediate Scale Quantum (NISQ) circuits.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

study.mddocs/

Parameter Studies and Sweeps

The study module provides tools for parameterized quantum circuits and parameter sweeps, enabling systematic exploration of quantum algorithms and optimization of quantum circuit parameters.

Parameter Resolution

ParamResolver

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."""

ExpressionMap

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."""

Parameter Sweeps

Sweep - Base Class

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."""

UnitSweep - Single Parameter Set

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."""

ListSweep - Explicit Parameter List

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."""

Linspace - Linear Parameter Sweep

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."""

Points - Discrete Parameter Values

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."""

Composite Sweeps

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."""

Sweep Construction Functions

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
    """

Sweep Conversion Functions

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."""

Result Classes

Result - Circuit Execution Results

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."""

ResultDict - Dictionary-like Result Access

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."""

Expression Flattening

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 Definitions

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."""

Usage Examples

Basic Parameter Resolution

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)

Linear Parameter Sweeps

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}")

Product Sweeps - Multiple Parameters

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}")

Zip Sweeps - Paired Parameters

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")

Working with Results

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}")

Advanced Sweep Combinations

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

docs

circuits.md

devices.md

index.md

linalg.md

ops.md

protocols.md

qis.md

remaining-modules.md

sim.md

study.md

transformers.md

tile.json