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

# Rigetti Cepheus-1-108Q

> Submitting gate-model and timing-aware programs to Rigetti's Cepheus-1-108Q through the QbraidProvider, from any qBraid-supported framework.

<Info>
  Device ID: `rigetti:rigetti:qpu:cepheus-1-108q`  ·  108 qubits
   ·  superconducting  ·  accessed through
  [`QbraidProvider`](/v2/sdk/user-guide/providers/native)
</Info>

Cepheus-1-108Q is Rigetti's 108-qubit superconducting processor, available on qBraid with no
Rigetti account of your own. You write a circuit in whichever framework you already use, hand it
to `device.run()`, and qBraid handles conversion, compilation, submission and results.

This page covers the one thing about Cepheus that surprises people: **it has two different
compilation paths, and which one your program takes depends on whether it contains timing
instructions.** Everything else follows from that.

<Note>
  This is the **direct** Rigetti device, billed per minute of execution. Cepheus-1-108Q is also
  offered through Amazon Braket (`aws:rigetti:qpu:cepheus-1-108q`), which is billed per task +
  per shot and has different compilation behavior. If you are working with delays or other
  timing operations, you want the direct device documented here, since Braket has no gate-level delay.

  For direct QCS access using your own Rigetti credentials, see
  [RigettiProvider](/v2/sdk/user-guide/providers/rigetti) instead.
</Note>

## Quick start

A plain gate-model circuit needs nothing special. Write it however you like and submit:

```python theme={null}
from qbraid.runtime import QbraidProvider
from qiskit import QuantumCircuit

provider = QbraidProvider()
device = provider.get_device("rigetti:rigetti:qpu:cepheus-1-108q")

circuit = QuantumCircuit(2, 2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure([0, 1], [0, 1])

job = device.run(circuit, shots=10)
job.wait_for_final_state()
print(job.result().data.get_counts())
# {'00': 2, '01': 1, '11': 7}
```

`H` and `CX` are not gates Cepheus can execute. You did not have to care, because this program
took the **compiled path**.

## The two compilation paths

Whether your program is compiled for you, or has to arrive ready to run, depends entirely on
whether it contains **Quil-T** instructions: Rigetti's timing and pulse-level operations, of
which `DELAY` is the one most people meet first.

| Your program                                 | Path         | Compiler                                                 | You must write        |
| :------------------------------------------- | :----------- | :------------------------------------------------------- | :-------------------- |
| Gates only                                   | **compiled** | [quilc](https://github.com/quil-lang/quilc) nativizes it | any gates you like    |
| Contains a delay or other Quil-T instruction | **direct**   | quilc is skipped                                         | **native gates only** |

The reason is not a qBraid limitation. quilc is a gate-model compiler, and as Rigetti's docs put
it plainly:

> Quil-T instructions are not supported by quilc or the QVM.

So a program containing `DELAY` cannot go through quilc at all. qBraid detects Quil-T
automatically and routes such programs straight to the QCS translation service, which does accept
timing instructions. Nothing is dropped and you do not set a flag. But because quilc is what
would normally have nativized your gates, **that job is now yours**.

<Warning>
  If a program contains a delay and uses a non-native gate, it fails at translation. Rigetti
  names the instruction it could not execute:

  ```
  Translation failed for quantum processor 'Cepheus-1-108Q': ... message:
  "input program error: Failed to schedule Quil program: at instruction 0 ("X 0"):
  this instruction must be replaced or decomposed prior to compilation"
  ```

  This is the single most common error on this device: your timing program reached the QPU with a
  gate it cannot execute, here `X 0`. See [Native gates](#native-gates) below.
</Warning>

## Native gates

When you take the direct path, these are the only instructions Cepheus-1-108Q accepts. The set
comes from the device's own ISA:

| Instruction | Accepts              | Notes                               |
| :---------- | :------------------- | :---------------------------------- |
| `RX(θ)`     | **only ±π/2 and ±π** | any other angle has no calibration  |
| `RZ(θ)`     | **any angle**        | parametric, so no angle restriction |
| `CZ`        | —                    | the only two-qubit gate             |
| `I`         | —                    | identity                            |
| `MEASURE`   | —                    | readout                             |

The `RX` restriction is the one that catches people, and it follows from the calibrations: Rigetti
publishes `DEFCAL`s for `RX` at exactly four angles (`±π/2` and `±π`), while `RZ` is defined
parametrically (`DEFCAL RZ(%theta)`) and so takes any angle. A pulse only exists for those `RX`
angles, which is why `RX(0)`, `RX(2π)` and `RX(π/4)` are rejected.

`RX(π)` is an `X`; `RX(π/2)` is a half rotation. Arbitrary single-qubit rotations are built from
these plus `RZ`, which is exactly the decomposition quilc performs for you on the compiled path.

<Tip>
  Reaching for `X`? Use `RX(π)`: same operation, and it is native:

  ```python theme={null}
  circuit.rx(np.pi, 0)   # native
  circuit.x(0)           # NOT native: fails at translation if the program has a delay
  ```
</Tip>

## Timing operations

A delay is what makes a program Quil-T. This is a T1 (energy relaxation) measurement: excite the
qubit, wait, and see whether it is still excited:

<CodeGroup>
  ```python Qiskit theme={null}
  import numpy as np
  from qbraid.runtime import QbraidProvider
  from qiskit import QuantumCircuit

  provider = QbraidProvider()
  device = provider.get_device("rigetti:rigetti:qpu:cepheus-1-108q")

  circuit = QuantumCircuit(1, 1)
  circuit.rx(np.pi, 0)               # native, NOT circuit.x(0)
  circuit.delay(500, 0, unit="us")   # makes this a Quil-T program
  circuit.measure(0, 0)

  job = device.run(circuit, shots=10)
  job.wait_for_final_state()
  print(job.result().data.get_counts())
  # {'0': 9, '1': 1}  -- mostly relaxed to |0> during the 500 us delay
  ```

  ```python pyQuil theme={null}
  from pyquil import Program
  from qbraid.runtime import QbraidProvider

  provider = QbraidProvider()
  device = provider.get_device("rigetti:rigetti:qpu:cepheus-1-108q")

  program = Program(
      "DECLARE ro BIT[1]",
      "RX(pi) 0",           # native, NOT "X 0"
      "DELAY 0 0.0005",     # 0.0005 seconds = 500 us
      "MEASURE 0 ro[0]",
  )

  job = device.run(program, shots=10)
  job.wait_for_final_state()
  print(job.result().data.get_counts())
  # {'0': 9, '1': 1}
  ```
</CodeGroup>

Both submit the same thing. In Quil, `DELAY 0 0.0005` delays qubit 0 by 0.0005 **seconds**;
Qiskit's `delay(500, 0, unit="us")` converts to exactly that.

Relaxation is probabilistic, so your counts will differ run to run. A stray `'1'` at 500 us is
the physics, not a bug. That variation is exactly what a T1 sweep measures.

<Tip>
  Passing each instruction as its own string, as above, sidesteps a common trap: pyQuil rejects a
  flat instruction that starts with whitespace (`expected a command or a gate`), so an indented
  triple-quoted block of plain instructions fails even though it looks fine.

  The exception is a block that is *meant* to be indented, such as a `DEFCAL` or `DEFFRAME` body. Those
  must arrive as **one** string, indentation included; passed as separate arguments they fail with
  `failed to parse arguments for DEFCAL`. See
  [prepend\_default\_calibrations](#prepend_default_calibrations) for that shape.
</Tip>

To sweep T1, vary the delay and submit one job per point:

```python theme={null}
delays_us = [0, 50, 100, 200, 400, 800]
jobs = []

for t in delays_us:
    circuit = QuantumCircuit(1, 1)
    circuit.rx(np.pi, 0)
    circuit.delay(t, 0, unit="us")  # keep this even at t=0 -- see below
    circuit.measure(0, 0)
    jobs.append((t, device.run(circuit, shots=1000)))

for t, job in jobs:
    job.wait_for_final_state()
    counts = job.result().data.get_counts()
    p_excited = counts.get("1", 0) / sum(counts.values())
    print(f"{t:>4} us -> P(1) = {p_excited:.3f}")
```

<Warning>
  Keep the `delay` call at `t = 0` rather than skipping it. A circuit with no
  delay is not a Quil-T program, so your zero point would be nativized by quilc
  while every other point bypasses it, leaving a baseline compiled differently
  from the data it anchors. `delay(0)` emits `DELAY 0 0` and keeps every point
  on the same path.
</Warning>

<Note>
  Cepheus-1-108Q is billed **per minute of execution**, prorated with no
  minimum. A delay is execution time, so a long delay costs more than a short
  one. Individual jobs on this device typically run for tens to hundreds of
  milliseconds. See [Pricing](/v2/home/pricing).
</Note>

## Which framework?

The device itself accepts three run input types: **pyQuil**, **OpenQASM 2** and **OpenQASM 3**.
Qiskit appears throughout this page only because it is the most widely used, not because it is
special. It is converted to QASM like anything else.

That means **any framework qBraid can convert to QASM works here**, not just the two shown. Cirq,
Amazon Braket, PennyLane, pytket and the rest all reach `qasm2`/`qasm3` on the
[ConversionGraph](/v2/sdk/user-guide/transpiler), and `device.run()` handles the conversion:

<CodeGroup>
  ```python Cirq theme={null}
  import cirq

  q = cirq.LineQubit.range(2)
  circuit = cirq.Circuit([cirq.H(q[0]), cirq.CNOT(q[0], q[1]), cirq.measure(*q, key="m")])
  job = device.run(circuit, shots=10)
  ```

  ```python Braket theme={null}
  from braket.circuits import Circuit

  # .measure() is required here -- see the note below
  circuit = Circuit().h(0).cnot(0, 1).measure(0).measure(1)
  job = device.run(circuit, shots=10)
  ```

  ```python PennyLane theme={null}
  import pennylane as qml

  with qml.tape.QuantumTape() as circuit:
      qml.Hadamard(wires=0)
      qml.CNOT(wires=[0, 1])
      qml.sample(wires=[0, 1])

  job = device.run(circuit, shots=10)
  ```
</CodeGroup>

If your framework has a path to `qasm2` or `qasm3` on the ConversionGraph, it will run on Cepheus.
Write in whichever one you already use.

<Warning>
  **Measure explicitly.** Some frameworks measure implicitly when run on their own simulators, and
  that implicitness does not survive conversion. An Amazon Braket circuit written as
  `Circuit().h(0).cnot(0, 1)` converts to QASM with no `measure` statement, so the program reaches
  the QPU with nothing to read out. It runs, then fails when the results are parsed:

  ```
  No declared registers found in ro_sources. ro_sources keys: []
  ```

  Add the measurements yourself and the job returns counts as expected.
</Warning>

<Tip>
  `QPROGRAM_REGISTRY` is the authoritative answer to "what type do I pass?". It maps each
  framework to the exact program type `device.run()` accepts, which is not always the object you
  would guess (PennyLane, for instance, takes a `QuantumTape` rather than a `QNode`):

  ```python theme={null}
  from qbraid.programs import QPROGRAM_REGISTRY

  print(QPROGRAM_REGISTRY["pennylane"])   # <class 'pennylane.tape.tape.QuantumTape'>
  print(QPROGRAM_REGISTRY["cirq"])        # <class 'cirq.circuits.circuit.Circuit'>
  print(sorted(QPROGRAM_REGISTRY))        # every framework qBraid knows
  ```
</Tip>

### When to reach for pyQuil

The one thing QASM cannot express is **Quil-T beyond a simple delay**: `FENCE`, `PULSE`,
frame-level `DELAY 0 "rf" 1e-6`, or your own `DEFCAL` calibrations. Those have no vocabulary in
Qiskit or QASM, so there is nothing for the transpiler to convert. pyQuil is Rigetti's native
language, so nothing is translated and those features have first-class syntax.

An ordinary `delay` is the exception: it converts cleanly from Qiskit, so a T1 or T2 experiment
does not require pyQuil.

<Tip>
  Not sure which path your program will take? Ask before you spend a job:

  ```python theme={null}
  from qbraid.runtime.rigetti.device import contains_quil_t
  from pyquil import Program

  contains_quil_t(Program("RX(pi) 0\nDELAY 0 0.0005"))   # True  -> direct path, native gates required
  contains_quil_t(Program("H 0\nCNOT 0 1"))              # False -> compiled path, quilc handles it
  ```
</Tip>

## Runtime options

Rigetti's [translation service](https://docs.rigetti.com/qcs/guides/the-lifecycle-of-a-program),
the stage that turns your native-gate program into pulses, takes two options, passed as a dict
through `runtime_options`. Unrecognized keys are silently ignored.

| Option                         | Type  | Default | Effect                                                            |
| :----------------------------- | :---- | :------ | :---------------------------------------------------------------- |
| `passive_reset_delay_seconds`  | float | Rigetti | How long to wait for qubits to relax to \|0⟩ before each shot.    |
| `prepend_default_calibrations` | bool  | `True`  | If `False`, Rigetti's default calibrations are **not** prepended. |

### passive\_reset\_delay\_seconds

Between shots, qubits are left to relax back to |0⟩ on their own, a **passive** reset. This
option sets how long the QPU waits for that.

Rigetti documents it as "the delay between passive resets, in seconds" and does not publish a
default or a recommended range, so the figures below are **measurements from a single run on one
qubit**, included to show the shape of the trade-off. Treat them as illustrative; your own numbers
will differ with the qubit, the calibration and the day.

**The delay is paid once per shot, and you are billed for it.** The same 20-shot program, changing
nothing else:

| `passive_reset_delay_seconds` | Execution observed | Cost observed |
| :---------------------------- | :----------------- | :------------ |
| `0.000001` (1 µs)             | 15 ms              | \~3 credits   |
| `0.01` (10 ms)                | 215 ms             | \~43 credits  |

The 200 ms difference is exactly 20 shots × 10 ms, which is the part that generalizes: **the delay
is per shot**, and this device is billed [per minute of execution](/v2/home/pricing). Multiply by
your shot count before raising it.

What the wait buys is a cleaner starting state. Relaxation is what clears the previous shot.
Measuring a qubit at shot start, after a program that deliberately leaves it excited:

| Reset before each shot | Still excited at shot start (observed)    |
| :--------------------- | :---------------------------------------- |
| 1 µs                   | \~5% (the previous shot bleeding through) |
| 1 ms                   | \~1.5% (indistinguishable from baseline)  |

A control that never excited the qubit read 0%, so the 5% was leftover state rather than readout
error. Again: one qubit, one run. The effect is the point, not the percentages.

So the trade runs both ways:

* **Raise it** for circuits sensitive to initialization, where a few percent of shots starting in
  the wrong state would matter.
* **Lower it** to finish sooner and pay less. The floor is what your circuit can tolerate.

```python theme={null}
job = device.run(
    circuit,
    shots=1000,
    runtime_options={"passive_reset_delay_seconds": 0.0001},  # 100 us
)
```

<Note>
  The translation service rejects delays above roughly **67 ms**, reporting
  `waveform duration of 1e-1s exceeds maximum allowed duration of
      6.7108864e-2s`. That ceiling comes from the service's own error rather than
  published documentation, so do not rely on the exact figure.
</Note>

### prepend\_default\_calibrations

By default Rigetti prepends its calibration set to every program: the `DEFFRAME` and `DEFCAL` definitions that
give `RX`, `RZ`, `CZ` and `MEASURE` their actual pulse shapes. Those definitions are the only
reason a gate means anything on hardware.

**Leave this one alone.** It enables nothing, and setting it to `False` only breaks things.

To **override a calibration**, include your own `DEFCAL` and keep this option at its default.
Your definition is used in place of Rigetti's. A `DEFCAL` that turns `RX(pi)` into a no-op shows
this plainly: the qubit is left in |0⟩ rather than excited.

```python theme={null}
from pyquil import Program

# A DEFCAL body must be indented, so pass the block as ONE string --
# not as separate arguments (see the note under Timing operations).
program = Program(
    """DEFCAL RX(pi) 0:
    NOP
DECLARE ro BIT[1]
RX(pi) 0
DELAY 0 0
MEASURE 0 ro[0]
"""
)

job = device.run(program, shots=20)   # no runtime_options needed
job.wait_for_final_state()
print(job.result().data.get_counts())
# {'0': 19, '1': 1}   -- the RX did nothing.
# Without the custom DEFCAL the same program reads {'0': 1, '1': 19}.
```

Setting `prepend_default_calibrations=False` only *removes* the defaults. Your program must then
carry a complete calibration set of its own, and there is no practical way to do that here:
Rigetti's set defines frames across far more qubits than Cepheus exposes, so submitting it is
rejected before it reaches the QPU.

```
ProgramValidationError: Number of qubits in the circuit (300) exceeds the device's capacity (108)
```

Without a calibration set, translation fails instead, with Rigetti's reason:

```
input program error: program has no defined frames
```

<Note>
  Custom `DEFFRAME`s are constrained regardless: only `INITIAL-FREQUENCY` and
  `CHANNEL-DELAY` may differ from Rigetti's defaults. Changing anything else,
  such as `SAMPLE-RATE` or `HARDWARE-OBJECT`, is rejected (`frame 0
      "Transmon-0_charge_tx" differs from Rigetti-provided definition`). Rigetti
  restricts the flag that lifts this to [certain
  users](https://docs.rs/qcs/latest/qcs/qpu/translation/struct.TranslationOptions.html),
  and it is not enabled for qBraid. Treat the default frames as fixed and
  confine your customization to `DEFCAL`s.
</Note>

## Troubleshooting

Every failure at the translation stage arrives as a `RigettiJobError` naming the processor,
followed by Rigetti's own reason, which is the part that tells you what to fix:

```
Translation failed for quantum processor 'Cepheus-1-108Q': ... message:
"input program error: Failed to schedule Quil program: at instruction 0 ("X 0"):
this instruction must be replaced or decomposed prior to compilation"
```

Read to the end of the line. Rigetti names the offending instruction, here `X 0`, which is not
native.

| Rigetti's reason                                         | What happened                                                                                                                                                                                                                                                  |
| :------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `at instruction N (...): must be replaced or decomposed` | A non-native gate reached the QPU, because your program contains a delay and so skipped quilc. Replace `X` with `RX(π)`, `H`/`CX` with `RX`/`RZ`/`CZ` decompositions, or drop the delay to get the compiled path back. Also covers `RX` at a non-native angle. |
| `program has no defined frames`                          | You set `prepend_default_calibrations=False` without supplying a calibration set. Drop the option; see [above](#prepend_default_calibrations).                                                                                                                 |
| `waveform duration ... exceeds maximum allowed duration` | `passive_reset_delay_seconds` is above the 67.1 ms cap.                                                                                                                                                                                                        |
| `frame ... differs from Rigetti-provided definition`     | A `DEFFRAME` of yours changes something other than `INITIAL-FREQUENCY` or `CHANNEL-DELAY`.                                                                                                                                                                     |

Failures elsewhere in the pipeline:

| Message                                                               | Cause                                                                                                                                         |
| :-------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------- |
| `quilc failed to compile the program ...`                             | The gate-model path could not nativize your circuit. The message carries quilc's own reason.                                                  |
| `Number of qubits in the circuit (300) exceeds the device's capacity` | You are submitting Rigetti's full calibration set. See [prepend\_default\_calibrations](#prepend_default_calibrations).                       |
| Delay silently missing from results                                   | You are on `aws:rigetti:qpu:cepheus-1-108q`, not the direct device. Braket has no gate-level delay. Use `rigetti:rigetti:qpu:cepheus-1-108q`. |

## Related links

* [Pricing](/v2/home/pricing): Cepheus-1-108Q is billed per minute of execution
* [QbraidProvider](/v2/sdk/user-guide/providers/native): installation, authentication, runtime options
* [RigettiProvider](/v2/sdk/user-guide/providers/rigetti): direct QCS access with your own credentials
* [Rigetti: Quil-T](https://pyquil-docs.rigetti.com/en/stable/quilt.html): the timing/pulse extension to Quil
* [Rigetti: Getting started with Quil-T](https://pyquil-docs.rigetti.com/en/stable/quilt_getting_started.html): why Quil-T programs must be nativized by hand
* [Rigetti: The Quil compiler](https://pyquil-docs.rigetti.com/en/stable/compiler.html): what quilc does, and qubit rewiring
* [Rigetti: The lifecycle of a program](https://docs.rigetti.com/qcs/guides/the-lifecycle-of-a-program): compilation vs translation on QCS
* [Rigetti: TranslationOptions](https://docs.rs/qcs/latest/qcs/qpu/translation/struct.TranslationOptions.html): the full set of translation options
* [quilc](https://github.com/quil-lang/quilc): the open-source Quil compiler
