TargetData Demo

This notebook demonstrates how to use and configure TargetData in QAT, including:

  • default construction

  • nested qubit/resonator overrides

  • validation behaviour

  • random generation (seeded and unseeded)

  • serialisation and YAML loading

  • migration from deprecated helpers

import tempfile
import warnings
from pathlib import Path

from pydantic import ValidationError

from qat.core.config.descriptions import CompilePipelineDescription
from qat.model.target_data import (
    CustomTargetData,
    DefaultTargetData,
    QubitDescription,
    ResonatorDescription,
    TargetData,
)

warnings.simplefilter("always", DeprecationWarning)

1) Start With Defaults

TargetData() now directly creates a complete default instance and is the preferred entry point for new code.

target_data = TargetData()

print("max_shots:", target_data.max_shots)
print("default_shots:", target_data.default_shots)
print("clock_cycle:", target_data.clock_cycle)
print("qubit passive_reset_time:", target_data.QUBIT_DATA.passive_reset_time)
print("qubit sample_time:", target_data.QUBIT_DATA.sample_time)
print("resonator sample_time:", target_data.RESONATOR_DATA.sample_time)

print("\nTop-level model keys:")
print(sorted(target_data.model_dump().keys()))
max_shots: 10000
default_shots: 1000
clock_cycle: 1e-09
qubit passive_reset_time: 0.001
qubit sample_time: 1e-09
resonator sample_time: 1e-09

Top-level model keys:
['QUBIT_DATA', 'RESONATOR_DATA', 'default_shots', 'max_shots']

2) Customise TargetData

You can override top-level and nested values directly when constructing TargetData.

custom_target_data = TargetData(
    max_shots=20_000,
    default_shots=2_048,
    QUBIT_DATA=QubitDescription(
        passive_reset_time=5e-4,
        instruction_memory_size=60_000,
    ),
    RESONATOR_DATA=ResonatorDescription(
        instruction_memory_size=70_000,
    ),
)

print("custom default_shots:", custom_target_data.default_shots)
print("custom passive_reset_time:", custom_target_data.QUBIT_DATA.passive_reset_time)
print(
    "custom qubit instruction_memory_size:",
    custom_target_data.QUBIT_DATA.instruction_memory_size,
)
print(
    "custom resonator instruction_memory_size:",
    custom_target_data.RESONATOR_DATA.instruction_memory_size,
)
custom default_shots: 2048
custom passive_reset_time: 0.0005
custom qubit instruction_memory_size: 60000
custom resonator instruction_memory_size: 70000

3) Validation Behaviour

TargetData enforces consistency and strict value constraints. The examples below show two common validation failures.

# Invalid 1: pulse_duration_min > pulse_duration_max
try:
    _ = QubitDescription(pulse_duration_min=2e-6, pulse_duration_max=1e-6)
except ValidationError as exc:
    print("Invalid duration config caught:")
    print(exc)

# Invalid 2: incompatible clock cycles between qubit and resonator
try:
    _ = TargetData(
        QUBIT_DATA=QubitDescription(sample_time=1e-9, samples_per_clock_cycle=2),
        RESONATOR_DATA=ResonatorDescription(sample_time=2e-9, samples_per_clock_cycle=2),
    )
except ValidationError as exc:
    print("\nClock-cycle mismatch caught:")
    print(exc)
Invalid duration config caught:
1 validation error for QubitDescription
  Value error, Min. pulse duration cannot be larger than max. pulse duration. [type=value_error, input_value={'pulse_duration_min': 2e...se_duration_max': 1e-06}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.11/v/value_error

Clock-cycle mismatch caught:
1 validation error for TargetData
  Value error, Different clock cycles for qubit and resonator are currently not supported. [type=value_error, input_value={'QUBIT_DATA': QubitDescr...f_freq_max=10000000000)}, input_type=dict]
    For further information visit https://errors.pydantic.dev/2.11/v/value_error

4) Random TargetData

TargetData.random() supports both patterns:

  • without a seed: convenient random examples

  • with a seed: deterministic examples for testing and debugging

# Without a seed: values may differ across calls
random_td_unseeded_1 = TargetData.random()
random_td_unseeded_2 = TargetData.random()

print("Unseeded call 1 clock_cycle:", random_td_unseeded_1.clock_cycle)
print("Unseeded call 2 clock_cycle:", random_td_unseeded_2.clock_cycle)
print(
    "Unseeded reproducible:",
    random_td_unseeded_1.model_dump() == random_td_unseeded_2.model_dump(),
)

# With a seed: deterministic across calls
random_td_seeded_1 = TargetData.random(seed=123)
random_td_seeded_2 = TargetData.random(seed=123)

print("\nSeeded call 1 clock_cycle:", random_td_seeded_1.clock_cycle)
print("Seeded call 2 clock_cycle:", random_td_seeded_2.clock_cycle)
print(
    "Seeded reproducible:",
    random_td_seeded_1.model_dump() == random_td_seeded_2.model_dump(),
)

compile_desc = CompilePipelineDescription(name="demo")
print("\nCompilePipelineDescription.target_data default:")
print(compile_desc.target_data)
Unseeded call 1 clock_cycle: 6.000000000000001e-09
Unseeded call 2 clock_cycle: 1.6e-08
Unseeded reproducible: False

Seeded call 1 clock_cycle: 5e-09
Seeded call 2 clock_cycle: 5e-09
Seeded reproducible: True

CompilePipelineDescription.target_data default:
<class 'qat.model.target_data.TargetData'>

5) Serialisation, YAML Loading, and Deprecation Migration

This section shows how to serialise/deserialise TargetData and how legacy helpers map to the preferred constructor style.

# JSON serialisation
payload_json = target_data.model_dump_json(indent=2)
print("Serialised JSON (first 250 chars):")
print(payload_json[:250] + "...")

# YAML loading from disk via TargetData.from_yaml(...)
yaml_text = """
max_shots: 12000
default_shots: 512
QUBIT_DATA:
  sample_time: 1e-09
  samples_per_clock_cycle: 1
  instruction_memory_size: 50000
  waveform_memory_size: 1500
  pulse_duration_min: 6.4e-08
  pulse_duration_max: 0.001
  pulse_channel_lo_freq_min: 1000000
  pulse_channel_lo_freq_max: 10000000000
  pulse_channel_if_freq_min: 0
  pulse_channel_if_freq_max: 10000000000
  passive_reset_time: 0.001
RESONATOR_DATA:
  sample_time: 1e-09
  samples_per_clock_cycle: 1
  instruction_memory_size: 50000
  waveform_memory_size: 1500
  pulse_duration_min: 6.4e-08
  pulse_duration_max: 0.001
  pulse_channel_lo_freq_min: 1000000
  pulse_channel_lo_freq_max: 10000000000
  pulse_channel_if_freq_min: 0
  pulse_channel_if_freq_max: 10000000000
""".strip()

with tempfile.TemporaryDirectory() as tmp_dir:
    yaml_path = Path(tmp_dir) / "target_data.yaml"
    yaml_path.write_text(yaml_text)
    loaded_td = TargetData.from_yaml(yaml_path)

print("\nLoaded from YAML default_shots:", loaded_td.default_shots)

# Deprecated helpers still work, but emit DeprecationWarning.
with warnings.catch_warnings(record=True) as caught:
    warnings.simplefilter("always", DeprecationWarning)
    _ = TargetData.default()
    _ = TargetData.create_with(passive_reset_time=2e-3)
    _ = DefaultTargetData()
    _ = CustomTargetData(passive_reset_time=3e-3)

dep_msgs = [str(w.message) for w in caught if issubclass(w.category, DeprecationWarning)]
print("\nDeprecation warnings captured:", len(dep_msgs))
for msg in dep_msgs:
    print("-", msg)
Serialised JSON (first 250 chars):
{
  "max_shots": 10000,
  "default_shots": 1000,
  "QUBIT_DATA": {
    "sample_time": 1e-9,
    "samples_per_clock_cycle": 1,
    "instruction_memory_size": 50000,
    "waveform_memory_size": 1500,
    "pulse_duration_min": 6.4e-8,
    "pulse_duratio...

Loaded from YAML default_shots: 512

Deprecation warnings captured: 4
- `TargetData.default()` is deprecated; use `TargetData()` instead. This will be removed in v4.0.0.
- `TargetData.create_with()` is deprecated; use `TargetData()` with appropriate keyword arguments instead. This will be removed in v4.0.0.
- `DefaultTargetData()` is deprecated; use `TargetData()` instead. This will be removed in v4.0.0.
- `CustomTargetData()` is deprecated; use `TargetData()` with appropriate keyword arguments instead. This will be removed in v4.0.0.

Summary

For new code, use TargetData(...) directly.

Migration quick reference:

  • TargetData.default() -> TargetData()

  • TargetData.create_with(...) -> TargetData(...)

  • DefaultTargetData() -> TargetData()

  • CustomTargetData(...) -> TargetData(...)