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

protocols.mddocs/

0

# Protocols and Extensibility

1

2

The protocols module provides Cirq's extensible protocol system based on structural subtyping. Protocols define interfaces that allow custom classes to integrate seamlessly with Cirq's quantum operations and enable polymorphic behavior without inheritance.

3

4

## Protocol System Overview

5

6

Cirq uses protocols (similar to type classes or traits) to provide extensible behavior for quantum objects. Any class can implement protocol methods to participate in Cirq's ecosystem.

7

8

## Core Protocol Functions

9

10

### Unitary Protocols

11

12

Protocols for working with unitary matrices and operations.

13

14

```python { .api }

15

def has_unitary(val: Any) -> bool:

16

"""Check if object has a unitary matrix representation."""

17

18

def unitary(val: Any) -> np.ndarray:

19

"""Get the unitary matrix of a quantum operation.

20

21

Args:

22

val: Object that may have a unitary representation

23

24

Returns:

25

Unitary matrix as numpy array

26

27

Raises:

28

TypeError: If val doesn't have a unitary representation

29

"""

30

31

def apply_unitary(val: Any, args: 'ApplyUnitaryArgs') -> Union[np.ndarray, None]:

32

"""Apply unitary effect to a state vector or density matrix.

33

34

Args:

35

val: Object with unitary effect

36

args: Arguments specifying target state and workspace

37

38

Returns:

39

Modified state array, or None if not implemented

40

"""

41

42

def apply_unitaries(vals: Iterable[Any], qubits: Sequence['cirq.Qid'],

43

args: 'ApplyUnitaryArgs') -> Union[np.ndarray, None]:

44

"""Apply multiple unitaries in sequence."""

45

```

46

47

### Channel Protocols

48

49

Protocols for quantum channels and noise operations.

50

51

```python { .api }

52

def has_kraus(val: Any) -> bool:

53

"""Check if object has Kraus representation."""

54

55

def kraus(val: Any) -> Tuple[np.ndarray, ...]:

56

"""Get Kraus operators of a quantum channel.

57

58

Returns:

59

Tuple of Kraus operator matrices

60

"""

61

62

def apply_channel(val: Any, args: 'ApplyChannelArgs') -> Union[np.ndarray, None]:

63

"""Apply quantum channel to a state.

64

65

Args:

66

val: Object representing quantum channel

67

args: Arguments specifying target state and workspace

68

69

Returns:

70

Modified state array, or None if not implemented

71

"""

72

73

def has_mixture(val: Any) -> bool:

74

"""Check if object has mixture representation."""

75

76

def mixture(val: Any) -> Tuple[Tuple[float, Any], ...]:

77

"""Get mixture representation as probability-unitary pairs."""

78

79

def apply_mixture(val: Any, args: 'ApplyMixtureArgs') -> Union[np.ndarray, None]:

80

"""Apply mixture representation to a state."""

81

```

82

83

### Decomposition Protocols

84

85

Protocols for decomposing operations into simpler components.

86

87

```python { .api }

88

def decompose(val: Any, *, intercepting_decomposer: Callable = None,

89

fallback_decomposer: Callable = None,

90

keep: Callable[[Any], bool] = None,

91

on_stuck_raise: Union[Exception, Callable[[], Exception]] = None) -> List[Any]:

92

"""Recursively decompose a value into simpler operations.

93

94

Args:

95

val: Object to decompose

96

intercepting_decomposer: Function called before default decomposition

97

fallback_decomposer: Function called if default decomposition fails

98

keep: Predicate for operations that should not be decomposed further

99

on_stuck_raise: Exception to raise if decomposition gets stuck

100

101

Returns:

102

List of decomposed operations

103

"""

104

105

def decompose_once(val: Any, *, default: Any = None) -> Union[List[Any], Any]:

106

"""Decompose value one level.

107

108

Args:

109

val: Object to decompose

110

default: Value to return if decomposition fails

111

112

Returns:

113

List of operations from one level of decomposition, or default

114

"""

115

116

def decompose_once_with_qubits(val: Any, qubits: Sequence['cirq.Qid'],

117

*, default: Any = None) -> Union[List[Any], Any]:

118

"""Decompose with explicit qubit specification."""

119

```

120

121

### Comparison and Equality Protocols

122

123

```python { .api }

124

def approx_eq(val: Any, other: Any, *, atol: Union[int, float] = 1e-8) -> bool:

125

"""Check approximate equality with tolerance.

126

127

Args:

128

val: First value to compare

129

other: Second value to compare

130

atol: Absolute tolerance for comparison

131

132

Returns:

133

True if values are approximately equal

134

"""

135

136

def equal_up_to_global_phase(val: Any, other: Any, *, atol: float = 1e-8) -> bool:

137

"""Check equality up to global phase factor."""

138

139

def commutes(val1: Any, val2: Any, *, atol: float = 1e-8) -> Union[bool, None]:

140

"""Check if two operations commute.

141

142

Returns:

143

True if they commute, False if they don't, None if unknown

144

"""

145

146

def definitely_commutes(val1: Any, val2: Any, *, atol: float = 1e-8) -> bool:

147

"""Check if operations definitely commute (conservative check)."""

148

```

149

150

### Measurement Protocols

151

152

Protocols for measurement operations and keys.

153

154

```python { .api }

155

def is_measurement(val: Any) -> bool:

156

"""Check if object represents a measurement operation."""

157

158

def measurement_key_name(val: Any) -> Optional[str]:

159

"""Get measurement key name, if any."""

160

161

def measurement_key_obj(val: Any) -> Optional['cirq.MeasurementKey']:

162

"""Get measurement key object, if any."""

163

164

def measurement_key_names(val: Any) -> AbstractSet[str]:

165

"""Get all measurement key names used by an object."""

166

167

def measurement_key_objs(val: Any) -> AbstractSet['cirq.MeasurementKey']:

168

"""Get all measurement key objects used by an object."""

169

170

def measurement_keys_touched(val: Any) -> FrozenSet['cirq.MeasurementKey']:

171

"""Get measurement keys read or written by an operation."""

172

```

173

174

### Parameterization Protocols

175

176

Protocols for parameterized operations.

177

178

```python { .api }

179

def is_parameterized(val: Any) -> bool:

180

"""Check if object contains symbolic parameters."""

181

182

def parameter_names(val: Any) -> AbstractSet[str]:

183

"""Get names of symbolic parameters."""

184

185

def parameter_symbols(val: Any) -> AbstractSet[sympy.Symbol]:

186

"""Get symbolic parameter symbols."""

187

188

def resolve_parameters(val: Any, resolver: 'cirq.ParamResolverOrSimilarType',

189

recursive: bool = True) -> Any:

190

"""Resolve symbolic parameters to concrete values.

191

192

Args:

193

val: Object with parameters to resolve

194

resolver: Maps parameter names/symbols to values

195

recursive: Whether to resolve parameters recursively

196

197

Returns:

198

Object with parameters resolved

199

"""

200

201

def resolve_parameters_once(val: Any, resolver: 'cirq.ParamResolverOrSimilarType') -> Any:

202

"""Resolve parameters one level (non-recursive)."""

203

```

204

205

### Shape and Size Protocols

206

207

```python { .api }

208

def num_qubits(val: Any) -> int:

209

"""Get number of qubits operated on by a gate or operation."""

210

211

def qid_shape(val: Any) -> Tuple[int, ...]:

212

"""Get shape tuple describing qid dimensions.

213

214

Returns:

215

Tuple where each element is the dimension of the corresponding qid

216

"""

217

```

218

219

### Inverse and Power Protocols

220

221

```python { .api }

222

def inverse(val: Any, default: Any = None) -> Any:

223

"""Get inverse of an operation.

224

225

Args:

226

val: Operation to invert

227

default: Value to return if inversion not possible

228

229

Returns:

230

Inverse operation, or default if not invertible

231

"""

232

233

def pow(val: Any, exponent: Any, default: Any = None) -> Any:

234

"""Raise operation to a power.

235

236

Args:

237

val: Operation to exponentiate

238

exponent: Power to raise to

239

default: Value to return if exponentiation not supported

240

241

Returns:

242

Operation raised to given power

243

"""

244

```

245

246

### Phase and Multiplication Protocols

247

248

```python { .api }

249

def phase_by(val: Any, phase_turns: float, qubit_index: int) -> Any:

250

"""Phase operation by rotating a qubit's eigenspace.

251

252

Args:

253

val: Operation to phase

254

phase_turns: Phase in units of full turns (2π radians)

255

qubit_index: Index of qubit to phase

256

257

Returns:

258

Phased operation

259

"""

260

261

def mul(lhs: Any, rhs: Any, default: Any = None) -> Any:

262

"""Multiply/compose two operations."""

263

```

264

265

### Circuit Diagram Protocol

266

267

```python { .api }

268

def circuit_diagram_info(val: Any, *, args: 'CircuitDiagramInfoArgs' = None) -> 'CircuitDiagramInfo':

269

"""Get information for drawing operation in circuit diagrams.

270

271

Args:

272

val: Operation to get diagram info for

273

args: Arguments affecting diagram generation

274

275

Returns:

276

Circuit diagram information

277

"""

278

```

279

280

### QASM Generation Protocol

281

282

```python { .api }

283

def qasm(val: Any, *, args: 'QasmArgs' = None, default: Any = None) -> Union[str, Any]:

284

"""Generate QASM code for an operation.

285

286

Args:

287

val: Operation to convert to QASM

288

args: QASM generation arguments

289

default: Value to return if QASM generation fails

290

291

Returns:

292

QASM string representation

293

"""

294

```

295

296

### Other Protocols

297

298

```python { .api }

299

def act_on(val: Any, args: 'cirq.ActOnArgs', allow_decompose: bool = True) -> bool:

300

"""Apply operation effect to a simulation state.

301

302

Returns:

303

True if operation was applied successfully, False otherwise

304

"""

305

306

def pauli_expansion(val: Any) -> Dict['cirq.PauliString', complex]:

307

"""Get Pauli expansion of an operation."""

308

309

def has_stabilizer_effect(val: Any) -> Optional[bool]:

310

"""Check if operation has stabilizer effect (preserves stabilizer states)."""

311

312

def control_keys(val: Any) -> FrozenSet['cirq.MeasurementKey']:

313

"""Get measurement keys that control this operation."""

314

315

def trace_distance_bound(val: Any) -> Optional[float]:

316

"""Upper bound on trace distance from perfect operation."""

317

```

318

319

## Protocol Support Classes

320

321

### Apply Unitary Support

322

323

```python { .api }

324

class ApplyUnitaryArgs:

325

"""Arguments for apply_unitary protocol method."""

326

327

def __init__(self, target_tensor: np.ndarray,

328

available_buffer: np.ndarray,

329

axes: Sequence[int],

330

default: Any = None) -> None:

331

"""Initialize apply unitary arguments.

332

333

Args:

334

target_tensor: State tensor to modify

335

available_buffer: Workspace tensor of same shape

336

axes: Tensor axes corresponding to qubits

337

default: Default value to return if application fails

338

"""

339

340

@property

341

def target_tensor(self) -> np.ndarray:

342

"""Target tensor to apply unitary to."""

343

344

@property

345

def available_buffer(self) -> np.ndarray:

346

"""Workspace buffer tensor."""

347

348

@property

349

def axes(self) -> Tuple[int, ...]:

350

"""Axes in tensor corresponding to qubits."""

351

352

def subspace_view(self, little_endian_bits_int: int = 0) -> np.ndarray:

353

"""Get view of a computational basis subspace."""

354

355

def swap_target_tensor_for(self, new_target_tensor: np.ndarray) -> 'ApplyUnitaryArgs':

356

"""Return args with different target tensor."""

357

358

class SupportsConsistentApplyUnitary:

359

"""Marker interface for consistent unitary application."""

360

361

class SupportsExplicitHasUnitary:

362

"""Marker interface for explicit unitary support."""

363

```

364

365

### Apply Channel Support

366

367

```python { .api }

368

class ApplyChannelArgs:

369

"""Arguments for apply_channel protocol method."""

370

371

def __init__(self, target_tensor: np.ndarray,

372

out_buffer: np.ndarray,

373

auxiliary_buffer0: np.ndarray,

374

auxiliary_buffer1: np.ndarray,

375

left_axes: Sequence[int],

376

right_axes: Sequence[int]) -> None:

377

"""Initialize apply channel arguments."""

378

379

class ApplyMixtureArgs:

380

"""Arguments for apply_mixture protocol method."""

381

382

def __init__(self, target_tensor: np.ndarray,

383

available_buffer: np.ndarray,

384

axes: Sequence[int]) -> None:

385

"""Initialize apply mixture arguments."""

386

```

387

388

### Circuit Diagram Support

389

390

```python { .api }

391

class CircuitDiagramInfo:

392

"""Information for drawing operations in circuit diagrams."""

393

394

def __init__(self, wire_symbols: Tuple[str, ...],

395

exponent: Any = 1,

396

connected: bool = True,

397

exponent_qubit_index: Optional[int] = None,

398

auto_exponent_parens: bool = True) -> None:

399

"""Initialize circuit diagram info.

400

401

Args:

402

wire_symbols: Symbols to show on each wire

403

exponent: Exponent to display (for gates like X^0.5)

404

connected: Whether to connect symbols with lines

405

exponent_qubit_index: Which wire to show exponent on

406

auto_exponent_parens: Whether to add parentheses around exponent

407

"""

408

409

@property

410

def wire_symbols(self) -> Tuple[str, ...]:

411

"""Symbols for each wire."""

412

413

def with_wire_symbols(self, wire_symbols: Sequence[str]) -> 'CircuitDiagramInfo':

414

"""Return info with different wire symbols."""

415

416

class CircuitDiagramInfoArgs:

417

"""Arguments for circuit diagram info generation."""

418

419

def __init__(self, known_qubits: Optional[Iterable['cirq.Qid']] = None,

420

known_qubit_count: Optional[int] = None,

421

use_unicode_characters: bool = True,

422

precision: Optional[int] = None,

423

label_map: Optional[Dict[str, str]] = None) -> None:

424

"""Initialize circuit diagram args."""

425

426

class LabelEntity:

427

"""Entity for labeling in circuit diagrams."""

428

429

def __init__(self, label: str) -> None:

430

"""Initialize label entity."""

431

```

432

433

### Decomposition Context

434

435

```python { .api }

436

class DecompositionContext:

437

"""Context for operation decomposition."""

438

439

def __init__(self, qubit_manager: Optional['cirq.QubitManager'] = None) -> None:

440

"""Initialize decomposition context."""

441

442

@property

443

def qubit_manager(self) -> Optional['cirq.QubitManager']:

444

"""Qubit manager for allocating ancillas during decomposition."""

445

```

446

447

### QASM Support

448

449

```python { .api }

450

class QasmArgs:

451

"""Arguments for QASM generation."""

452

453

def __init__(self, precision: int = 10,

454

version: str = '2.0',

455

qubit_id_map: Optional[Dict['cirq.Qid', str]] = None,

456

meas_key_id_map: Optional[Dict[str, str]] = None) -> None:

457

"""Initialize QASM arguments."""

458

459

def format_field(self, value: Any) -> str:

460

"""Format a field for QASM output."""

461

462

def validate_version(self, supported_versions: Sequence[str]) -> str:

463

"""Validate QASM version."""

464

```

465

466

## JSON Serialization Support

467

468

### JSON Protocol Classes

469

470

```python { .api }

471

class HasJSONNamespace:

472

"""Interface for objects with JSON namespace."""

473

474

@property

475

@abc.abstractmethod

476

def _json_namespace_(self) -> str:

477

"""JSON namespace for serialization."""

478

479

class JsonResolver:

480

"""Resolver for JSON object deserialization."""

481

482

def __init__(self, cirq_type_to_resolver: Dict[str, Callable] = None) -> None:

483

"""Initialize JSON resolver."""

484

485

def resolve(self, cirq_type: str, obj_dict: Dict[str, Any]) -> Any:

486

"""Resolve JSON object to Python object."""

487

488

class SerializableByKey:

489

"""Interface for objects serializable by key."""

490

491

@property

492

@abc.abstractmethod

493

def _serialization_key_(self) -> str:

494

"""Key used for serialization."""

495

496

DEFAULT_RESOLVERS: List[JsonResolver]

497

"""Default JSON resolvers for Cirq objects."""

498

```

499

500

### JSON Utility Functions

501

502

```python { .api }

503

def to_json(obj: Any) -> str:

504

"""Convert object to JSON string."""

505

506

def read_json(file_or_fn: Union[str, pathlib.Path, IO],

507

resolvers: Sequence[JsonResolver] = None) -> Any:

508

"""Read object from JSON file."""

509

510

def to_json_gzip(obj: Any) -> bytes:

511

"""Convert object to gzip-compressed JSON."""

512

513

def read_json_gzip(file_or_fn: Union[str, pathlib.Path, IO],

514

resolvers: Sequence[JsonResolver] = None) -> Any:

515

"""Read object from gzip-compressed JSON file."""

516

517

def cirq_type_from_json(json_dict: Dict[str, Any],

518

resolvers: Sequence[JsonResolver] = None) -> Any:

519

"""Convert JSON dictionary to Cirq object."""

520

521

def obj_to_dict_helper(obj: Any, attribute_names: Iterable[str],

522

namespace: Optional[str] = None) -> Dict[str, Any]:

523

"""Helper for converting objects to dictionaries."""

524

525

def dataclass_json_dict(obj: Any) -> Dict[str, Any]:

526

"""Convert dataclass to JSON dictionary."""

527

528

def json_cirq_type(cls: type) -> type:

529

"""Decorator to register class for JSON serialization."""

530

531

def json_namespace(namespace: str) -> Callable[[type], type]:

532

"""Decorator to set JSON namespace for a class."""

533

```

534

535

## Protocol Support Interfaces

536

537

All protocol support interfaces follow the naming pattern `Supports*`:

538

539

```python { .api }

540

class SupportsActOn:

541

"""Supports acting on simulation states."""

542

543

class SupportsActOnQubits:

544

"""Supports acting on qubits in simulation."""

545

546

class SupportsApplyChannel:

547

"""Supports applying quantum channels."""

548

549

class SupportsApplyMixture:

550

"""Supports applying mixture representations."""

551

552

class SupportsApproximateEquality:

553

"""Supports approximate equality comparison."""

554

555

class SupportsCircuitDiagramInfo:

556

"""Supports circuit diagram generation."""

557

558

class SupportsCommutes:

559

"""Supports commutativity checking."""

560

561

class SupportsControlKey:

562

"""Supports control keys for conditional operations."""

563

564

class SupportsDecompose:

565

"""Supports operation decomposition."""

566

567

class SupportsDecomposeWithQubits:

568

"""Supports decomposition with explicit qubits."""

569

570

class SupportsEqualUpToGlobalPhase:

571

"""Supports equality up to global phase."""

572

573

class SupportsExplicitQidShape:

574

"""Supports explicit qid shape specification."""

575

576

class SupportsExplicitNumQubits:

577

"""Supports explicit qubit count specification."""

578

579

class SupportsJSON:

580

"""Supports JSON serialization."""

581

582

class SupportsKraus:

583

"""Supports Kraus operator representation."""

584

585

class SupportsMeasurementKey:

586

"""Supports measurement keys."""

587

588

class SupportsMixture:

589

"""Supports mixture representation."""

590

591

class SupportsParameterization:

592

"""Supports symbolic parameterization."""

593

594

class SupportsPauliExpansion:

595

"""Supports Pauli operator expansion."""

596

597

class SupportsPhase:

598

"""Supports phase operations."""

599

600

class SupportsQasm:

601

"""Supports QASM generation."""

602

603

class SupportsQasmWithArgs:

604

"""Supports QASM generation with arguments."""

605

606

class SupportsQasmWithArgsAndQubits:

607

"""Supports QASM generation with arguments and qubits."""

608

609

class SupportsTraceDistanceBound:

610

"""Supports trace distance bounds."""

611

612

class SupportsUnitary:

613

"""Supports unitary matrix representation."""

614

```

615

616

## Measurement Key Utilities

617

618

```python { .api }

619

def with_key_path(operation: 'cirq.Operation', path: Tuple[str, ...]) -> 'cirq.Operation':

620

"""Add key path to measurement operation."""

621

622

def with_key_path_prefix(operation: 'cirq.Operation', prefix: Tuple[str, ...]) -> 'cirq.Operation':

623

"""Add key path prefix to measurement operation."""

624

625

def with_measurement_key_mapping(operation: 'cirq.Operation',

626

key_map: Dict[str, str]) -> 'cirq.Operation':

627

"""Apply measurement key mapping to operation."""

628

629

def with_rescoped_keys(operation: 'cirq.Operation',

630

path: Tuple[str, ...]) -> 'cirq.Operation':

631

"""Rescope measurement keys with path."""

632

```

633

634

## Validation Functions

635

636

```python { .api }

637

def validate_mixture(mixture: Sequence[Tuple[float, Any]]) -> None:

638

"""Validate mixture representation (probabilities sum to 1)."""

639

640

def trace_distance_from_angle_list(angles: Sequence[float]) -> float:

641

"""Calculate trace distance bound from rotation angles."""

642

```

643

644

## Usage Examples

645

646

### Implementing Protocol Methods

647

648

```python

649

import cirq

650

import numpy as np

651

652

class MyGate(cirq.Gate):

653

"""Custom gate implementing multiple protocols."""

654

655

def __init__(self, theta: float):

656

self.theta = theta

657

658

def _num_qubits_(self) -> int:

659

return 1

660

661

# Unitary protocol

662

def _unitary_(self) -> np.ndarray:

663

"""Return unitary matrix."""

664

c, s = np.cos(self.theta/2), np.sin(self.theta/2)

665

return np.array([[c, -1j*s], [-1j*s, c]])

666

667

# Decomposition protocol

668

def _decompose_(self, qubits):

669

"""Decompose into basic gates."""

670

return [cirq.rx(self.theta)(qubits[0])]

671

672

# Circuit diagram protocol

673

def _circuit_diagram_info_(self, args):

674

"""Circuit diagram representation."""

675

return cirq.CircuitDiagramInfo(

676

wire_symbols=(f"MyGate({self.theta:.2f})",)

677

)

678

679

# Parameterization protocol

680

def _is_parameterized_(self) -> bool:

681

"""Check if gate has symbolic parameters."""

682

return isinstance(self.theta, sympy.Symbol)

683

684

# Approximate equality protocol

685

def _approx_eq_(self, other, atol):

686

"""Check approximate equality."""

687

return (isinstance(other, MyGate) and

688

abs(self.theta - other.theta) <= atol)

689

690

# Use the custom gate

691

gate = MyGate(np.pi/4)

692

q = cirq.LineQubit(0)

693

694

# Protocol functions work automatically

695

print(f"Has unitary: {cirq.has_unitary(gate)}")

696

print(f"Unitary matrix:\n{cirq.unitary(gate)}")

697

print(f"Decomposition: {cirq.decompose(gate(q))}")

698

```

699

700

### Using Protocol Functions

701

702

```python

703

import cirq

704

import numpy as np

705

706

# Create various operations

707

h_gate = cirq.H

708

x_gate = cirq.X

709

noise = cirq.depolarize(0.1)

710

measurement = cirq.measure(cirq.LineQubit(0), key='result')

711

712

# Check what protocols they support

713

operations = [h_gate, x_gate, noise, measurement]

714

715

for op in operations:

716

print(f"\nOperation: {op}")

717

print(f" Has unitary: {cirq.has_unitary(op)}")

718

print(f" Has Kraus: {cirq.has_kraus(op)}")

719

print(f" Is measurement: {cirq.is_measurement(op)}")

720

print(f" Is parameterized: {cirq.is_parameterized(op)}")

721

722

# Get protocol information when available

723

if cirq.has_unitary(op):

724

print(f" Unitary shape: {cirq.unitary(op).shape}")

725

if cirq.is_measurement(op):

726

print(f" Measurement key: {cirq.measurement_key_name(op)}")

727

```

728

729

### Parameter Resolution

730

731

```python

732

import cirq

733

import sympy

734

735

# Create parameterized circuit

736

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

737

qubits = cirq.LineQubit.range(2)

738

739

circuit = cirq.Circuit([

740

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

741

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

742

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

743

])

744

745

print(f"Is parameterized: {cirq.is_parameterized(circuit)}")

746

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

747

748

# Resolve parameters

749

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

750

resolved_circuit = cirq.resolve_parameters(circuit, resolver)

751

752

print(f"After resolution: {cirq.is_parameterized(resolved_circuit)}")

753

```

754

755

This comprehensive protocol system enables Cirq's extensible architecture and allows custom quantum objects to integrate seamlessly with the framework.