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

# Workflow: Formulation and Sampling

> The standard Dynex SDK workflow from problem definition to result analysis

# Workflow: Formulation and Sampling

Every computation on Dynex follows the same pattern: define a model, configure a backend, sample, and analyze results.

## Full Example

```python theme={null}
import dynex
import dimod
from dynex import DynexConfig, ComputeBackend

# Step 1: Build the problem model
bqm = dimod.BinaryQuadraticModel(
    {0: -1.0, 1: -1.0},
    {(0, 1): 2.0},
    0.0,
    'BINARY'
)

# Step 2: Configure the compute backend (GPU = Dynex neuromorphic chips)
config = DynexConfig(compute_backend=ComputeBackend.GPU)

# Step 3: Wrap model and create sampler
model = dynex.BQM(bqm)
sampler = dynex.DynexSampler(model, config=config, description="My optimization job")

# Step 4: Sample
sampleset = sampler.sample(
    num_reads=1000,
    annealing_time=200,
    shots=5,
)

# Step 5: Inspect results
best = sampleset.first
print(f"Best sample:  {best.sample}")
print(f"Best energy:  {best.energy}")

# Iterate over all samples
for sample, energy in sampleset.data(['sample', 'energy']):
    print(f"  {sample} → energy {energy:.4f}")
```

## Step 1: Choose a Model Type

Select the model class that best fits your problem:

| Model                       | Class       | Use when                                   |
| --------------------------- | ----------- | ------------------------------------------ |
| Binary Quadratic Model      | `dynex.BQM` | Natural QUBO/Ising formulation             |
| Constrained Quadratic Model | `dynex.CQM` | Constraints are central to the problem     |
| Discrete Quadratic Model    | `dynex.DQM` | Variables have more than 2 possible values |

See [Defining Models](/annealing/models) for detailed examples of each type.

## Step 2: Choose a Compute Backend

```python theme={null}
from dynex import DynexConfig, ComputeBackend, QPUModel

# GPU — Dynex neuromorphic chips, primary production backend
config = DynexConfig(compute_backend=ComputeBackend.GPU)

# QPU — specific quantum hardware model
config = DynexConfig(
    compute_backend=ComputeBackend.QPU,
    qpu_model=QPUModel.APOLLO_RC1
)

# CPU — lightweight network jobs and connectivity testing
config = DynexConfig(compute_backend=ComputeBackend.CPU)

# LOCAL — offline testing, no credentials required
config = DynexConfig(compute_backend=ComputeBackend.LOCAL)
```

<Tip>
  Use `GPU` for all production workloads — it runs on Dynex's own neuromorphic chips distributed globally. Use `LOCAL` for offline development and unit tests.
</Tip>

## Step 3: Build Sampler

```python theme={null}
sampler = dynex.DynexSampler(
    model,
    config=config,
    description="Optional job description",
    logging=True
)
```

## Step 4: Run Sampling

```python theme={null}
sampleset = sampler.sample(
    num_reads=1000,       # Number of parallel reads
    annealing_time=200,   # Integration depth (ODE steps)
    shots=5,              # Minimum solutions from network
    preprocess=False,     # Enable preprocessing for QPU
)
```

**Parameter guidance:**

| Parameter        | GPU (small/test) | GPU (production) | QPU     |
| ---------------- | ---------------- | ---------------- | ------- |
| `num_reads`      | 100–500          | 1000–10000       | 1–100   |
| `annealing_time` | 50–200           | 200–1000         | 10–1000 |
| `shots`          | 1                | 1–5              | 1–5     |

<Note>
  QPU backends have tighter hardware constraints: `num_reads` must stay within 1–100, `annealing_time` within 10–1000, and `shots` up to 5.
</Note>

## Step 5: Analyze Results

The sampler returns a dimod `SampleSet`:

```python theme={null}
# Best solution
best = sampleset.first
print(best.sample)   # {0: 1, 1: 0, 2: 1, ...}
print(best.energy)   # -3.14159

# All samples sorted by energy
for sample in sampleset.samples():
    print(sample)

# As pandas DataFrame
df = sampleset.to_pandas_dataframe()
print(df.head())

# Number of occurrences
for sample, energy, num_occ in sampleset.data(['sample', 'energy', 'num_occurrences']):
    print(f"Energy {energy:.3f} occurred {num_occ} times")
```

## Step 6: Iterate

Tune your model and parameters:

* **Better solutions** → increase `num_reads` and `annealing_time`
* **Faster results** → decrease `annealing_time`, use CPU instead of QPU
* **Constrained problems** → switch from BQM to CQM
* **Large-scale** → use QPU backend with `preprocess=True`

## Migrating from legacy SDK

| Legacy                               | Current                                             |
| ------------------------------------ | --------------------------------------------------- |
| `sampler.sample(..., mainnet=True)`  | `DynexConfig(compute_backend=ComputeBackend.CPU)`   |
| `sampler.sample(..., mainnet=False)` | `DynexConfig(compute_backend=ComputeBackend.LOCAL)` |
| `sampler.sample(..., v2=True)`       | Remove `v2=True` — no longer needed                 |
| REST-based communication             | gRPC-based communication (automatic)                |
