Skip to content

HybridProgram

from cascaqit import HybridProgram

HybridProgram

HybridProgram(
    program_id: str,
    syntax_hash: str = "0" * 64,
    blocks: tuple[HybridProgramBlock, ...] = (),
    dependencies: tuple[BlockDependency, ...] = (),
    source_map: SourceMap = SourceMap(),
    metadata: dict[str, Any] = dict(),
    schema_version: str = ORCHESTRATION_SCHEMA_VERSION,
    _payloads: Mapping[str, object] = dict(),
    _hir: SemanticProgramHIR | None = None,
)

Compose Digital circuits, Analog evolution and terminal measurement in program order. Start with HybridProgram(program_id="experiment"), then call digital(), analog() and measure_all(). These methods return new programs; retain the returned value. Payloads are snapshotted, so later changes to an original Circuit do not update an attached block.

For direct construction, blocks, dependencies, source_map, syntax_hash, metadata and schema_version describe orchestration for advanced compiler workflows. Do not supply the private _payloads or _hir arguments yourself. Block names aid reading and may repeat; use a unique block_id to identify an invocation.

This example uses only a Digital block but follows the same Hybrid submission path. Leave terminal measurement out of the payload and let the Hybrid program own it.

from cascaqit import Circuit, HybridProgram

original = HybridProgram(program_id="hybrid_x")
program = original.digital("flip", Circuit(1).x(0)).measure_all()
assert original.blocks == ()
assert program.run(shots=32, seed=7).result().counts == {"1": 32}
restored = HybridProgram.from_ir(program.to_ir())
assert restored.run(shots=32, seed=7).result().counts == {"1": 32}

Choose serialization by purpose: to_dict()/to_json() save orchestration declarations without execution payloads. to_ir() exports a bound program with payloads for execution after from_ir(). See Shared parameters for a complete experiment.

digital

digital(
    name: str,
    circuit: Circuit | DigitalProgramIR,
    *,
    mapping: Mapping[str, str] | None = None,
) -> HybridProgram

Append a snapshot of Circuit or DigitalProgramIR and return a new HybridProgram. name labels the block. mapping maps payload logical IDs to target IDs, retaining identity mappings for omitted entries; unknown logical IDs raise. Blocks cannot be appended after terminal measurement.

analog

analog(
    name: str,
    program: AHSProgram | ProgramIR,
    *,
    mapping: Mapping[str, str] | None = None,
) -> HybridProgram

Append a snapshot of AHSProgram or ProgramIR and return a new HybridProgram. mapping follows the same rules as digital(); cross-block logical order and mapping still require compilation and execution checks. An AHSProgram payload used in Hybrid need not declare its own terminal measurement.

measure_all

measure_all(
    *, name: str = "measure", key: str = "result"
) -> HybridProgram

Add one computational-basis terminal measurement over existing logical IDs and return a new program. name labels the block and key identifies the measurement in results. An empty program or a second measurement raises ValueError; only one terminal measurement is supported.

parameters

parameters: ParameterManager

Collect parameters from attached Circuit/AHSProgram payloads and return ParameterManager with parameter-to-block mappings. Identical declarations with the same name share a binding. Conflicting declarations, including type, unit or default differences, raise ValueError.

bind

bind(
    values: Mapping[str, bool | int | float],
) -> HybridProgram

Bind values by parameter name, project them into payloads and return a new program. The parameter manager checks missing values, unknown names and bounds. Failure raises ProgramValidationError with parameter diagnostics retained in error metadata.

with_payload

with_payload(
    block_name_or_id: str, payload: object
) -> HybridProgram

Attach a payload snapshot by block_id or unique block name and return a new program. The payload type must match the Digital or Analog block; use an ID for repeated names. Parameter declarations and the payload digest are updated. Use this to supply executable content to orchestration created by from_hir().

payload

payload(block_name_or_id: str) -> object

Return a payload snapshot by ID or unique block name, not the internal mutable object. Unknown or ambiguous names and missing payloads raise ValueError. Measurement blocks have no Digital/Analog payload.

analyze

analyze() -> HybridAnalysisResult

Return HybridAnalysisResult with program and parameter-schema hashes, validate() diagnostics and any retained HIR. Programs built through Python may have hir=None. Payloads are not executed.

validate

validate() -> tuple[OrchestrationDiagnosticIR, ...]

Return orchestration diagnostics for blocks, dependencies, mapping continuity and measurement lifecycle. No diagnostics means those checks found no problems; it does not replace payload binding, target validation or execution preflight.

compile

compile(
    *, allowed_capabilities: Iterable[str] | None = None
) -> HybridCompileResult

Return HybridCompileResult with a graph, non-executable local plan and diagnostics; plan may be None on failure. allowed_capabilities restricts permitted capabilities. The plan itself cannot be executed by LocalBackend.run().

execution_builder

execution_builder(
    *,
    params: Mapping[str, bool | int | float] | None = None,
    shots: int = 1000,
    seed: int = 0,
    measurement_key: str | None = None,
    parameterized: bool = False,
) -> LocalHybridExecutionBuilder

Compile and attach owned payloads to LocalHybridExecutionBuilder. Ordinary mode binds params or defaults. parameterized=True retains factories for scans and cannot be combined with params. shots, seed and measurement_key configure measurement. Compilation failures or missing payloads raise ProgramValidationError. The returned builder has not executed.

prepare

prepare(
    *,
    params: Mapping[str, bool | int | float] | None = None,
    shots: int = 1000,
    seed: int = 0,
    measurement_key: str | None = None,
    bundle_id: str | None = None,
) -> LocalExecutionBundleResult

Call execution_builder().build() and return LocalExecutionBundleResult; inspect bundle and diagnostics. bundle_id optionally names the bundle. This prepares one bound execution without sampling or returning ResultIR.

run

run(
    *,
    backend: object | None = None,
    params: Mapping[str, bool | int | float] | None = None,
    sweep: ParameterScan | None = None,
    noise: object | None = None,
    options: SimulationOptions | None = None,
    shots: int = 1000,
    seed: int | None = None,
    optimization_level: int = 0,
) -> object

Call backend.run() and return a job; obtain the result with job.result(). An omitted backend creates LocalBackend. params, sweep, noise, options, shots and seed are passed to the backend. optimization_level accepts 0 or 1; level 1 binds and simplifies the program while retaining an optimization report, and currently cannot be combined with sweep.

block_ids

block_ids(block_name: str) -> tuple[str, ...]

Return invocation IDs for a block name in current program order. No matches produce an empty tuple.

resolve_block_id

resolve_block_id(block_name: str) -> str

Resolve a unique block name to an invocation ID. Missing or repeated names raise ValueError. For repeated invocations, obtain block_ids() and select a specific ID.

add

add(
    block: HybridProgramBlock, *, index: int | None = None
) -> HybridProgram

Insert a cascaqit.hybrid.HybridProgramBlock and return a new program. index=None appends; an explicit index must be between 0 and the current block count. This advanced entry point adds an orchestration block without attaching an execution payload; use with_payload() when needed.

remove

remove(block_id: str) -> HybridProgram

Remove a block by ID, its associated dependencies and its payload, returning a new program. Unknown IDs raise ValueError. Recheck measurement and logical mappings after removal.

compose

compose(other: HybridProgram) -> HybridProgram

Append another HybridProgram’s blocks and dependencies, merge payloads and source information, and return a new program. It does not rename colliding block IDs or repair measurement order; validate()/compile() the composition.

reorder

reorder(block_id: str, new_index: int) -> HybridProgram

Move block_id to zero-based new_index and return a new program. The index must be less than the block count. Out-of-range indices raise IndexError and unknown IDs raise ValueError. Explicit dependencies are not rewritten.

set_execution_order

set_execution_order(
    block_ids: Iterable[str],
) -> HybridProgram

Return a program ordered by an exact permutation of all current block IDs. IDs cannot be omitted, repeated or added. Explicit dependencies must remain compatible with the order or later checks fail.

add_dependency

add_dependency(
    dependency: BlockDependency,
) -> HybridProgram

Append a cascaqit.hybrid.BlockDependency and return a new program. This adds a declaration; endpoint, cycle and ordering constraints are checked by subsequent validate()/compile() calls.

from_hir

from_hir(hir: SemanticProgramHIR) -> HybridProgram

Build orchestration blocks from an analyzed SemanticProgramHIR and retain the HIR. Invalid types or references to unknown declarations raise. Execution payloads are not supplied by this conversion; attach them with with_payload().

to_ir

to_ir() -> HybridProgramIR

Return a bound HybridProgramIR containing payloads. Missing payloads, unbound parameters, embedded terminal measurements and unsupported payload types raise. Use to_dict() for orchestration declarations; use this IR to retain a program for restored execution.

from_ir

from_ir(program: HybridProgramIR) -> HybridProgram

Restore a payload-owning HybridProgram from HybridProgramIR, rebuilding Digital, Analog and measurement blocks while preserving block IDs, mappings and metadata. A measurement block requires one measurement entry. Other input types raise TypeError.

to_dict

to_dict() -> dict[str, Any]

Return orchestration declarations including blocks, dependencies, source information and metadata. Private payloads and HIR are deliberately excluded. A program restored from this dictionary requires payloads to be reattached before execution.

to_json

to_json(*, indent: int | None = None) -> str

Encode the orchestration declarations from to_dict() as a JSON string. indent controls formatting. No file is written and execution payloads are not saved.

stable_hash

stable_hash() -> str

Return the SHA-256 digest of canonical orchestration JSON. A payload_hash recorded in block metadata participates in the digest, but full private payloads are not serialized directly. This does not establish physical equivalence between programs.

from_dict

from_dict(data: dict[str, Any]) -> HybridProgram

Restore HybridProgram from a dictionary. Only orchestration fields are restored, not execution payloads or HIR. Missing required fields or invalid values can raise KeyError, TypeError or ValueError.

from_json

from_json(text: str) -> HybridProgram

Parse a JSON object and call from_dict(), returning HybridProgram. Invalid JSON raises a parsing error; a non-object root raises TypeError.