or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdaws-integration.mdcircuits.mddevices-simulation.mdindex.mdquantum-information.md

quantum-information.mddocs/

0

# Quantum Information Utilities

1

2

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

3

4

## Core Imports

5

6

```python { .api }

7

# Quantum information

8

from braket.quantum_information import PauliString

9

10

# Circuit registers and qubits (from circuits module)

11

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

12

13

# Parametric circuits and free parameters (from circuits module)

14

from braket.circuits import FreeParameter, FreeParameterExpression, Parameterizable

15

16

# Program sets for batch execution

17

from braket.program_sets import CircuitBinding, ParameterSets, ParameterSetsLike, ProgramSet

18

19

# Timing data structures

20

from braket.timings import TimeSeries, TimeSeriesItem

21

```

22

23

## Pauli String Operations

24

25

### PauliString Class

26

27

```python { .api }

28

from braket.quantum_information import PauliString

29

import numpy as np

30

31

class PauliString:

32

"""Representation and manipulation of Pauli strings."""

33

34

def __init__(self, pauli_dict: dict = None):

35

"""

36

Initialize Pauli string from dictionary representation.

37

38

Args:

39

pauli_dict: Dictionary mapping qubit indices to Pauli operators

40

{'X': [0, 2], 'Y': [1], 'Z': [3]} represents X₀Y₁X₂Z₃

41

"""

42

self.pauli_dict = pauli_dict or {}

43

44

@classmethod

45

def from_string(cls, pauli_string: str) -> 'PauliString':

46

"""

47

Create PauliString from string representation.

48

49

Args:

50

pauli_string: String like 'XIYIZ' or 'X0 Y1 Z2'

51

52

Returns:

53

PauliString: Parsed Pauli string

54

"""

55

pass

56

57

def __str__(self) -> str:

58

"""

59

String representation of Pauli string.

60

61

Returns:

62

str: Human-readable Pauli string

63

"""

64

pass

65

66

def __mul__(self, other) -> 'PauliString':

67

"""

68

Multiply two Pauli strings.

69

70

Args:

71

other: Another PauliString or scalar

72

73

Returns:

74

PauliString: Product of Pauli strings

75

"""

76

pass

77

78

def __add__(self, other) -> 'PauliSum':

79

"""

80

Add Pauli strings to create Pauli sum (Hamiltonian).

81

82

Args:

83

other: Another PauliString

84

85

Returns:

86

PauliSum: Sum of Pauli strings

87

"""

88

pass

89

90

def commutes_with(self, other: 'PauliString') -> bool:

91

"""

92

Check if this Pauli string commutes with another.

93

94

Args:

95

other: Another Pauli string

96

97

Returns:

98

bool: True if strings commute

99

"""

100

pass

101

102

def expectation_value(self, state_vector: np.ndarray) -> complex:

103

"""

104

Compute expectation value of Pauli string in given state.

105

106

Args:

107

state_vector: Quantum state vector

108

109

Returns:

110

complex: Expectation value ⟨ψ|P|ψ⟩

111

"""

112

pass

113

114

def to_matrix(self) -> np.ndarray:

115

"""

116

Convert Pauli string to matrix representation.

117

118

Returns:

119

np.ndarray: Matrix representation of Pauli string

120

"""

121

pass

122

123

@property

124

def qubits(self) -> list[int]:

125

"""Get list of qubits involved in Pauli string."""

126

pass

127

128

@property

129

def weight(self) -> int:

130

"""Get weight (number of non-identity Paulis)."""

131

pass

132

133

# Pauli string examples

134

def create_pauli_hamiltonians() -> dict:

135

"""

136

Create common Pauli string Hamiltonians for quantum algorithms.

137

138

Returns:

139

dict: Collection of important Hamiltonians

140

"""

141

hamiltonians = {}

142

143

# Ising model Hamiltonian: H = -J∑ZᵢZⱼ - h∑Xᵢ

144

# 1D chain with 4 qubits

145

ising_terms = []

146

J = 1.0 # Coupling strength

147

h = 0.5 # Transverse field

148

149

# ZZ interactions

150

for i in range(3): # 0-1, 1-2, 2-3 pairs

151

zz_string = PauliString({'Z': [i, i+1]})

152

ising_terms.append((-J, zz_string))

153

154

# X transverse field

155

for i in range(4):

156

x_string = PauliString({'X': [i]})

157

ising_terms.append((-h, x_string))

158

159

hamiltonians['ising_1d'] = ising_terms

160

161

# Heisenberg model: H = J∑(XᵢXⱼ + YᵢYⱼ + ZᵢZⱼ)

162

heisenberg_terms = []

163

J_heis = 1.0

164

165

for i in range(3):

166

# XX interaction

167

xx_string = PauliString({'X': [i, i+1]})

168

heisenberg_terms.append((J_heis, xx_string))

169

170

# YY interaction

171

yy_string = PauliString({'Y': [i, i+1]})

172

heisenberg_terms.append((J_heis, yy_string))

173

174

# ZZ interaction

175

zz_string = PauliString({'Z': [i, i+1]})

176

heisenberg_terms.append((J_heis, zz_string))

177

178

hamiltonians['heisenberg'] = heisenberg_terms

179

180

# H₂ molecule Hamiltonian (simplified)

181

h2_terms = [

182

(-1.0523732, PauliString({})), # Identity term

183

(0.39793742, PauliString({'Z': [0]})), # Z₀

184

(-0.39793742, PauliString({'Z': [1]})), # Z₁

185

(-0.01128010, PauliString({'Z': [0, 1]})), # Z₀Z₁

186

(0.18093119, PauliString({'X': [0, 1]})) # X₀X₁

187

]

188

189

hamiltonians['h2_molecule'] = h2_terms

190

191

return hamiltonians

192

193

def analyze_pauli_string_properties(pauli_string: PauliString) -> dict:

194

"""

195

Analyze mathematical properties of Pauli string.

196

197

Args:

198

pauli_string: Pauli string to analyze

199

200

Returns:

201

dict: Comprehensive property analysis

202

"""

203

analysis = {

204

'basic_properties': {

205

'weight': pauli_string.weight,

206

'qubits': pauli_string.qubits,

207

'qubit_count': len(pauli_string.qubits),

208

'string_representation': str(pauli_string)

209

},

210

'algebraic_properties': {

211

'is_hermitian': True, # All Pauli strings are Hermitian

212

'eigenvalues': [-1, 1], # All Pauli operators have eigenvalues ±1

213

'trace': 0 if pauli_string.weight > 0 else 2**len(pauli_string.qubits)

214

},

215

'computational_complexity': {

216

'matrix_size': 2**(2 * len(pauli_string.qubits)),

217

'measurement_complexity': 'O(1)', # Single measurement setting

218

'classical_simulation': 'Exponential' if len(pauli_string.qubits) > 20 else 'Feasible'

219

}

220

}

221

222

return analysis

223

224

def find_commuting_pauli_groups(pauli_strings: list[PauliString]) -> list[list[PauliString]]:

225

"""

226

Group Pauli strings by commutation relations.

227

228

Args:

229

pauli_strings: List of Pauli strings to group

230

231

Returns:

232

list[list[PauliString]]: Groups of mutually commuting Pauli strings

233

"""

234

groups = []

235

unassigned = pauli_strings.copy()

236

237

while unassigned:

238

# Start new group with first unassigned string

239

current_group = [unassigned.pop(0)]

240

241

# Find all strings that commute with all strings in current group

242

i = 0

243

while i < len(unassigned):

244

string = unassigned[i]

245

246

# Check if string commutes with all in current group

247

if all(string.commutes_with(group_string) for group_string in current_group):

248

current_group.append(unassigned.pop(i))

249

else:

250

i += 1

251

252

groups.append(current_group)

253

254

return groups

255

256

def optimize_pauli_measurement_grouping(pauli_strings: list[PauliString]) -> dict:

257

"""

258

Optimize measurement grouping for Pauli string expectation values.

259

260

Args:

261

pauli_strings: Pauli strings requiring expectation value measurement

262

263

Returns:

264

dict: Optimized measurement strategy

265

"""

266

# Group by commutation relations

267

commuting_groups = find_commuting_pauli_groups(pauli_strings)

268

269

optimization = {

270

'original_measurements': len(pauli_strings),

271

'optimized_measurements': len(commuting_groups),

272

'reduction_factor': len(pauli_strings) / len(commuting_groups),

273

'measurement_groups': [],

274

'measurement_circuits': []

275

}

276

277

for i, group in enumerate(commuting_groups):

278

group_info = {

279

'group_id': i,

280

'pauli_strings': [str(ps) for ps in group],

281

'measurement_basis': determine_measurement_basis(group),

282

'simultaneous_measurements': len(group)

283

}

284

optimization['measurement_groups'].append(group_info)

285

286

# Create measurement circuit for this group

287

measurement_circuit = create_pauli_measurement_circuit(group)

288

optimization['measurement_circuits'].append(measurement_circuit)

289

290

return optimization

291

292

def determine_measurement_basis(pauli_group: list[PauliString]) -> dict:

293

"""

294

Determine optimal measurement basis for commuting Pauli group.

295

296

Args:

297

pauli_group: Group of commuting Pauli strings

298

299

Returns:

300

dict: Measurement basis transformations needed

301

"""

302

# Analyze required basis rotations for each qubit

303

qubit_basis = {}

304

305

for pauli_string in pauli_group:

306

for pauli_op, qubits in pauli_string.pauli_dict.items():

307

for qubit in qubits:

308

if qubit not in qubit_basis:

309

qubit_basis[qubit] = pauli_op

310

elif qubit_basis[qubit] != pauli_op:

311

# Conflict - this should not happen in commuting group

312

raise ValueError(f"Non-commuting Pauli operations on qubit {qubit}")

313

314

return qubit_basis

315

316

def create_pauli_measurement_circuit(pauli_group: list[PauliString]):

317

"""

318

Create quantum circuit for measuring commuting Pauli group.

319

320

Args:

321

pauli_group: Commuting Pauli strings to measure

322

323

Returns:

324

Circuit: Quantum circuit with appropriate basis rotations

325

"""

326

from braket.circuits import Circuit

327

from braket.circuits.gates import H, S, Si

328

329

circuit = Circuit()

330

measurement_basis = determine_measurement_basis(pauli_group)

331

332

# Add basis rotation gates

333

for qubit, pauli_op in measurement_basis.items():

334

if pauli_op == 'X':

335

circuit.h(qubit) # Rotate to X basis

336

elif pauli_op == 'Y':

337

circuit.si(qubit) # S† gate

338

circuit.h(qubit) # Then Hadamard for Y basis

339

# Z basis needs no rotation

340

341

# Add measurements

342

measured_qubits = list(measurement_basis.keys())

343

circuit.measure(measured_qubits)

344

345

return circuit

346

```

347

348

## Quantum Registers

349

350

### Qubit and QubitSet Management

351

352

```python { .api }

353

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

354

355

class Qubit:

356

"""Individual qubit representation."""

357

358

def __init__(self, index: int):

359

"""

360

Initialize qubit with index.

361

362

Args:

363

index: Qubit index identifier

364

"""

365

self.index = index

366

367

def __eq__(self, other) -> bool:

368

"""Check equality with another qubit."""

369

return isinstance(other, Qubit) and self.index == other.index

370

371

def __hash__(self) -> int:

372

"""Hash for use in sets and dictionaries."""

373

return hash(self.index)

374

375

def __str__(self) -> str:

376

"""String representation."""

377

return f"Qubit({self.index})"

378

379

class QubitSet:

380

"""Set of qubits with set operations."""

381

382

def __init__(self, qubits: QubitSetInput = None):

383

"""

384

Initialize qubit set.

385

386

Args:

387

qubits: Initial qubits (int, Qubit, list, or range)

388

"""

389

self._qubits = set()

390

if qubits is not None:

391

self.add(qubits)

392

393

def add(self, qubits: QubitSetInput) -> 'QubitSet':

394

"""

395

Add qubits to set.

396

397

Args:

398

qubits: Qubits to add

399

400

Returns:

401

QubitSet: Self for method chaining

402

"""

403

pass

404

405

def union(self, other: 'QubitSet') -> 'QubitSet':

406

"""

407

Union with another qubit set.

408

409

Args:

410

other: Another qubit set

411

412

Returns:

413

QubitSet: Union of qubit sets

414

"""

415

pass

416

417

def intersection(self, other: 'QubitSet') -> 'QubitSet':

418

"""

419

Intersection with another qubit set.

420

421

Args:

422

other: Another qubit set

423

424

Returns:

425

QubitSet: Intersection of qubit sets

426

"""

427

pass

428

429

def __len__(self) -> int:

430

"""Number of qubits in set."""

431

return len(self._qubits)

432

433

def __iter__(self):

434

"""Iterate over qubits in set."""

435

return iter(sorted(self._qubits, key=lambda q: q.index))

436

437

def __contains__(self, qubit: QubitInput) -> bool:

438

"""Check if qubit is in set."""

439

pass

440

441

# Register management examples

442

def create_quantum_register_layout(n_qubits: int, connectivity: str = 'all_to_all') -> dict:

443

"""

444

Create quantum register layout with connectivity constraints.

445

446

Args:

447

n_qubits: Number of qubits in register

448

connectivity: Connectivity type ('all_to_all', 'linear', 'grid')

449

450

Returns:

451

dict: Register layout with connectivity information

452

"""

453

qubits = QubitSet(range(n_qubits))

454

455

layout = {

456

'qubits': list(qubits),

457

'qubit_count': len(qubits),

458

'connectivity_type': connectivity,

459

'adjacency_list': {},

460

'coupling_map': []

461

}

462

463

# Generate connectivity based on type

464

if connectivity == 'all_to_all':

465

for i in range(n_qubits):

466

layout['adjacency_list'][i] = list(range(n_qubits))

467

layout['adjacency_list'][i].remove(i) # Remove self

468

469

for j in range(i+1, n_qubits):

470

layout['coupling_map'].append((i, j))

471

472

elif connectivity == 'linear':

473

for i in range(n_qubits):

474

neighbors = []

475

if i > 0:

476

neighbors.append(i-1)

477

if i < n_qubits - 1:

478

neighbors.append(i+1)

479

layout['adjacency_list'][i] = neighbors

480

481

if i < n_qubits - 1:

482

layout['coupling_map'].append((i, i+1))

483

484

elif connectivity == 'grid':

485

# Assume square grid for simplicity

486

grid_size = int(n_qubits ** 0.5)

487

if grid_size * grid_size != n_qubits:

488

raise ValueError(f"Grid connectivity requires perfect square number of qubits, got {n_qubits}")

489

490

for i in range(n_qubits):

491

row = i // grid_size

492

col = i % grid_size

493

neighbors = []

494

495

# Add neighbors (up, down, left, right)

496

if row > 0: # Up

497

neighbors.append((row-1) * grid_size + col)

498

if row < grid_size - 1: # Down

499

neighbors.append((row+1) * grid_size + col)

500

if col > 0: # Left

501

neighbors.append(row * grid_size + (col-1))

502

if col < grid_size - 1: # Right

503

neighbors.append(row * grid_size + (col+1))

504

505

layout['adjacency_list'][i] = neighbors

506

507

# Add coupling map entries

508

for neighbor in neighbors:

509

if i < neighbor: # Avoid duplicates

510

layout['coupling_map'].append((i, neighbor))

511

512

return layout

513

514

def optimize_qubit_allocation(circuit, device_layout: dict) -> dict:

515

"""

516

Optimize qubit allocation for circuit on device with limited connectivity.

517

518

Args:

519

circuit: Quantum circuit requiring qubit allocation

520

device_layout: Device connectivity layout

521

522

Returns:

523

dict: Optimized qubit mapping and routing information

524

"""

525

# Extract two-qubit gates from circuit

526

two_qubit_operations = []

527

for instruction in circuit.instructions:

528

if len(instruction.target) == 2:

529

two_qubit_operations.append(tuple(instruction.target))

530

531

# Build circuit connectivity graph

532

circuit_connectivity = {}

533

for qubit in range(circuit.qubit_count):

534

circuit_connectivity[qubit] = []

535

536

for q1, q2 in two_qubit_operations:

537

if q2 not in circuit_connectivity[q1]:

538

circuit_connectivity[q1].append(q2)

539

if q1 not in circuit_connectivity[q2]:

540

circuit_connectivity[q2].append(q1)

541

542

# Simple greedy mapping (more sophisticated algorithms exist)

543

qubit_mapping = {}

544

used_physical_qubits = set()

545

546

# Start with most connected circuit qubit

547

start_qubit = max(circuit_connectivity.keys(), key=lambda q: len(circuit_connectivity[q]))

548

549

# Map to most connected device qubit

550

start_physical = max(device_layout['adjacency_list'].keys(),

551

key=lambda q: len(device_layout['adjacency_list'][q]))

552

553

qubit_mapping[start_qubit] = start_physical

554

used_physical_qubits.add(start_physical)

555

556

# Iteratively map remaining qubits

557

remaining_circuit_qubits = set(range(circuit.qubit_count)) - {start_qubit}

558

559

while remaining_circuit_qubits:

560

best_score = -1

561

best_mapping = None

562

563

for circuit_qubit in remaining_circuit_qubits:

564

for physical_qubit in device_layout['adjacency_list'].keys():

565

if physical_qubit in used_physical_qubits:

566

continue

567

568

# Score based on adjacency to already mapped qubits

569

score = 0

570

for neighbor in circuit_connectivity[circuit_qubit]:

571

if neighbor in qubit_mapping:

572

mapped_neighbor = qubit_mapping[neighbor]

573

if physical_qubit in device_layout['adjacency_list'][mapped_neighbor]:

574

score += 1

575

576

if score > best_score:

577

best_score = score

578

best_mapping = (circuit_qubit, physical_qubit)

579

580

if best_mapping:

581

circuit_qubit, physical_qubit = best_mapping

582

qubit_mapping[circuit_qubit] = physical_qubit

583

used_physical_qubits.add(physical_qubit)

584

remaining_circuit_qubits.remove(circuit_qubit)

585

else:

586

# Fallback: use any available physical qubit

587

circuit_qubit = remaining_circuit_qubits.pop()

588

for physical_qubit in device_layout['adjacency_list'].keys():

589

if physical_qubit not in used_physical_qubits:

590

qubit_mapping[circuit_qubit] = physical_qubit

591

used_physical_qubits.add(physical_qubit)

592

break

593

594

# Calculate routing overhead

595

swap_gates_needed = 0

596

for q1, q2 in two_qubit_operations:

597

p1, p2 = qubit_mapping[q1], qubit_mapping[q2]

598

if p2 not in device_layout['adjacency_list'][p1]:

599

swap_gates_needed += 1 # Simplified - actual routing more complex

600

601

return {

602

'qubit_mapping': qubit_mapping,

603

'routing_overhead': swap_gates_needed,

604

'mapping_efficiency': (len(two_qubit_operations) - swap_gates_needed) / max(len(two_qubit_operations), 1),

605

'physical_qubits_used': len(used_physical_qubits)

606

}

607

```

608

609

## Parametric Computation

610

611

### Free Parameters and Expressions

612

613

```python { .api }

614

from braket.circuits import FreeParameter, FreeParameterExpression, Parameterizable

615

616

class FreeParameter(Parameterizable):

617

"""Free parameter for parameterized quantum circuits."""

618

619

def __init__(self, name: str):

620

"""

621

Initialize free parameter.

622

623

Args:

624

name: Parameter name identifier

625

"""

626

self.name = name

627

628

def __str__(self) -> str:

629

"""String representation."""

630

return self.name

631

632

def __add__(self, other) -> 'FreeParameterExpression':

633

"""Addition with another parameter or number."""

634

return FreeParameterExpression(f"({self.name} + {other})")

635

636

def __sub__(self, other) -> 'FreeParameterExpression':

637

"""Subtraction with another parameter or number."""

638

return FreeParameterExpression(f"({self.name} - {other})")

639

640

def __mul__(self, other) -> 'FreeParameterExpression':

641

"""Multiplication with another parameter or number."""

642

return FreeParameterExpression(f"({self.name} * {other})")

643

644

def __truediv__(self, other) -> 'FreeParameterExpression':

645

"""Division with another parameter or number."""

646

return FreeParameterExpression(f"({self.name} / {other})")

647

648

class FreeParameterExpression(Parameterizable):

649

"""Mathematical expressions with free parameters."""

650

651

def __init__(self, expression: str):

652

"""

653

Initialize parameter expression.

654

655

Args:

656

expression: Mathematical expression string

657

"""

658

self.expression = expression

659

660

def substitute(self, substitutions: dict) -> float:

661

"""

662

Substitute parameter values and evaluate expression.

663

664

Args:

665

substitutions: Dictionary mapping parameter names to values

666

667

Returns:

668

float: Evaluated expression value

669

"""

670

pass

671

672

def get_free_parameters(self) -> set[str]:

673

"""

674

Get all free parameters in expression.

675

676

Returns:

677

set[str]: Set of parameter names

678

"""

679

pass

680

681

def __add__(self, other) -> 'FreeParameterExpression':

682

"""Addition with another expression or number."""

683

return FreeParameterExpression(f"({self.expression} + {other})")

684

685

def __mul__(self, other) -> 'FreeParameterExpression':

686

"""Multiplication with another expression or number."""

687

return FreeParameterExpression(f"({self.expression} * {other})")

688

689

# Parametric computation examples

690

def create_parametric_ansatz(n_qubits: int, n_layers: int) -> dict:

691

"""

692

Create parametric quantum ansatz with systematic parameter naming.

693

694

Args:

695

n_qubits: Number of qubits in ansatz

696

n_layers: Number of parametric layers

697

698

Returns:

699

dict: Parametric ansatz information and parameter structure

700

"""

701

from braket.circuits import Circuit

702

from braket.circuits.gates import Ry, Rz, CNot

703

704

circuit = Circuit()

705

parameters = {}

706

parameter_count = 0

707

708

# Initialize with Hadamard gates

709

for qubit in range(n_qubits):

710

circuit.h(qubit)

711

712

# Parametric layers

713

for layer in range(n_layers):

714

# Single-qubit rotations

715

for qubit in range(n_qubits):

716

# Y rotation parameter

717

theta_param = FreeParameter(f"theta_{layer}_{qubit}")

718

parameters[f"theta_{layer}_{qubit}"] = theta_param

719

circuit.ry(qubit, theta_param)

720

parameter_count += 1

721

722

# Z rotation parameter

723

phi_param = FreeParameter(f"phi_{layer}_{qubit}")

724

parameters[f"phi_{layer}_{qubit}"] = phi_param

725

circuit.rz(qubit, phi_param)

726

parameter_count += 1

727

728

# Entangling gates

729

for qubit in range(n_qubits - 1):

730

circuit.cnot(qubit, (qubit + 1) % n_qubits)

731

732

ansatz_info = {

733

'circuit': circuit,

734

'parameters': parameters,

735

'parameter_count': parameter_count,

736

'parameter_names': list(parameters.keys()),

737

'layers': n_layers,

738

'qubits': n_qubits,

739

'structure': 'Hardware-efficient ansatz'

740

}

741

742

return ansatz_info

743

744

def optimize_parameter_expressions(expressions: list[FreeParameterExpression]) -> dict:

745

"""

746

Optimize parameter expressions for efficient evaluation.

747

748

Args:

749

expressions: List of parameter expressions to optimize

750

751

Returns:

752

dict: Optimization analysis and recommendations

753

"""

754

optimization = {

755

'original_expressions': [expr.expression for expr in expressions],

756

'common_subexpressions': {},

757

'parameter_dependencies': {},

758

'evaluation_order': [],

759

'computational_complexity': {}

760

}

761

762

# Find common subexpressions

763

subexpr_count = {}

764

for expr in expressions:

765

# Simplified parsing - would need proper expression tree analysis

766

subexprs = expr.expression.split()

767

for subexpr in subexprs:

768

if subexpr.startswith('(') and ')' in subexpr:

769

subexpr_count[subexpr] = subexpr_count.get(subexpr, 0) + 1

770

771

# Identify reusable subexpressions

772

optimization['common_subexpressions'] = {

773

subexpr: count for subexpr, count in subexpr_count.items() if count > 1

774

}

775

776

# Analyze parameter dependencies

777

all_parameters = set()

778

for expr in expressions:

779

params = expr.get_free_parameters()

780

all_parameters.update(params)

781

optimization['parameter_dependencies'][expr.expression] = list(params)

782

783

optimization['total_unique_parameters'] = len(all_parameters)

784

785

return optimization

786

787

def generate_parameter_sweep_ranges(ansatz_info: dict, sweep_type: str = 'random') -> dict:

788

"""

789

Generate parameter value ranges for ansatz optimization.

790

791

Args:

792

ansatz_info: Ansatz information from create_parametric_ansatz

793

sweep_type: Type of parameter sweep ('random', 'grid', 'adaptive')

794

795

Returns:

796

dict: Parameter sweep configuration

797

"""

798

import numpy as np

799

800

parameter_names = ansatz_info['parameter_names']

801

n_params = len(parameter_names)

802

803

sweep_config = {

804

'sweep_type': sweep_type,

805

'parameter_count': n_params,

806

'parameter_ranges': {},

807

'suggested_values': {},

808

'optimization_hints': []

809

}

810

811

if sweep_type == 'random':

812

# Random sampling in [0, 2π] for rotation angles

813

for param_name in parameter_names:

814

sweep_config['parameter_ranges'][param_name] = (0, 2*np.pi)

815

sweep_config['suggested_values'][param_name] = np.random.random(10) * 2 * np.pi

816

817

sweep_config['optimization_hints'] = [

818

"Use random search for initial exploration",

819

"Consider Bayesian optimization for refinement",

820

f"Total parameter space size: {n_params} dimensions"

821

]

822

823

elif sweep_type == 'grid':

824

# Grid search with reasonable resolution

825

points_per_dim = max(3, int(10**(1/max(n_params, 1)))) # Adaptive grid resolution

826

827

for param_name in parameter_names:

828

sweep_config['parameter_ranges'][param_name] = (0, 2*np.pi)

829

sweep_config['suggested_values'][param_name] = np.linspace(0, 2*np.pi, points_per_dim)

830

831

total_evaluations = points_per_dim ** n_params

832

sweep_config['optimization_hints'] = [

833

f"Grid search with {points_per_dim} points per parameter",

834

f"Total evaluations needed: {total_evaluations}",

835

"Consider reducing parameters if grid is too large"

836

]

837

838

elif sweep_type == 'adaptive':

839

# Adaptive ranges based on parameter sensitivity

840

for param_name in parameter_names:

841

if 'theta' in param_name: # Y rotations - typically more sensitive

842

sweep_config['parameter_ranges'][param_name] = (0, np.pi)

843

else: # Z rotations - full range

844

sweep_config['parameter_ranges'][param_name] = (0, 2*np.pi)

845

846

# Initial sampling points

847

sweep_config['suggested_values'][param_name] = np.random.random(5) * sweep_config['parameter_ranges'][param_name][1]

848

849

sweep_config['optimization_hints'] = [

850

"Adaptive sampling based on parameter types",

851

"Y rotations limited to [0, π] for efficiency",

852

"Use gradient-based methods when possible"

853

]

854

855

return sweep_config

856

```

857

858

## Time Series and Program Sets

859

860

### Time Series Data Management

861

862

```python { .api }

863

from braket.timings import TimeSeries, TimeSeriesItem

864

865

class TimeSeriesItem:

866

"""Individual time series data item."""

867

868

def __init__(self, time: float, value: float):

869

"""

870

Initialize time series item.

871

872

Args:

873

time: Time point

874

value: Value at time point

875

"""

876

self.time = time

877

self.value = value

878

879

class TimeSeries:

880

"""Time series data representation."""

881

882

def __init__(self, values: list[TimeSeriesItem] = None):

883

"""

884

Initialize time series.

885

886

Args:

887

values: List of time series items

888

"""

889

self.values = values or []

890

891

def add_point(self, time: float, value: float) -> 'TimeSeries':

892

"""

893

Add data point to time series.

894

895

Args:

896

time: Time coordinate

897

value: Value at time

898

899

Returns:

900

TimeSeries: Self for method chaining

901

"""

902

self.values.append(TimeSeriesItem(time, value))

903

return self

904

905

def interpolate(self, time: float) -> float:

906

"""

907

Interpolate value at given time.

908

909

Args:

910

time: Time point for interpolation

911

912

Returns:

913

float: Interpolated value

914

"""

915

pass

916

917

def resample(self, new_times: list[float]) -> 'TimeSeries':

918

"""

919

Resample time series at new time points.

920

921

Args:

922

new_times: New time sampling points

923

924

Returns:

925

TimeSeries: Resampled time series

926

"""

927

pass

928

929

### Program Set Management

930

931

```python { .api }

932

from braket.program_sets import CircuitBinding, ParameterSets, ProgramSet

933

934

class CircuitBinding:

935

"""Circuit parameter binding for program sets."""

936

937

def __init__(self, circuit, parameter_values: dict):

938

"""

939

Initialize circuit binding.

940

941

Args:

942

circuit: Parameterized circuit

943

parameter_values: Parameter value assignments

944

"""

945

self.circuit = circuit

946

self.parameter_values = parameter_values

947

948

def bind_parameters(self):

949

"""

950

Create bound circuit with parameter values substituted.

951

952

Returns:

953

Circuit: Circuit with parameters bound

954

"""

955

pass

956

957

class ParameterSets:

958

"""Parameter set management for optimization."""

959

960

def __init__(self, parameter_names: list[str]):

961

"""

962

Initialize parameter sets.

963

964

Args:

965

parameter_names: Names of parameters to manage

966

"""

967

self.parameter_names = parameter_names

968

self.parameter_sets = []

969

970

def add_parameter_set(self, values: list[float]) -> 'ParameterSets':

971

"""

972

Add parameter value set.

973

974

Args:

975

values: Parameter values in order of parameter_names

976

977

Returns:

978

ParameterSets: Self for method chaining

979

"""

980

if len(values) != len(self.parameter_names):

981

raise ValueError(f"Expected {len(self.parameter_names)} values, got {len(values)}")

982

983

param_dict = dict(zip(self.parameter_names, values))

984

self.parameter_sets.append(param_dict)

985

return self

986

987

def generate_grid(self, ranges: dict, resolution: int = 10) -> 'ParameterSets':

988

"""

989

Generate grid of parameter values.

990

991

Args:

992

ranges: Parameter ranges {param_name: (min, max)}

993

resolution: Grid resolution per parameter

994

995

Returns:

996

ParameterSets: Self with grid parameter sets

997

"""

998

import itertools

999

import numpy as np

1000

1001

grid_values = []

1002

for param_name in self.parameter_names:

1003

if param_name in ranges:

1004

min_val, max_val = ranges[param_name]

1005

param_grid = np.linspace(min_val, max_val, resolution)

1006

grid_values.append(param_grid)

1007

else:

1008

grid_values.append([0.0]) # Default value

1009

1010

# Generate all combinations

1011

for combination in itertools.product(*grid_values):

1012

self.add_parameter_set(list(combination))

1013

1014

return self

1015

1016

class ProgramSet:

1017

"""Collection of parameterized programs for batch execution."""

1018

1019

def __init__(self, base_program, parameter_sets: ParameterSets):

1020

"""

1021

Initialize program set.

1022

1023

Args:

1024

base_program: Base parameterized program

1025

parameter_sets: Parameter sets for batch execution

1026

"""

1027

self.base_program = base_program

1028

self.parameter_sets = parameter_sets

1029

1030

def create_bindings(self) -> list[CircuitBinding]:

1031

"""

1032

Create circuit bindings for all parameter sets.

1033

1034

Returns:

1035

list[CircuitBinding]: Bound circuits for execution

1036

"""

1037

bindings = []

1038

for param_set in self.parameter_sets.parameter_sets:

1039

binding = CircuitBinding(self.base_program, param_set)

1040

bindings.append(binding)

1041

return bindings

1042

1043

def execute_all(self, device, shots: int = 1000) -> list:

1044

"""

1045

Execute all programs in set on device.

1046

1047

Args:

1048

device: Quantum device for execution

1049

shots: Number of shots per program

1050

1051

Returns:

1052

list: Results from all program executions

1053

"""

1054

bindings = self.create_bindings()

1055

bound_circuits = [binding.bind_parameters() for binding in bindings]

1056

1057

# Execute batch

1058

batch_task = device.run_batch(bound_circuits, shots=shots)

1059

return batch_task.results()

1060

1061

# Program set example

1062

def create_optimization_program_set(ansatz_info: dict, optimization_config: dict) -> ProgramSet:

1063

"""

1064

Create program set for variational quantum optimization.

1065

1066

Args:

1067

ansatz_info: Ansatz circuit information

1068

optimization_config: Optimization configuration

1069

1070

Returns:

1071

ProgramSet: Program set for batch optimization

1072

"""

1073

base_circuit = ansatz_info['circuit']

1074

parameter_names = ansatz_info['parameter_names']

1075

1076

# Create parameter sets based on optimization strategy

1077

parameter_sets = ParameterSets(parameter_names)

1078

1079

if optimization_config.get('method') == 'grid_search':

1080

ranges = optimization_config.get('parameter_ranges', {})

1081

resolution = optimization_config.get('resolution', 5)

1082

parameter_sets.generate_grid(ranges, resolution)

1083

1084

elif optimization_config.get('method') == 'random_search':

1085

import numpy as np

1086

n_samples = optimization_config.get('n_samples', 100)

1087

1088

for _ in range(n_samples):

1089

random_values = []

1090

for param_name in parameter_names:

1091

if param_name in optimization_config.get('parameter_ranges', {}):

1092

min_val, max_val = optimization_config['parameter_ranges'][param_name]

1093

random_val = np.random.uniform(min_val, max_val)

1094

else:

1095

random_val = np.random.uniform(0, 2*np.pi)

1096

random_values.append(random_val)

1097

1098

parameter_sets.add_parameter_set(random_values)

1099

1100

return ProgramSet(base_circuit, parameter_sets)

1101

```

1102

1103

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.