or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

circuits.mddevices.mdindex.mdlinalg.mdops.mdprotocols.mdqis.mdremaining-modules.mdsim.mdstudy.mdtransformers.md

study.mddocs/

0

# Parameter Studies and Sweeps

1

2

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

3

4

## Parameter Resolution

5

6

### ParamResolver

7

8

Resolves symbolic parameters to concrete values.

9

10

```python { .api }

11

class ParamResolver:

12

"""Resolves symbolic parameters to values."""

13

14

def __init__(self, param_dict: Optional[Dict[Union[str, sympy.Symbol], Any]] = None) -> None:

15

"""Initialize parameter resolver.

16

17

Args:

18

param_dict: Mapping from parameter names/symbols to values

19

"""

20

21

def resolve(self, value: Any) -> Any:

22

"""Resolve a parameterized value.

23

24

Args:

25

value: Value that may contain parameters

26

27

Returns:

28

Value with parameters substituted

29

"""

30

31

@property

32

def param_dict(self) -> Dict[Union[str, sympy.Symbol], Any]:

33

"""Dictionary mapping parameters to values."""

34

35

def __getitem__(self, key: Union[str, sympy.Symbol]) -> Any:

36

"""Get parameter value by key."""

37

38

def __contains__(self, key: Union[str, sympy.Symbol]) -> bool:

39

"""Check if parameter is defined."""

40

41

def __bool__(self) -> bool:

42

"""True if resolver contains any parameters."""

43

44

def __len__(self) -> int:

45

"""Number of parameters in resolver."""

46

47

def keys(self) -> KeysView[Union[str, sympy.Symbol]]:

48

"""Parameter names/symbols."""

49

50

def values(self) -> ValuesView[Any]:

51

"""Parameter values."""

52

53

def items(self) -> ItemsView[Union[str, sympy.Symbol], Any]:

54

"""Parameter name-value pairs."""

55

```

56

57

### ExpressionMap

58

59

Maps expressions to values for parameter resolution.

60

61

```python { .api }

62

class ExpressionMap:

63

"""Maps expressions to values."""

64

65

def __init__(self, param_dict: Optional[Dict] = None) -> None:

66

"""Initialize expression map."""

67

68

def transform_dicts(self, dict_list: Iterable[Dict]) -> List[Dict]:

69

"""Transform list of parameter dictionaries."""

70

71

def zip_with(self, *expr_maps: 'ExpressionMap') -> 'ExpressionMap':

72

"""Zip with other expression maps."""

73

```

74

75

## Parameter Sweeps

76

77

### Sweep - Base Class

78

79

Abstract base class for parameter sweeps.

80

81

```python { .api }

82

class Sweep:

83

"""Abstract base class for parameter sweeps."""

84

85

@abc.abstractmethod

86

def __len__(self) -> int:

87

"""Number of parameter configurations in sweep."""

88

89

@abc.abstractmethod

90

def __getitem__(self, index: int) -> ParamResolver:

91

"""Get parameter resolver at given index."""

92

93

def __iter__(self) -> Iterator[ParamResolver]:

94

"""Iterate over parameter resolvers."""

95

96

@property

97

def keys(self) -> AbstractSet[Union[str, sympy.Symbol]]:

98

"""Set of parameter keys swept over."""

99

100

def param_tuples(self) -> Iterator[Tuple[Tuple[Union[str, sympy.Symbol], Any], ...]]:

101

"""Yield parameter tuples for each configuration."""

102

```

103

104

### UnitSweep - Single Parameter Set

105

106

Sweep containing a single parameter configuration.

107

108

```python { .api }

109

class UnitSweep(Sweep):

110

"""Sweep with a single parameter configuration."""

111

112

def __init__(self, param_resolver: Optional[ParamResolver] = None) -> None:

113

"""Initialize unit sweep."""

114

115

UNIT_SWEEP: UnitSweep

116

"""Default unit sweep with no parameters."""

117

```

118

119

### ListSweep - Explicit Parameter List

120

121

Sweep over an explicit list of parameter configurations.

122

123

```python { .api }

124

class ListSweep(Sweep):

125

"""Sweep over explicit list of parameter configurations."""

126

127

def __init__(self, param_resolvers: Sequence[ParamResolver]) -> None:

128

"""Initialize list sweep.

129

130

Args:

131

param_resolvers: List of parameter resolvers to sweep over

132

"""

133

134

def __len__(self) -> int:

135

"""Number of configurations."""

136

137

def __getitem__(self, index: int) -> ParamResolver:

138

"""Get parameter resolver at index."""

139

```

140

141

### Linspace - Linear Parameter Sweep

142

143

Linear spacing of parameter values between start and stop.

144

145

```python { .api }

146

class Linspace(Sweep):

147

"""Linear spacing parameter sweep."""

148

149

def __init__(self, key: Union[str, sympy.Symbol], start: float, stop: float, length: int) -> None:

150

"""Initialize linear space sweep.

151

152

Args:

153

key: Parameter name or symbol

154

start: Starting value

155

stop: Ending value

156

length: Number of points in sweep

157

"""

158

159

@property

160

def key(self) -> Union[str, sympy.Symbol]:

161

"""Parameter being swept."""

162

163

@property

164

def start(self) -> float:

165

"""Starting value."""

166

167

@property

168

def stop(self) -> float:

169

"""Ending value."""

170

171

@property

172

def length(self) -> int:

173

"""Number of points."""

174

```

175

176

### Points - Discrete Parameter Values

177

178

Sweep over discrete parameter values.

179

180

```python { .api }

181

class Points(Sweep):

182

"""Discrete points parameter sweep."""

183

184

def __init__(self, key: Union[str, sympy.Symbol], points: Sequence[Any]) -> None:

185

"""Initialize points sweep.

186

187

Args:

188

key: Parameter name or symbol

189

points: Sequence of parameter values

190

"""

191

192

@property

193

def key(self) -> Union[str, sympy.Symbol]:

194

"""Parameter being swept."""

195

196

@property

197

def points(self) -> Tuple[Any, ...]:

198

"""Parameter values."""

199

```

200

201

### Composite Sweeps

202

203

Sweeps that combine multiple parameter sweeps.

204

205

```python { .api }

206

class Product(Sweep):

207

"""Cartesian product of parameter sweeps."""

208

209

def __init__(self, *sweeps: Sweep) -> None:

210

"""Initialize product sweep.

211

212

Args:

213

*sweeps: Sweeps to take Cartesian product of

214

"""

215

216

@property

217

def factors(self) -> Tuple[Sweep, ...]:

218

"""Factor sweeps in the product."""

219

220

class Zip(Sweep):

221

"""Zip multiple parameter sweeps together."""

222

223

def __init__(self, *sweeps: Sweep) -> None:

224

"""Initialize zip sweep.

225

226

Args:

227

*sweeps: Sweeps to zip together (must have same length)

228

"""

229

230

class ZipLongest(Sweep):

231

"""Zip sweeps with different lengths using longest."""

232

233

def __init__(self, *sweeps: Sweep, fillvalue: ParamResolver = None) -> None:

234

"""Initialize zip longest sweep."""

235

236

class Concat(Sweep):

237

"""Concatenate multiple parameter sweeps."""

238

239

def __init__(self, *sweeps: Sweep) -> None:

240

"""Initialize concatenated sweep."""

241

```

242

243

## Sweep Construction Functions

244

245

Utility functions for creating parameter sweeps.

246

247

```python { .api }

248

def dict_to_product_sweep(param_dict: Dict[Union[str, sympy.Symbol], Sequence[Any]]) -> Product:

249

"""Create product sweep from dictionary.

250

251

Args:

252

param_dict: Dictionary mapping parameter names to sequences of values

253

254

Returns:

255

Product sweep over all parameter combinations

256

257

Example:

258

>>> sweep = dict_to_product_sweep({'theta': [0, π/2, π], 'phi': [0, π/4]})

259

>>> len(sweep) # 3 * 2 = 6 combinations

260

6

261

"""

262

263

def dict_to_zip_sweep(param_dict: Dict[Union[str, sympy.Symbol], Sequence[Any]]) -> Zip:

264

"""Create zip sweep from dictionary.

265

266

Args:

267

param_dict: Dictionary mapping parameter names to equal-length sequences

268

269

Returns:

270

Zip sweep pairing corresponding values

271

"""

272

```

273

274

## Sweep Conversion Functions

275

276

Functions for converting various objects to sweeps.

277

278

```python { .api }

279

def to_resolvers(sweepable: 'Sweepable') -> List[ParamResolver]:

280

"""Convert sweepable object to list of parameter resolvers.

281

282

Args:

283

sweepable: Object that can be converted to parameter resolvers

284

285

Returns:

286

List of parameter resolvers

287

"""

288

289

def to_sweep(sweep_or_resolver_or_params: 'Sweepable') -> Sweep:

290

"""Convert object to parameter sweep.

291

292

Args:

293

sweep_or_resolver_or_params: Object to convert to sweep

294

295

Returns:

296

Parameter sweep

297

"""

298

299

def to_sweeps(sweepable: 'Sweepable') -> List[Sweep]:

300

"""Convert to list of sweeps."""

301

```

302

303

## Result Classes

304

305

### Result - Circuit Execution Results

306

307

Container for circuit execution results.

308

309

```python { .api }

310

class Result:

311

"""Result of running a quantum circuit."""

312

313

def __init__(self, *,

314

params: ParamResolver,

315

measurements: Dict[str, np.ndarray],

316

records: Optional[Dict[str, np.ndarray]] = None) -> None:

317

"""Initialize result.

318

319

Args:

320

params: Parameters used for this execution

321

measurements: Measurement outcomes keyed by measurement key

322

records: Raw measurement records

323

"""

324

325

@property

326

def params(self) -> ParamResolver:

327

"""Parameters used in this execution."""

328

329

@property

330

def measurements(self) -> Dict[str, np.ndarray]:

331

"""Measurement results keyed by measurement key."""

332

333

@property

334

def records(self) -> Dict[str, np.ndarray]:

335

"""Raw measurement records."""

336

337

def histogram(self, *, key: str, fold_func: Optional[Callable] = None) -> Dict[Any, int]:

338

"""Get histogram of measurement outcomes.

339

340

Args:

341

key: Measurement key to histogram

342

fold_func: Function to fold multi-qubit outcomes

343

344

Returns:

345

Dictionary mapping outcomes to counts

346

"""

347

348

def multi_measurement_histogram(self, *, keys: Sequence[str],

349

fold_func: Optional[Callable] = None) -> Dict[Tuple[Any, ...], int]:

350

"""Get histogram over multiple measurement keys."""

351

352

def data(self, *, name: str = None) -> pd.DataFrame:

353

"""Get measurement data as pandas DataFrame."""

354

355

def __getitem__(self, key: str) -> np.ndarray:

356

"""Get measurement outcomes for key."""

357

358

def __contains__(self, key: str) -> bool:

359

"""Check if measurement key is present."""

360

361

def __len__(self) -> int:

362

"""Number of repetitions in result."""

363

364

def __iter__(self) -> Iterator[str]:

365

"""Iterate over measurement keys."""

366

367

def __bool__(self) -> bool:

368

"""True if result contains measurements."""

369

```

370

371

### ResultDict - Dictionary-like Result Access

372

373

Enhanced result access with dictionary-like interface.

374

375

```python { .api }

376

class ResultDict:

377

"""Dictionary-like access to circuit results."""

378

379

def __init__(self, params_to_results: Dict[ParamResolver, Result]) -> None:

380

"""Initialize result dictionary."""

381

382

def __getitem__(self, params: ParamResolver) -> Result:

383

"""Get result for parameter configuration."""

384

385

def __contains__(self, params: ParamResolver) -> bool:

386

"""Check if parameters are in results."""

387

388

def __iter__(self) -> Iterator[ParamResolver]:

389

"""Iterate over parameter configurations."""

390

391

def __len__(self) -> int:

392

"""Number of parameter configurations."""

393

394

def keys(self) -> KeysView[ParamResolver]:

395

"""Parameter configurations."""

396

397

def values(self) -> ValuesView[Result]:

398

"""Results for each configuration."""

399

400

def items(self) -> ItemsView[ParamResolver, Result]:

401

"""Parameter-result pairs."""

402

```

403

404

## Expression Flattening

405

406

Utilities for flattening nested expressions with parameters.

407

408

```python { .api }

409

def flatten(sweep_or_resolver_or_params: 'Sweepable') -> List[ParamResolver]:

410

"""Flatten sweepable to list of parameter resolvers."""

411

412

def flatten_with_params(program: 'cirq.CIRCUIT_LIKE',

413

params: 'Sweepable') -> List[Tuple['cirq.CIRCUIT_LIKE', ParamResolver]]:

414

"""Flatten program with parameters to (program, resolver) pairs."""

415

416

def flatten_with_sweep(program: 'cirq.CIRCUIT_LIKE',

417

params: 'Sweepable') -> List[Tuple['cirq.CIRCUIT_LIKE', ParamResolver]]:

418

"""Flatten program with sweep to (program, resolver) pairs."""

419

```

420

421

## Type Definitions

422

423

Type aliases and hints used throughout the study module.

424

425

```python { .api }

426

ParamDictType = Mapping[Union[str, sympy.Symbol], Any]

427

"""Type for parameter dictionaries."""

428

429

ParamMappingType = Mapping[Union[str, sympy.Symbol], Any]

430

"""Type for parameter mappings."""

431

432

ParamResolverOrSimilarType = Union[ParamResolver, ParamDictType, None, Iterable[Any]]

433

"""Type for parameter resolver-like objects."""

434

435

Sweepable = Union[Sweep, ParamResolver, ParamDictType, Iterable[Any]]

436

"""Type for objects that can be converted to sweeps."""

437

```

438

439

## Usage Examples

440

441

### Basic Parameter Resolution

442

443

```python

444

import cirq

445

import sympy

446

import numpy as np

447

448

# Create parameterized circuit

449

theta, phi = sympy.symbols('theta phi')

450

qubits = cirq.LineQubit.range(2)

451

452

circuit = cirq.Circuit([

453

cirq.rx(theta)(qubits[0]),

454

cirq.ry(phi)(qubits[1]),

455

cirq.CNOT(qubits[0], qubits[1]),

456

cirq.measure(*qubits, key='result')

457

])

458

459

print(f"Original circuit parameters: {cirq.parameter_names(circuit)}")

460

461

# Resolve parameters

462

resolver = cirq.ParamResolver({'theta': np.pi/4, 'phi': np.pi/3})

463

resolved_circuit = cirq.resolve_parameters(circuit, resolver)

464

465

print("Resolved circuit:")

466

print(resolved_circuit)

467

```

468

469

### Linear Parameter Sweeps

470

471

```python

472

import cirq

473

import sympy

474

import numpy as np

475

476

# Create parameterized rotation circuit

477

theta = sympy.Symbol('theta')

478

qubit = cirq.LineQubit(0)

479

480

circuit = cirq.Circuit([

481

cirq.rx(theta)(qubit),

482

cirq.measure(qubit, key='result')

483

])

484

485

# Create linear sweep over rotation angle

486

sweep = cirq.Linspace('theta', start=0, stop=2*np.pi, length=8)

487

488

print(f"Sweep length: {len(sweep)}")

489

print("Parameter values:")

490

for i, resolver in enumerate(sweep):

491

print(f" Point {i}: theta = {resolver['theta']:.3f}")

492

493

# Simulate over sweep

494

simulator = cirq.Simulator()

495

results = simulator.run_sweep(circuit, sweep, repetitions=100)

496

497

print("\nSweep results:")

498

for i, result in enumerate(results):

499

theta_val = sweep[i]['theta']

500

prob_zero = result.histogram(key='result').get(0, 0) / 100

501

print(f"θ = {theta_val:.3f}: P(|0⟩) = {prob_zero:.3f}")

502

```

503

504

### Product Sweeps - Multiple Parameters

505

506

```python

507

import cirq

508

import sympy

509

import numpy as np

510

511

# Two-parameter circuit

512

theta, phi = sympy.symbols('theta phi')

513

qubits = cirq.LineQubit.range(2)

514

515

circuit = cirq.Circuit([

516

cirq.rx(theta)(qubits[0]),

517

cirq.ry(phi)(qubits[1]),

518

cirq.CNOT(qubits[0], qubits[1]),

519

cirq.measure(*qubits, key='result')

520

])

521

522

# Create product sweep over both parameters

523

theta_sweep = cirq.Linspace('theta', 0, np.pi, 3)

524

phi_sweep = cirq.Linspace('phi', 0, np.pi/2, 2)

525

product_sweep = cirq.Product(theta_sweep, phi_sweep)

526

527

print(f"Product sweep length: {len(product_sweep)} = {len(theta_sweep)} × {len(phi_sweep)}")

528

529

# Alternative: create from dictionary

530

param_dict = {

531

'theta': [0, np.pi/2, np.pi],

532

'phi': [0, np.pi/4]

533

}

534

dict_sweep = cirq.dict_to_product_sweep(param_dict)

535

print(f"Dictionary sweep length: {len(dict_sweep)}")

536

537

# Run the sweep

538

results = cirq.sample_sweep(circuit, product_sweep, repetitions=50)

539

540

print("\nProduct sweep results:")

541

for i, result in enumerate(results):

542

params = product_sweep[i]

543

theta_val = params['theta']

544

phi_val = params['phi']

545

outcomes = result.histogram(key='result')

546

print(f"θ={theta_val:.2f}, φ={phi_val:.2f}: {outcomes}")

547

```

548

549

### Zip Sweeps - Paired Parameters

550

551

```python

552

import cirq

553

import sympy

554

import numpy as np

555

556

# Circuit with two correlated parameters

557

alpha, beta = sympy.symbols('alpha beta')

558

qubit = cirq.LineQubit(0)

559

560

circuit = cirq.Circuit([

561

cirq.rx(alpha)(qubit),

562

cirq.rz(beta)(qubit),

563

cirq.measure(qubit, key='result')

564

])

565

566

# Create paired parameter sweep

567

alpha_values = np.linspace(0, np.pi, 5)

568

beta_values = 2 * alpha_values # β = 2α correlation

569

570

alpha_sweep = cirq.Points('alpha', alpha_values)

571

beta_sweep = cirq.Points('beta', beta_values)

572

zip_sweep = cirq.Zip(alpha_sweep, beta_sweep)

573

574

print("Zip sweep - correlated parameters:")

575

for i, resolver in enumerate(zip_sweep):

576

alpha_val = resolver['alpha']

577

beta_val = resolver['beta']

578

print(f" Point {i}: α = {alpha_val:.3f}, β = {beta_val:.3f}")

579

580

# Alternative: from dictionary with equal-length lists

581

param_dict = {

582

'alpha': alpha_values,

583

'beta': beta_values

584

}

585

dict_zip_sweep = cirq.dict_to_zip_sweep(param_dict)

586

587

# Run zip sweep

588

results = cirq.sample_sweep(circuit, zip_sweep, repetitions=100)

589

print(f"\nRan zip sweep with {len(results)} parameter configurations")

590

```

591

592

### Working with Results

593

594

```python

595

import cirq

596

import numpy as np

597

598

# Create and run a simple circuit

599

qubits = cirq.LineQubit.range(2)

600

circuit = cirq.Circuit([

601

cirq.H(qubits[0]),

602

cirq.CNOT(qubits[0], qubits[1]),

603

cirq.measure(*qubits, key='bell_pair')

604

])

605

606

simulator = cirq.Simulator()

607

result = simulator.run(circuit, repetitions=1000)

608

609

# Analyze results

610

print("Result analysis:")

611

print(f"Number of repetitions: {len(result)}")

612

print(f"Measurement keys: {list(result.measurements.keys())}")

613

print(f"Bell pair histogram: {result.histogram(key='bell_pair')}")

614

615

# Access raw measurement data

616

bell_measurements = result['bell_pair']

617

print(f"Measurement array shape: {bell_measurements.shape}")

618

print(f"First 10 outcomes: {bell_measurements[:10]}")

619

620

# Convert to DataFrame for analysis

621

import pandas as pd

622

df = result.data()

623

print(f"\nDataFrame shape: {df.shape}")

624

print(df.head())

625

626

# Multi-key measurements

627

multi_circuit = cirq.Circuit([

628

cirq.H(qubits[0]),

629

cirq.measure(qubits[0], key='first'),

630

cirq.CNOT(qubits[0], qubits[1]),

631

cirq.measure(qubits[1], key='second')

632

])

633

634

multi_result = simulator.run(multi_circuit, repetitions=100)

635

multi_hist = multi_result.multi_measurement_histogram(keys=['first', 'second'])

636

print(f"\nMulti-key histogram: {multi_hist}")

637

```

638

639

### Advanced Sweep Combinations

640

641

```python

642

import cirq

643

import sympy

644

import numpy as np

645

646

# Complex parameter sweep combining multiple sweep types

647

theta, phi, gamma = sympy.symbols('theta phi gamma')

648

qubits = cirq.LineQubit.range(2)

649

650

circuit = cirq.Circuit([

651

cirq.rx(theta)(qubits[0]),

652

cirq.ry(phi)(qubits[0]),

653

cirq.rz(gamma)(qubits[1]),

654

cirq.CNOT(qubits[0], qubits[1]),

655

cirq.measure(*qubits, key='result')

656

])

657

658

# Combine different sweep types

659

theta_sweep = cirq.Linspace('theta', 0, np.pi, 3)

660

phi_points = cirq.Points('phi', [0, np.pi/4, np.pi/2])

661

gamma_sweep = cirq.Linspace('gamma', 0, 2*np.pi, 4)

662

663

# First combine theta and phi as product

664

theta_phi_product = cirq.Product(theta_sweep, phi_points)

665

666

# Then zip with gamma (need to match lengths)

667

# Repeat gamma sweep to match product length

668

repeated_gamma = cirq.Concat(*[gamma_sweep] * (len(theta_phi_product) // len(gamma_sweep) + 1))

669

truncated_gamma = cirq.ListSweep([repeated_gamma[i] for i in range(len(theta_phi_product))])

670

671

final_sweep = cirq.Zip(theta_phi_product, truncated_gamma)

672

673

print(f"Complex sweep length: {len(final_sweep)}")

674

print("First few parameter combinations:")

675

for i in range(min(5, len(final_sweep))):

676

params = final_sweep[i]

677

print(f" {i}: θ={params['theta']:.2f}, φ={params['phi']:.2f}, γ={params['gamma']:.2f}")

678

```

679

680

This comprehensive parameter study system enables systematic exploration and optimization of quantum algorithms through structured parameter sweeps and result analysis.