> ## Documentation Index
> Fetch the complete documentation index at: https://docs.haiqu.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview

> Build hybrid quantum-classical programs from composable layers and run them with haiqu.flow

A **hybrid program** is a pipeline that you assemble yourself from small building blocks called
**layers**. Each layer is one processing step — transpile the circuits, pack them onto spare
qubits, apply error mitigation, run them on a device. Stacking layers into a program lets you
describe exactly how your circuits are prepared, executed, and post-processed, combining classical
processing with quantum execution in a single object. You then execute the program with
[`haiqu.flow`](/reference/run/flow).

<Tip>
  * **Layer** — one processing step (transpilation, packing, mitigation, device execution, …).
  * **Program** — an ordered pipeline of layers, from an `InputLayer` to a `DeviceLayer`.
  * **Hybrid program** — a program that interleaves classical pre/post-processing with quantum
    execution; "hybrid" because both kinds of work live in the same pipeline.
  * **Flow** — running a hybrid program against concrete circuits with `haiqu.flow(...)`.
</Tip>

## Flow vs. run

[`haiqu.run`](/reference/run/run) executes circuits through one fixed, built-in pipeline controlled
by keyword flags (`use_mitigation`, `use_packing`, …). `haiqu.flow` runs a pipeline that **you**
compose layer by layer, so you control which steps run and in what order. Both accept the same
circuits, parameters, and observables, and both return a job whose `result()` follows the same
nested-list ordering.

## Anatomy of a program

Every program starts with an `InputLayer` (the entry point for your circuits) and ends with a
`DeviceLayer` (the backend that runs them). Anything in between is optional processing. The
smallest valid program just feeds circuits straight to a device:

```python theme={null}
from haiqu.sdk.hybrid import HybridProgram, layers

program = HybridProgram(layers=[
    layers.InputLayer(),
    layers.DeviceLayer(device_id="aer_simulator"),
])
```

Add processing steps between the two ends to shape the pipeline:

```python theme={null}
program = HybridProgram(layers=[
    layers.InputLayer(),
    layers.TranspilationLayer(optimization_level=3),
    layers.PackingLayer(pack_size=2),
    layers.EstimatorLayer(),
    layers.DeviceLayer(device_id="fake_torino"),
])
```

A program is validated when you build it. The rules are:

* The first layer must be an `InputLayer`, and the last must be a `DeviceLayer`.
* There is exactly one of each — no `InputLayer` or `DeviceLayer` in the middle.
* At most one *grouped* error-mitigation layer (`EstimatorLayer` or `DistributionMitigationLayer`);
  the two are mutually exclusive.

## The layer catalog

| Layer                             | Purpose                                                                   | Key parameters             |
| :-------------------------------- | :------------------------------------------------------------------------ | :------------------------- |
| **`InputLayer`**                  | Entry point; every program starts with one.                               | —                          |
| **`TranspilationLayer`**          | Transpile the circuits for the target backend.                            | `optimization_level` (0–3) |
| **`PackingLayer`**                | Pack several copies of a circuit into one run to use spare device qubits. | `pack_size` (≥ 2)          |
| **`EstimatorLayer`**              | Measure observable expectation values with error mitigation.              | mitigation flags           |
| **`DistributionMitigationLayer`** | Mitigate errors on the raw measured distribution.                         | mitigation flags           |
| **`DeviceLayer`**                 | Run the circuits on a backend; every program ends with one.               | `device_id`, `options`     |

Leave a layer's parameters unset to take its defaults (for example, `TranspilationLayer()` uses the
backend's default optimization level, and `PackingLayer()` picks a pack size automatically).

<Note>
  **Handling observables.** A program that supplies observables must include a layer that computes
  them — either the grouped `EstimatorLayer` (expectation values with error mitigation) or the
  fine-grained `ObservableSplitLayer` → `QWCComputeLayer` pair. When you read the raw measurement
  distribution instead (no observables), reach for `DistributionMitigationLayer`. A program uses at
  most one grouped mitigation layer — `EstimatorLayer` or `DistributionMitigationLayer`.
</Note>

For full control you can assemble the pipeline by hand from individual steps instead of the grouped
layers: `ObservableSplitLayer` and `QWCComputeLayer` compute observables, while `NoiseTailoringLayer`,
`DynamicalDecouplingLayer`, and `AdvancedReadoutMitigationLayer` apply individual mitigation
techniques. See the [hybrid program reference](/reference/run/hybrid_program) for every layer and its
fields.

## Next steps

<Card title="Building and running flows" icon="play" href="/hybrid/flows">
  Compose a program from layers and execute it with `haiqu.flow`, step by step.
</Card>

Before running a flow you need to authenticate with [`haiqu.login`](/reference/core/login) and
start an experiment — see the [Get Started guide](/quickstart/qs_intro).
