CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-amazon-braket-sdk

An open source library for interacting with quantum computing devices on Amazon Braket

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

quantum-information.mddocs/

Quantum Information Utilities

Quantum information theory tools, Pauli string operations, parametric circuits, register management, program sets, and quantum computing algorithms.

Core Imports

# Quantum information
from braket.quantum_information import PauliString

# Circuit registers and qubits (from circuits module)
from braket.circuits import Qubit, QubitInput, QubitSet, QubitSetInput  

# Parametric circuits and free parameters (from circuits module)
from braket.circuits import FreeParameter, FreeParameterExpression, Parameterizable

# Program sets for batch execution
from braket.program_sets import CircuitBinding, ParameterSets, ParameterSetsLike, ProgramSet

# Timing data structures
from braket.timings import TimeSeries, TimeSeriesItem

Pauli String Operations

PauliString Class

from braket.quantum_information import PauliString
import numpy as np

class PauliString:
    """Representation and manipulation of Pauli strings."""
    
    def __init__(self, pauli_dict: dict = None):
        """
        Initialize Pauli string from dictionary representation.
        
        Args:
            pauli_dict: Dictionary mapping qubit indices to Pauli operators
                       {'X': [0, 2], 'Y': [1], 'Z': [3]} represents X₀Y₁X₂Z₃
        """
        self.pauli_dict = pauli_dict or {}
    
    @classmethod
    def from_string(cls, pauli_string: str) -> 'PauliString':
        """
        Create PauliString from string representation.
        
        Args:
            pauli_string: String like 'XIYIZ' or 'X0 Y1 Z2'
            
        Returns:
            PauliString: Parsed Pauli string
        """
        pass
    
    def __str__(self) -> str:
        """
        String representation of Pauli string.
        
        Returns:
            str: Human-readable Pauli string
        """
        pass
    
    def __mul__(self, other) -> 'PauliString':
        """
        Multiply two Pauli strings.
        
        Args:
            other: Another PauliString or scalar
            
        Returns:
            PauliString: Product of Pauli strings
        """
        pass
    
    def __add__(self, other) -> 'PauliSum':
        """
        Add Pauli strings to create Pauli sum (Hamiltonian).
        
        Args:
            other: Another PauliString
            
        Returns:
            PauliSum: Sum of Pauli strings
        """
        pass
    
    def commutes_with(self, other: 'PauliString') -> bool:
        """
        Check if this Pauli string commutes with another.
        
        Args:
            other: Another Pauli string
            
        Returns:
            bool: True if strings commute
        """
        pass
    
    def expectation_value(self, state_vector: np.ndarray) -> complex:
        """
        Compute expectation value of Pauli string in given state.
        
        Args:
            state_vector: Quantum state vector
            
        Returns:
            complex: Expectation value ⟨ψ|P|ψ⟩
        """
        pass
    
    def to_matrix(self) -> np.ndarray:
        """
        Convert Pauli string to matrix representation.
        
        Returns:
            np.ndarray: Matrix representation of Pauli string
        """
        pass
    
    @property
    def qubits(self) -> list[int]:
        """Get list of qubits involved in Pauli string."""
        pass
    
    @property
    def weight(self) -> int:
        """Get weight (number of non-identity Paulis)."""
        pass

# Pauli string examples
def create_pauli_hamiltonians() -> dict:
    """
    Create common Pauli string Hamiltonians for quantum algorithms.
    
    Returns:
        dict: Collection of important Hamiltonians
    """
    hamiltonians = {}
    
    # Ising model Hamiltonian: H = -J∑ZᵢZⱼ - h∑Xᵢ
    # 1D chain with 4 qubits
    ising_terms = []
    J = 1.0  # Coupling strength
    h = 0.5  # Transverse field
    
    # ZZ interactions
    for i in range(3):  # 0-1, 1-2, 2-3 pairs
        zz_string = PauliString({'Z': [i, i+1]})
        ising_terms.append((-J, zz_string))
    
    # X transverse field
    for i in range(4):
        x_string = PauliString({'X': [i]})
        ising_terms.append((-h, x_string))
    
    hamiltonians['ising_1d'] = ising_terms
    
    # Heisenberg model: H = J∑(XᵢXⱼ + YᵢYⱼ + ZᵢZⱼ)
    heisenberg_terms = []
    J_heis = 1.0
    
    for i in range(3):
        # XX interaction
        xx_string = PauliString({'X': [i, i+1]})
        heisenberg_terms.append((J_heis, xx_string))
        
        # YY interaction
        yy_string = PauliString({'Y': [i, i+1]})
        heisenberg_terms.append((J_heis, yy_string))
        
        # ZZ interaction
        zz_string = PauliString({'Z': [i, i+1]})
        heisenberg_terms.append((J_heis, zz_string))
    
    hamiltonians['heisenberg'] = heisenberg_terms
    
    # H₂ molecule Hamiltonian (simplified)
    h2_terms = [
        (-1.0523732, PauliString({})),  # Identity term
        (0.39793742, PauliString({'Z': [0]})),  # Z₀
        (-0.39793742, PauliString({'Z': [1]})),  # Z₁
        (-0.01128010, PauliString({'Z': [0, 1]})),  # Z₀Z₁
        (0.18093119, PauliString({'X': [0, 1]}))   # X₀X₁
    ]
    
    hamiltonians['h2_molecule'] = h2_terms
    
    return hamiltonians

def analyze_pauli_string_properties(pauli_string: PauliString) -> dict:
    """
    Analyze mathematical properties of Pauli string.
    
    Args:
        pauli_string: Pauli string to analyze
        
    Returns:
        dict: Comprehensive property analysis
    """
    analysis = {
        'basic_properties': {
            'weight': pauli_string.weight,
            'qubits': pauli_string.qubits,
            'qubit_count': len(pauli_string.qubits),
            'string_representation': str(pauli_string)
        },
        'algebraic_properties': {
            'is_hermitian': True,  # All Pauli strings are Hermitian
            'eigenvalues': [-1, 1],  # All Pauli operators have eigenvalues ±1
            'trace': 0 if pauli_string.weight > 0 else 2**len(pauli_string.qubits)
        },
        'computational_complexity': {
            'matrix_size': 2**(2 * len(pauli_string.qubits)),
            'measurement_complexity': 'O(1)',  # Single measurement setting
            'classical_simulation': 'Exponential' if len(pauli_string.qubits) > 20 else 'Feasible'
        }
    }
    
    return analysis

def find_commuting_pauli_groups(pauli_strings: list[PauliString]) -> list[list[PauliString]]:
    """
    Group Pauli strings by commutation relations.
    
    Args:
        pauli_strings: List of Pauli strings to group
        
    Returns:
        list[list[PauliString]]: Groups of mutually commuting Pauli strings
    """
    groups = []
    unassigned = pauli_strings.copy()
    
    while unassigned:
        # Start new group with first unassigned string
        current_group = [unassigned.pop(0)]
        
        # Find all strings that commute with all strings in current group
        i = 0
        while i < len(unassigned):
            string = unassigned[i]
            
            # Check if string commutes with all in current group
            if all(string.commutes_with(group_string) for group_string in current_group):
                current_group.append(unassigned.pop(i))
            else:
                i += 1
        
        groups.append(current_group)
    
    return groups

def optimize_pauli_measurement_grouping(pauli_strings: list[PauliString]) -> dict:
    """
    Optimize measurement grouping for Pauli string expectation values.
    
    Args:
        pauli_strings: Pauli strings requiring expectation value measurement
        
    Returns:
        dict: Optimized measurement strategy
    """
    # Group by commutation relations
    commuting_groups = find_commuting_pauli_groups(pauli_strings)
    
    optimization = {
        'original_measurements': len(pauli_strings),
        'optimized_measurements': len(commuting_groups),
        'reduction_factor': len(pauli_strings) / len(commuting_groups),
        'measurement_groups': [],
        'measurement_circuits': []
    }
    
    for i, group in enumerate(commuting_groups):
        group_info = {
            'group_id': i,
            'pauli_strings': [str(ps) for ps in group],
            'measurement_basis': determine_measurement_basis(group),
            'simultaneous_measurements': len(group)
        }
        optimization['measurement_groups'].append(group_info)
        
        # Create measurement circuit for this group
        measurement_circuit = create_pauli_measurement_circuit(group)
        optimization['measurement_circuits'].append(measurement_circuit)
    
    return optimization

def determine_measurement_basis(pauli_group: list[PauliString]) -> dict:
    """
    Determine optimal measurement basis for commuting Pauli group.
    
    Args:
        pauli_group: Group of commuting Pauli strings
        
    Returns:
        dict: Measurement basis transformations needed
    """
    # Analyze required basis rotations for each qubit
    qubit_basis = {}
    
    for pauli_string in pauli_group:
        for pauli_op, qubits in pauli_string.pauli_dict.items():
            for qubit in qubits:
                if qubit not in qubit_basis:
                    qubit_basis[qubit] = pauli_op
                elif qubit_basis[qubit] != pauli_op:
                    # Conflict - this should not happen in commuting group
                    raise ValueError(f"Non-commuting Pauli operations on qubit {qubit}")
    
    return qubit_basis

def create_pauli_measurement_circuit(pauli_group: list[PauliString]):
    """
    Create quantum circuit for measuring commuting Pauli group.
    
    Args:
        pauli_group: Commuting Pauli strings to measure
        
    Returns:
        Circuit: Quantum circuit with appropriate basis rotations
    """
    from braket.circuits import Circuit
    from braket.circuits.gates import H, S, Si
    
    circuit = Circuit()
    measurement_basis = determine_measurement_basis(pauli_group)
    
    # Add basis rotation gates
    for qubit, pauli_op in measurement_basis.items():
        if pauli_op == 'X':
            circuit.h(qubit)  # Rotate to X basis
        elif pauli_op == 'Y':
            circuit.si(qubit)  # S† gate
            circuit.h(qubit)   # Then Hadamard for Y basis
        # Z basis needs no rotation
    
    # Add measurements
    measured_qubits = list(measurement_basis.keys())
    circuit.measure(measured_qubits)
    
    return circuit

Quantum Registers

Qubit and QubitSet Management

from braket.circuits import Qubit, QubitInput, QubitSet, QubitSetInput

class Qubit:
    """Individual qubit representation."""
    
    def __init__(self, index: int):
        """
        Initialize qubit with index.
        
        Args:
            index: Qubit index identifier
        """
        self.index = index
    
    def __eq__(self, other) -> bool:
        """Check equality with another qubit."""
        return isinstance(other, Qubit) and self.index == other.index
    
    def __hash__(self) -> int:
        """Hash for use in sets and dictionaries."""
        return hash(self.index)
    
    def __str__(self) -> str:
        """String representation."""
        return f"Qubit({self.index})"

class QubitSet:
    """Set of qubits with set operations."""
    
    def __init__(self, qubits: QubitSetInput = None):
        """
        Initialize qubit set.
        
        Args:
            qubits: Initial qubits (int, Qubit, list, or range)
        """
        self._qubits = set()
        if qubits is not None:
            self.add(qubits)
    
    def add(self, qubits: QubitSetInput) -> 'QubitSet':
        """
        Add qubits to set.
        
        Args:
            qubits: Qubits to add
            
        Returns:
            QubitSet: Self for method chaining
        """
        pass
    
    def union(self, other: 'QubitSet') -> 'QubitSet':
        """
        Union with another qubit set.
        
        Args:
            other: Another qubit set
            
        Returns:
            QubitSet: Union of qubit sets
        """
        pass
    
    def intersection(self, other: 'QubitSet') -> 'QubitSet':
        """
        Intersection with another qubit set.
        
        Args:
            other: Another qubit set
            
        Returns:
            QubitSet: Intersection of qubit sets
        """
        pass
    
    def __len__(self) -> int:
        """Number of qubits in set."""
        return len(self._qubits)
    
    def __iter__(self):
        """Iterate over qubits in set."""
        return iter(sorted(self._qubits, key=lambda q: q.index))
    
    def __contains__(self, qubit: QubitInput) -> bool:
        """Check if qubit is in set."""
        pass

# Register management examples
def create_quantum_register_layout(n_qubits: int, connectivity: str = 'all_to_all') -> dict:
    """
    Create quantum register layout with connectivity constraints.
    
    Args:
        n_qubits: Number of qubits in register
        connectivity: Connectivity type ('all_to_all', 'linear', 'grid')
        
    Returns:
        dict: Register layout with connectivity information
    """
    qubits = QubitSet(range(n_qubits))
    
    layout = {
        'qubits': list(qubits),
        'qubit_count': len(qubits),
        'connectivity_type': connectivity,
        'adjacency_list': {},
        'coupling_map': []
    }
    
    # Generate connectivity based on type
    if connectivity == 'all_to_all':
        for i in range(n_qubits):
            layout['adjacency_list'][i] = list(range(n_qubits))
            layout['adjacency_list'][i].remove(i)  # Remove self
            
            for j in range(i+1, n_qubits):
                layout['coupling_map'].append((i, j))
    
    elif connectivity == 'linear':
        for i in range(n_qubits):
            neighbors = []
            if i > 0:
                neighbors.append(i-1)
            if i < n_qubits - 1:
                neighbors.append(i+1)
            layout['adjacency_list'][i] = neighbors
            
            if i < n_qubits - 1:
                layout['coupling_map'].append((i, i+1))
    
    elif connectivity == 'grid':
        # Assume square grid for simplicity
        grid_size = int(n_qubits ** 0.5)
        if grid_size * grid_size != n_qubits:
            raise ValueError(f"Grid connectivity requires perfect square number of qubits, got {n_qubits}")
        
        for i in range(n_qubits):
            row = i // grid_size
            col = i % grid_size
            neighbors = []
            
            # Add neighbors (up, down, left, right)
            if row > 0:  # Up
                neighbors.append((row-1) * grid_size + col)
            if row < grid_size - 1:  # Down
                neighbors.append((row+1) * grid_size + col)
            if col > 0:  # Left
                neighbors.append(row * grid_size + (col-1))
            if col < grid_size - 1:  # Right
                neighbors.append(row * grid_size + (col+1))
            
            layout['adjacency_list'][i] = neighbors
            
            # Add coupling map entries
            for neighbor in neighbors:
                if i < neighbor:  # Avoid duplicates
                    layout['coupling_map'].append((i, neighbor))
    
    return layout

def optimize_qubit_allocation(circuit, device_layout: dict) -> dict:
    """
    Optimize qubit allocation for circuit on device with limited connectivity.
    
    Args:
        circuit: Quantum circuit requiring qubit allocation
        device_layout: Device connectivity layout
        
    Returns:
        dict: Optimized qubit mapping and routing information
    """
    # Extract two-qubit gates from circuit
    two_qubit_operations = []
    for instruction in circuit.instructions:
        if len(instruction.target) == 2:
            two_qubit_operations.append(tuple(instruction.target))
    
    # Build circuit connectivity graph
    circuit_connectivity = {}
    for qubit in range(circuit.qubit_count):
        circuit_connectivity[qubit] = []
    
    for q1, q2 in two_qubit_operations:
        if q2 not in circuit_connectivity[q1]:
            circuit_connectivity[q1].append(q2)
        if q1 not in circuit_connectivity[q2]:
            circuit_connectivity[q2].append(q1)
    
    # Simple greedy mapping (more sophisticated algorithms exist)
    qubit_mapping = {}
    used_physical_qubits = set()
    
    # Start with most connected circuit qubit
    start_qubit = max(circuit_connectivity.keys(), key=lambda q: len(circuit_connectivity[q]))
    
    # Map to most connected device qubit
    start_physical = max(device_layout['adjacency_list'].keys(), 
                        key=lambda q: len(device_layout['adjacency_list'][q]))
    
    qubit_mapping[start_qubit] = start_physical
    used_physical_qubits.add(start_physical)
    
    # Iteratively map remaining qubits
    remaining_circuit_qubits = set(range(circuit.qubit_count)) - {start_qubit}
    
    while remaining_circuit_qubits:
        best_score = -1
        best_mapping = None
        
        for circuit_qubit in remaining_circuit_qubits:
            for physical_qubit in device_layout['adjacency_list'].keys():
                if physical_qubit in used_physical_qubits:
                    continue
                
                # Score based on adjacency to already mapped qubits
                score = 0
                for neighbor in circuit_connectivity[circuit_qubit]:
                    if neighbor in qubit_mapping:
                        mapped_neighbor = qubit_mapping[neighbor]
                        if physical_qubit in device_layout['adjacency_list'][mapped_neighbor]:
                            score += 1
                
                if score > best_score:
                    best_score = score
                    best_mapping = (circuit_qubit, physical_qubit)
        
        if best_mapping:
            circuit_qubit, physical_qubit = best_mapping
            qubit_mapping[circuit_qubit] = physical_qubit
            used_physical_qubits.add(physical_qubit)
            remaining_circuit_qubits.remove(circuit_qubit)
        else:
            # Fallback: use any available physical qubit
            circuit_qubit = remaining_circuit_qubits.pop()
            for physical_qubit in device_layout['adjacency_list'].keys():
                if physical_qubit not in used_physical_qubits:
                    qubit_mapping[circuit_qubit] = physical_qubit
                    used_physical_qubits.add(physical_qubit)
                    break
    
    # Calculate routing overhead
    swap_gates_needed = 0
    for q1, q2 in two_qubit_operations:
        p1, p2 = qubit_mapping[q1], qubit_mapping[q2]
        if p2 not in device_layout['adjacency_list'][p1]:
            swap_gates_needed += 1  # Simplified - actual routing more complex
    
    return {
        'qubit_mapping': qubit_mapping,
        'routing_overhead': swap_gates_needed,
        'mapping_efficiency': (len(two_qubit_operations) - swap_gates_needed) / max(len(two_qubit_operations), 1),
        'physical_qubits_used': len(used_physical_qubits)
    }

Parametric Computation

Free Parameters and Expressions

from braket.circuits import FreeParameter, FreeParameterExpression, Parameterizable

class FreeParameter(Parameterizable):
    """Free parameter for parameterized quantum circuits."""
    
    def __init__(self, name: str):
        """
        Initialize free parameter.
        
        Args:
            name: Parameter name identifier
        """
        self.name = name
    
    def __str__(self) -> str:
        """String representation."""
        return self.name
    
    def __add__(self, other) -> 'FreeParameterExpression':
        """Addition with another parameter or number."""
        return FreeParameterExpression(f"({self.name} + {other})")
    
    def __sub__(self, other) -> 'FreeParameterExpression':
        """Subtraction with another parameter or number."""
        return FreeParameterExpression(f"({self.name} - {other})")
    
    def __mul__(self, other) -> 'FreeParameterExpression':
        """Multiplication with another parameter or number."""
        return FreeParameterExpression(f"({self.name} * {other})")
    
    def __truediv__(self, other) -> 'FreeParameterExpression':
        """Division with another parameter or number."""
        return FreeParameterExpression(f"({self.name} / {other})")

class FreeParameterExpression(Parameterizable):
    """Mathematical expressions with free parameters."""
    
    def __init__(self, expression: str):
        """
        Initialize parameter expression.
        
        Args:
            expression: Mathematical expression string
        """
        self.expression = expression
    
    def substitute(self, substitutions: dict) -> float:
        """
        Substitute parameter values and evaluate expression.
        
        Args:
            substitutions: Dictionary mapping parameter names to values
            
        Returns:
            float: Evaluated expression value
        """
        pass
    
    def get_free_parameters(self) -> set[str]:
        """
        Get all free parameters in expression.
        
        Returns:
            set[str]: Set of parameter names
        """
        pass
    
    def __add__(self, other) -> 'FreeParameterExpression':
        """Addition with another expression or number."""
        return FreeParameterExpression(f"({self.expression} + {other})")
    
    def __mul__(self, other) -> 'FreeParameterExpression':
        """Multiplication with another expression or number."""
        return FreeParameterExpression(f"({self.expression} * {other})")

# Parametric computation examples
def create_parametric_ansatz(n_qubits: int, n_layers: int) -> dict:
    """
    Create parametric quantum ansatz with systematic parameter naming.
    
    Args:
        n_qubits: Number of qubits in ansatz
        n_layers: Number of parametric layers
        
    Returns:
        dict: Parametric ansatz information and parameter structure
    """
    from braket.circuits import Circuit
    from braket.circuits.gates import Ry, Rz, CNot
    
    circuit = Circuit()
    parameters = {}
    parameter_count = 0
    
    # Initialize with Hadamard gates
    for qubit in range(n_qubits):
        circuit.h(qubit)
    
    # Parametric layers
    for layer in range(n_layers):
        # Single-qubit rotations
        for qubit in range(n_qubits):
            # Y rotation parameter
            theta_param = FreeParameter(f"theta_{layer}_{qubit}")
            parameters[f"theta_{layer}_{qubit}"] = theta_param
            circuit.ry(qubit, theta_param)
            parameter_count += 1
            
            # Z rotation parameter
            phi_param = FreeParameter(f"phi_{layer}_{qubit}")
            parameters[f"phi_{layer}_{qubit}"] = phi_param
            circuit.rz(qubit, phi_param)
            parameter_count += 1
        
        # Entangling gates
        for qubit in range(n_qubits - 1):
            circuit.cnot(qubit, (qubit + 1) % n_qubits)
    
    ansatz_info = {
        'circuit': circuit,
        'parameters': parameters,
        'parameter_count': parameter_count,
        'parameter_names': list(parameters.keys()),
        'layers': n_layers,
        'qubits': n_qubits,
        'structure': 'Hardware-efficient ansatz'
    }
    
    return ansatz_info

def optimize_parameter_expressions(expressions: list[FreeParameterExpression]) -> dict:
    """
    Optimize parameter expressions for efficient evaluation.
    
    Args:
        expressions: List of parameter expressions to optimize
        
    Returns:
        dict: Optimization analysis and recommendations
    """
    optimization = {
        'original_expressions': [expr.expression for expr in expressions],
        'common_subexpressions': {},
        'parameter_dependencies': {},
        'evaluation_order': [],
        'computational_complexity': {}
    }
    
    # Find common subexpressions
    subexpr_count = {}
    for expr in expressions:
        # Simplified parsing - would need proper expression tree analysis
        subexprs = expr.expression.split()
        for subexpr in subexprs:
            if subexpr.startswith('(') and ')' in subexpr:
                subexpr_count[subexpr] = subexpr_count.get(subexpr, 0) + 1
    
    # Identify reusable subexpressions
    optimization['common_subexpressions'] = {
        subexpr: count for subexpr, count in subexpr_count.items() if count > 1
    }
    
    # Analyze parameter dependencies
    all_parameters = set()
    for expr in expressions:
        params = expr.get_free_parameters()
        all_parameters.update(params)
        optimization['parameter_dependencies'][expr.expression] = list(params)
    
    optimization['total_unique_parameters'] = len(all_parameters)
    
    return optimization

def generate_parameter_sweep_ranges(ansatz_info: dict, sweep_type: str = 'random') -> dict:
    """
    Generate parameter value ranges for ansatz optimization.
    
    Args:
        ansatz_info: Ansatz information from create_parametric_ansatz
        sweep_type: Type of parameter sweep ('random', 'grid', 'adaptive')
        
    Returns:
        dict: Parameter sweep configuration
    """
    import numpy as np
    
    parameter_names = ansatz_info['parameter_names']
    n_params = len(parameter_names)
    
    sweep_config = {
        'sweep_type': sweep_type,
        'parameter_count': n_params,
        'parameter_ranges': {},
        'suggested_values': {},
        'optimization_hints': []
    }
    
    if sweep_type == 'random':
        # Random sampling in [0, 2π] for rotation angles
        for param_name in parameter_names:
            sweep_config['parameter_ranges'][param_name] = (0, 2*np.pi)
            sweep_config['suggested_values'][param_name] = np.random.random(10) * 2 * np.pi
        
        sweep_config['optimization_hints'] = [
            "Use random search for initial exploration",
            "Consider Bayesian optimization for refinement",
            f"Total parameter space size: {n_params} dimensions"
        ]
    
    elif sweep_type == 'grid':
        # Grid search with reasonable resolution
        points_per_dim = max(3, int(10**(1/max(n_params, 1))))  # Adaptive grid resolution
        
        for param_name in parameter_names:
            sweep_config['parameter_ranges'][param_name] = (0, 2*np.pi)
            sweep_config['suggested_values'][param_name] = np.linspace(0, 2*np.pi, points_per_dim)
        
        total_evaluations = points_per_dim ** n_params
        sweep_config['optimization_hints'] = [
            f"Grid search with {points_per_dim} points per parameter",
            f"Total evaluations needed: {total_evaluations}",
            "Consider reducing parameters if grid is too large"
        ]
    
    elif sweep_type == 'adaptive':
        # Adaptive ranges based on parameter sensitivity
        for param_name in parameter_names:
            if 'theta' in param_name:  # Y rotations - typically more sensitive
                sweep_config['parameter_ranges'][param_name] = (0, np.pi)
            else:  # Z rotations - full range
                sweep_config['parameter_ranges'][param_name] = (0, 2*np.pi)
            
            # Initial sampling points
            sweep_config['suggested_values'][param_name] = np.random.random(5) * sweep_config['parameter_ranges'][param_name][1]
        
        sweep_config['optimization_hints'] = [
            "Adaptive sampling based on parameter types",
            "Y rotations limited to [0, π] for efficiency",
            "Use gradient-based methods when possible"
        ]
    
    return sweep_config

Time Series and Program Sets

Time Series Data Management

from braket.timings import TimeSeries, TimeSeriesItem

class TimeSeriesItem:
    """Individual time series data item."""
    
    def __init__(self, time: float, value: float):
        """
        Initialize time series item.
        
        Args:
            time: Time point
            value: Value at time point
        """
        self.time = time
        self.value = value

class TimeSeries:
    """Time series data representation."""
    
    def __init__(self, values: list[TimeSeriesItem] = None):
        """
        Initialize time series.
        
        Args:
            values: List of time series items
        """
        self.values = values or []
    
    def add_point(self, time: float, value: float) -> 'TimeSeries':
        """
        Add data point to time series.
        
        Args:
            time: Time coordinate
            value: Value at time
            
        Returns:
            TimeSeries: Self for method chaining
        """
        self.values.append(TimeSeriesItem(time, value))
        return self
    
    def interpolate(self, time: float) -> float:
        """
        Interpolate value at given time.
        
        Args:
            time: Time point for interpolation
            
        Returns:
            float: Interpolated value
        """
        pass
    
    def resample(self, new_times: list[float]) -> 'TimeSeries':
        """
        Resample time series at new time points.
        
        Args:
            new_times: New time sampling points
            
        Returns:
            TimeSeries: Resampled time series
        """
        pass

### Program Set Management

```python { .api }
from braket.program_sets import CircuitBinding, ParameterSets, ProgramSet

class CircuitBinding:
    """Circuit parameter binding for program sets."""
    
    def __init__(self, circuit, parameter_values: dict):
        """
        Initialize circuit binding.
        
        Args:
            circuit: Parameterized circuit
            parameter_values: Parameter value assignments
        """
        self.circuit = circuit
        self.parameter_values = parameter_values
    
    def bind_parameters(self):
        """
        Create bound circuit with parameter values substituted.
        
        Returns:
            Circuit: Circuit with parameters bound
        """
        pass

class ParameterSets:
    """Parameter set management for optimization."""
    
    def __init__(self, parameter_names: list[str]):
        """
        Initialize parameter sets.
        
        Args:
            parameter_names: Names of parameters to manage
        """
        self.parameter_names = parameter_names
        self.parameter_sets = []
    
    def add_parameter_set(self, values: list[float]) -> 'ParameterSets':
        """
        Add parameter value set.
        
        Args:
            values: Parameter values in order of parameter_names
            
        Returns:
            ParameterSets: Self for method chaining
        """
        if len(values) != len(self.parameter_names):
            raise ValueError(f"Expected {len(self.parameter_names)} values, got {len(values)}")
        
        param_dict = dict(zip(self.parameter_names, values))
        self.parameter_sets.append(param_dict)
        return self
    
    def generate_grid(self, ranges: dict, resolution: int = 10) -> 'ParameterSets':
        """
        Generate grid of parameter values.
        
        Args:
            ranges: Parameter ranges {param_name: (min, max)}
            resolution: Grid resolution per parameter
            
        Returns:
            ParameterSets: Self with grid parameter sets
        """
        import itertools
        import numpy as np
        
        grid_values = []
        for param_name in self.parameter_names:
            if param_name in ranges:
                min_val, max_val = ranges[param_name]
                param_grid = np.linspace(min_val, max_val, resolution)
                grid_values.append(param_grid)
            else:
                grid_values.append([0.0])  # Default value
        
        # Generate all combinations
        for combination in itertools.product(*grid_values):
            self.add_parameter_set(list(combination))
        
        return self

class ProgramSet:
    """Collection of parameterized programs for batch execution."""
    
    def __init__(self, base_program, parameter_sets: ParameterSets):
        """
        Initialize program set.
        
        Args:
            base_program: Base parameterized program
            parameter_sets: Parameter sets for batch execution
        """
        self.base_program = base_program
        self.parameter_sets = parameter_sets
    
    def create_bindings(self) -> list[CircuitBinding]:
        """
        Create circuit bindings for all parameter sets.
        
        Returns:
            list[CircuitBinding]: Bound circuits for execution
        """
        bindings = []
        for param_set in self.parameter_sets.parameter_sets:
            binding = CircuitBinding(self.base_program, param_set)
            bindings.append(binding)
        return bindings
    
    def execute_all(self, device, shots: int = 1000) -> list:
        """
        Execute all programs in set on device.
        
        Args:
            device: Quantum device for execution
            shots: Number of shots per program
            
        Returns:
            list: Results from all program executions
        """
        bindings = self.create_bindings()
        bound_circuits = [binding.bind_parameters() for binding in bindings]
        
        # Execute batch
        batch_task = device.run_batch(bound_circuits, shots=shots)
        return batch_task.results()

# Program set example
def create_optimization_program_set(ansatz_info: dict, optimization_config: dict) -> ProgramSet:
    """
    Create program set for variational quantum optimization.
    
    Args:
        ansatz_info: Ansatz circuit information
        optimization_config: Optimization configuration
        
    Returns:
        ProgramSet: Program set for batch optimization
    """
    base_circuit = ansatz_info['circuit']
    parameter_names = ansatz_info['parameter_names']
    
    # Create parameter sets based on optimization strategy
    parameter_sets = ParameterSets(parameter_names)
    
    if optimization_config.get('method') == 'grid_search':
        ranges = optimization_config.get('parameter_ranges', {})
        resolution = optimization_config.get('resolution', 5)
        parameter_sets.generate_grid(ranges, resolution)
        
    elif optimization_config.get('method') == 'random_search':
        import numpy as np
        n_samples = optimization_config.get('n_samples', 100)
        
        for _ in range(n_samples):
            random_values = []
            for param_name in parameter_names:
                if param_name in optimization_config.get('parameter_ranges', {}):
                    min_val, max_val = optimization_config['parameter_ranges'][param_name]
                    random_val = np.random.uniform(min_val, max_val)
                else:
                    random_val = np.random.uniform(0, 2*np.pi)
                random_values.append(random_val)
            
            parameter_sets.add_parameter_set(random_values)
    
    return ProgramSet(base_circuit, parameter_sets)

This comprehensive quantum information documentation covers Pauli string operations, quantum registers, parametric computation, time series management, and program set utilities provided by the Amazon Braket SDK.

Install with Tessl CLI

npx tessl i tessl/pypi-amazon-braket-sdk

docs

advanced-features.md

aws-integration.md

circuits.md

devices-simulation.md

index.md

quantum-information.md

tile.json