An open source library for interacting with quantum computing devices on Amazon Braket
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Quantum information theory tools, Pauli string operations, parametric circuits, register management, program sets, and quantum computing algorithms.
# 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, TimeSeriesItemfrom 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 circuitfrom 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)
}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_configfrom 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