selene-formats 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- selene_formats-0.1.1/.gitignore +50 -0
- selene_formats-0.1.1/CHANGELOG.md +9 -0
- selene_formats-0.1.1/PKG-INFO +57 -0
- selene_formats-0.1.1/README.md +92 -0
- selene_formats-0.1.1/docs/publishing.md +18 -0
- selene_formats-0.1.1/docs/trace/0.1.0.md +63 -0
- selene_formats-0.1.1/docs/trace/legacy.md +27 -0
- selene_formats-0.1.1/docs/versioning.md +9 -0
- selene_formats-0.1.1/examples/trace/all-event-types.json +40 -0
- selene_formats-0.1.1/examples/trace/legacy.json +25 -0
- selene_formats-0.1.1/examples/trace/minimal.json +18 -0
- selene_formats-0.1.1/examples/trace/traces.json +22 -0
- selene_formats-0.1.1/pyproject.toml +39 -0
- selene_formats-0.1.1/python/README.md +40 -0
- selene_formats-0.1.1/python/selene_formats/__init__.py +11 -0
- selene_formats-0.1.1/python/selene_formats/schema.py +32 -0
- selene_formats-0.1.1/python/selene_formats/trace.py +469 -0
- selene_formats-0.1.1/python/selene_formats/trace_stream.py +183 -0
- selene_formats-0.1.1/python/tests/test_formats_trace.py +278 -0
- selene_formats-0.1.1/python/tests/test_legacy_serialization.py +129 -0
- selene_formats-0.1.1/python/tests/test_schema.py +306 -0
- selene_formats-0.1.1/python/tests/test_trace_stream.py +261 -0
- selene_formats-0.1.1/rust/Cargo.toml +24 -0
- selene_formats-0.1.1/rust/README.md +34 -0
- selene_formats-0.1.1/rust/src/lib.rs +4 -0
- selene_formats-0.1.1/rust/src/trace.rs +815 -0
- selene_formats-0.1.1/rust/src/trace_stream.rs +671 -0
- selene_formats-0.1.1/rust/tests/fixtures/all-event-types.json +40 -0
- selene_formats-0.1.1/rust/tests/fixtures/legacy.json +25 -0
- selene_formats-0.1.1/rust/tests/fixtures/minimal.json +18 -0
- selene_formats-0.1.1/rust/tests/fixtures/trace-stream.msgpack.hex +1 -0
- selene_formats-0.1.1/rust/tests/fixtures/traces.json +22 -0
- selene_formats-0.1.1/schemas/trace/0.1.0.schema.json +231 -0
- selene_formats-0.1.1/schemas/trace/legacy.schema.json +184 -0
- selene_formats-0.1.1/scripts/check_package_versions.py +31 -0
- selene_formats-0.1.1/scripts/check_schema_immutability.py +151 -0
- selene_formats-0.1.1/scripts/validate_schemas.py +44 -0
- selene_formats-0.1.1/typescript/README.md +52 -0
- selene_formats-0.1.1/typescript/package.json +36 -0
- selene_formats-0.1.1/typescript/src/index.ts +3 -0
- selene_formats-0.1.1/typescript/src/trace.ts +477 -0
- selene_formats-0.1.1/typescript/test/constructors.test.ts +12 -0
- selene_formats-0.1.1/typescript/test/protocol.test.mjs +408 -0
- selene_formats-0.1.1/typescript/tsconfig.json +12 -0
- selene_formats-0.1.1/typescript/tsconfig.test.json +8 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Generated by Cargo
|
|
2
|
+
# will have compiled files and executables
|
|
3
|
+
debug/
|
|
4
|
+
target/
|
|
5
|
+
|
|
6
|
+
# These are backup files generated by rustfmt
|
|
7
|
+
**/*.rs.bk
|
|
8
|
+
|
|
9
|
+
# MSVC Windows builds of rustc generate these, which store debugging information
|
|
10
|
+
*.pdb
|
|
11
|
+
|
|
12
|
+
.DS_Store
|
|
13
|
+
3rdparty/
|
|
14
|
+
.buildsecrets/
|
|
15
|
+
*.whl
|
|
16
|
+
*.pyc
|
|
17
|
+
*.o
|
|
18
|
+
*.so
|
|
19
|
+
*.dll
|
|
20
|
+
*.dll.lib
|
|
21
|
+
*.dll.a
|
|
22
|
+
|
|
23
|
+
venv/
|
|
24
|
+
.venv/
|
|
25
|
+
.vscode/
|
|
26
|
+
.direnv/
|
|
27
|
+
.devenv/
|
|
28
|
+
.hugrenv/
|
|
29
|
+
.devenv.flake.nix
|
|
30
|
+
.pre-commit-config.yaml
|
|
31
|
+
result
|
|
32
|
+
|
|
33
|
+
.envrc
|
|
34
|
+
|
|
35
|
+
__pycache__/
|
|
36
|
+
*.egg-info/
|
|
37
|
+
.ruff_cache/
|
|
38
|
+
.pytest_cache/
|
|
39
|
+
.mypy_cache/
|
|
40
|
+
/devenv.local.nix
|
|
41
|
+
_dist/
|
|
42
|
+
|
|
43
|
+
wheelhouse/
|
|
44
|
+
node_modules/
|
|
45
|
+
.pnpm-store/
|
|
46
|
+
selene-formats/typescript/dist/
|
|
47
|
+
!.cargo
|
|
48
|
+
scratch/
|
|
49
|
+
|
|
50
|
+
.idea
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.1](https://github.com/Quantinuum/selene/compare/selene-formats-v0.1.0...selene-formats-v0.1.1) (2026-10-16)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add streaming trace format, use it in place of instruction logs ([#235](https://github.com/Quantinuum/selene/issues/235)) ([6f18bda](https://github.com/Quantinuum/selene/commit/6f18bda40783c72c988b0764f3e9578045d29130))
|
|
9
|
+
* Add versioned, cross-language Selene API models ([#212](https://github.com/Quantinuum/selene/issues/212)) ([df33c56](https://github.com/Quantinuum/selene/commit/df33c566cb5e81428c7983e15fe2b1db177c9deb))
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: selene-formats
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Selene formats for Python
|
|
5
|
+
Project-URL: repository, https://github.com/quantinuum/selene
|
|
6
|
+
Author: Quantinuum
|
|
7
|
+
License-Expression: Apache-2.0
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Requires-Dist: msgpack<2,>=1.1
|
|
15
|
+
Requires-Dist: pydantic~=2.12
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# selene-formats for Python
|
|
19
|
+
|
|
20
|
+
Python models for the versioned, serializable Selene trace protocol. See the
|
|
21
|
+
protocol documentation and JSON Schema in the repository's `selene-formats/`
|
|
22
|
+
directory.
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from selene_formats.trace import (
|
|
26
|
+
SCHEMA_VERSION,
|
|
27
|
+
Trace,
|
|
28
|
+
TraceData,
|
|
29
|
+
Traces,
|
|
30
|
+
parse_trace_json,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
trace = Trace(schema_version=SCHEMA_VERSION, events=[])
|
|
34
|
+
traces = Traces(schema_version=SCHEMA_VERSION, traces=[TraceData(events=[])])
|
|
35
|
+
upgraded = parse_trace_json(versionless_trace_json)
|
|
36
|
+
legacy_json = trace.as_legacy().model_dump_json(indent=2)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`as_legacy()` returns a `LegacyTrace` sharing the current event models and
|
|
40
|
+
validation rules. Its `model_dump()` and `model_dump_json()` omit
|
|
41
|
+
`schema_version` and keep opaque tags numeric. `LegacyTrace` also accepts
|
|
42
|
+
versionless input and defaults its internal version to `0.1.0`. Filtering and
|
|
43
|
+
timing helpers retain legacy serialization. Collections have no legacy format.
|
|
44
|
+
|
|
45
|
+
For trace streams, use the MessagePack API rather than the JSON document parser:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from selene_formats.trace_stream import iter_trace_stream, write_trace_stream
|
|
49
|
+
|
|
50
|
+
write_trace_stream("trace.msgpack.gz", trace.events)
|
|
51
|
+
for event in iter_trace_stream("trace.msgpack.gz"):
|
|
52
|
+
print(event)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Use `iter_trace_stream_records` to include instruction metadata. Reads are lazy
|
|
56
|
+
and uncached, so keep the source file available until iteration finishes. See
|
|
57
|
+
the [stream format](../README.md#trace-streams) for framing and error handling.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Selene Formats
|
|
2
|
+
|
|
3
|
+
`selene-formats` contains the schemas, documentation, examples, and language
|
|
4
|
+
models for Selene's public serialized traces. It has no dependency on the
|
|
5
|
+
emulator.
|
|
6
|
+
|
|
7
|
+
Selene's `extractor.shots[index].get_trace()` output uses the versionless legacy format and
|
|
8
|
+
`selene_core.trace` models, which use the Python binding's `LegacyTrace` wrapper.
|
|
9
|
+
The language bindings use protocol 0.1.0 and provide adapters for reading and
|
|
10
|
+
serializing legacy traces with the current validation rules.
|
|
11
|
+
|
|
12
|
+
## APIs
|
|
13
|
+
|
|
14
|
+
| API | Version | Schema | Semantics |
|
|
15
|
+
| --- | --- | --- | --- |
|
|
16
|
+
| Trace documents (`Trace` and `Traces`) | 0.1.0 | [`schemas/trace/0.1.0.schema.json`](schemas/trace/0.1.0.schema.json) | [`docs/trace/0.1.0.md`](docs/trace/0.1.0.md) |
|
|
17
|
+
| Trace (legacy input) | versionless | [`schemas/trace/legacy.schema.json`](schemas/trace/legacy.schema.json) | [`docs/trace/legacy.md`](docs/trace/legacy.md) |
|
|
18
|
+
|
|
19
|
+
Schemas are also published at their canonical `$id` URLs:
|
|
20
|
+
|
|
21
|
+
* [Trace documents 0.1.0](https://quantinuum.github.io/selene/schemas/trace/0.1.0.schema.json)
|
|
22
|
+
* [Trace (legacy input)](https://quantinuum.github.io/selene/schemas/trace/legacy.schema.json)
|
|
23
|
+
|
|
24
|
+
Protocol-wide versioning is described in [`docs/versioning.md`](docs/versioning.md).
|
|
25
|
+
|
|
26
|
+
## Bindings
|
|
27
|
+
|
|
28
|
+
* Python: [`python/`](python) publishes the `selene-formats` distribution and is
|
|
29
|
+
imported as `selene_formats`.
|
|
30
|
+
* Rust: [`rust/`](rust) publishes the `selene-formats` crate.
|
|
31
|
+
* TypeScript: [`typescript/`](typescript) publishes the `@quantinuum/selene-formats`
|
|
32
|
+
package.
|
|
33
|
+
|
|
34
|
+
The binding release process is described in [`docs/publishing.md`](docs/publishing.md).
|
|
35
|
+
|
|
36
|
+
## Trace streams
|
|
37
|
+
|
|
38
|
+
`trace_stream` in the Python and Rust APIs implements gzipped MessagePack trace
|
|
39
|
+
streams. This is separate from the complete JSON `Trace` document format, in that
|
|
40
|
+
it is designed to be read and written in a sequential manner.
|
|
41
|
+
|
|
42
|
+
After gzip decompression, the stream consists of consecutive MessagePack objects:
|
|
43
|
+
|
|
44
|
+
1. A map with `format: "selene.trace.msgpack"`, `format_version: 1`, and
|
|
45
|
+
`schema_version: "0.1.0"`.
|
|
46
|
+
2. Zero or more record maps.
|
|
47
|
+
3. A single MessagePack nil (`0xc0`) marking successful completion.
|
|
48
|
+
|
|
49
|
+
Nothing may follow the end marker in the decompressed stream. Readers
|
|
50
|
+
reject missing markers, incomplete records, unsupported headers and bad gzip
|
|
51
|
+
trailers. Exhaust the iterator to check the whole stream; an error cannot retract
|
|
52
|
+
events already yielded.
|
|
53
|
+
|
|
54
|
+
Event records have the existing `source` and `event` fields. Custom payload tags
|
|
55
|
+
use native uint64 values and payload data uses MessagePack binary values, instead
|
|
56
|
+
of hex strings or base64 as used in the JSON format.
|
|
57
|
+
|
|
58
|
+
An event may also contain `instruction: "FutureRead"` or
|
|
59
|
+
`instruction: "MeasureLeakedRequest"`. Batch boundaries are separate maps of the
|
|
60
|
+
form `{"batch_start": {"start_time": 0, "end_time": 0}}`. These are instruction
|
|
61
|
+
metadata, not additional trace events. Event-only readers omit boundaries and
|
|
62
|
+
annotations, so materialising a trace doesn't add gates or change snapshots.
|
|
63
|
+
|
|
64
|
+
Barriers and classical delays use records with `source`, `uint_instruction`,
|
|
65
|
+
`value` and `qubits` fields. `uint_instruction` is `GlobalBarrier`, `LocalBarrier`
|
|
66
|
+
or `ClassicalDelay`, and `value` is a native uint64. Instruction readers preserve
|
|
67
|
+
the full range. Public-event readers and `get_trace()` reject operands above
|
|
68
|
+
`2^53 - 1` with an explicit error because the JSON schema cannot represent them.
|
|
69
|
+
Smaller operands convert to the same gate events as before.
|
|
70
|
+
|
|
71
|
+
Native opaque payload encoding belongs to the stream writer's wrappers. Using
|
|
72
|
+
serde directly on the public Rust models keeps their ordinary representation,
|
|
73
|
+
including hexadecimal tag strings and base64 data, even with a binary serializer.
|
|
74
|
+
|
|
75
|
+
Rust's `TraceStreamWriter` buffers records between caller-selected checkpoints.
|
|
76
|
+
Call `finish()` and check its result before publishing the destination. A failed
|
|
77
|
+
append poisons the writer; it cannot subsequently produce a completed stream.
|
|
78
|
+
`TraceStreamRecordReader` returns records with metadata, while `TraceStreamReader`
|
|
79
|
+
returns public events. The Rust reader adapts native payload fields in memory
|
|
80
|
+
before applying the existing model validation; it does not encode or parse JSON
|
|
81
|
+
text. The Python reader uses `TypeAdapter.validate_python` directly.
|
|
82
|
+
|
|
83
|
+
Python's `write_trace_stream` accepts an iterable and creates a new file without
|
|
84
|
+
overwriting one. `iter_trace_stream_records` and `iter_trace_stream` read lazily
|
|
85
|
+
without caching. Writers use gzip's fast compression setting. Callers own file
|
|
86
|
+
lifetime and removal of failed output; readers never copy or delete artifacts.
|
|
87
|
+
Interactive stacks also leave their run directories in place when closed or
|
|
88
|
+
garbage-collected. Once you're finished reading traces and state dumps, call
|
|
89
|
+
`stack.delete_run_directory()` to close the stack and remove its files. If the
|
|
90
|
+
stack has already been collected, remove the directory yourself using the path
|
|
91
|
+
you saved from `stack.configuration_path.parent`.
|
|
92
|
+
The conventional suffix is `.msgpack.gz`.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Publishing bindings
|
|
2
|
+
|
|
3
|
+
Release Please manages the Python, Rust, and TypeScript bindings as one
|
|
4
|
+
`selene-formats` component. A release PR updates every distribution to the
|
|
5
|
+
same version. Merging it creates this tag:
|
|
6
|
+
|
|
7
|
+
- `selene-formats-v<version>`
|
|
8
|
+
|
|
9
|
+
The formats packages workflow tests and packages all three bindings before it
|
|
10
|
+
publishes all three distributions. Releases are coordinated but not atomic.
|
|
11
|
+
|
|
12
|
+
The binding packages share one version, which remains independent from a trace
|
|
13
|
+
document's `schema_version`.
|
|
14
|
+
|
|
15
|
+
Selene's wheel tests install the Python formats package directly from
|
|
16
|
+
`selene-formats/`, alongside `selene-core/`. This lets us test model changes
|
|
17
|
+
before publishing a new formats release. `just build-ci` uses the same
|
|
18
|
+
installation steps locally through cibuildwheel. Run it inside devenv.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Trace protocol 0.1.0
|
|
2
|
+
|
|
3
|
+
Schema: [`../../schemas/trace/0.1.0.schema.json`](../../schemas/trace/0.1.0.schema.json)
|
|
4
|
+
|
|
5
|
+
## Documents
|
|
6
|
+
|
|
7
|
+
The schema accepts two top-level document shapes:
|
|
8
|
+
|
|
9
|
+
* `Trace` represents one emulation shot and contains an `events` array.
|
|
10
|
+
* `Traces` represents a collection and contains a `traces` array of
|
|
11
|
+
unversioned `TraceData` objects.
|
|
12
|
+
|
|
13
|
+
Both top-level shapes carry `schema_version`. `TraceData` contains the same
|
|
14
|
+
`events` field as a standalone `Trace`, but does not repeat the collection's
|
|
15
|
+
version. To extract a member as a standalone `Trace`, attach the enclosing
|
|
16
|
+
`schema_version`. A collection may be empty, and its traces retain their given
|
|
17
|
+
order.
|
|
18
|
+
|
|
19
|
+
## Event ordering and sources
|
|
20
|
+
|
|
21
|
+
`events` is ordered by observation during one emulation shot. An event's
|
|
22
|
+
`source` identifies the stage that emitted it:
|
|
23
|
+
|
|
24
|
+
* `UserProgram`: `index` is that source's zero-based event index.
|
|
25
|
+
* `Runtime`: `start_time` and `end_time` are nanoseconds in the runtime's shot
|
|
26
|
+
timeline.
|
|
27
|
+
* `ErrorModel`: `index` is that source's zero-based event index.
|
|
28
|
+
* `Simulator`: `index` is that source's zero-based event index, and
|
|
29
|
+
`duration_ns` is the wall-clock duration spent in the simulator call.
|
|
30
|
+
|
|
31
|
+
Indices are meaningful within a source only. Consumers must preserve event
|
|
32
|
+
order and must not assume that sources have equal event counts.
|
|
33
|
+
|
|
34
|
+
Indices, qubit IDs, timestamps, and durations are non-negative JSON integers no
|
|
35
|
+
larger than `9007199254740991`, so they can be represented exactly by a
|
|
36
|
+
JavaScript `number`. Opaque-payload tags retain the full unsigned 64-bit range
|
|
37
|
+
and are encoded as canonical hexadecimal strings: a lowercase `0x` prefix
|
|
38
|
+
followed by one to sixteen uppercase hexadecimal digits, with no leading zeroes
|
|
39
|
+
except for `"0x0"`. For example, `"0x11A12517"` is a valid tag, and the maximum
|
|
40
|
+
is `"0xFFFFFFFFFFFFFFFF"`. Gate parameters and values in
|
|
41
|
+
`KeyValuePairPayload` may be signed.
|
|
42
|
+
|
|
43
|
+
## Encoding
|
|
44
|
+
|
|
45
|
+
`OpaquePayload.data` is base64url-encoded in JSON. Padding may be omitted;
|
|
46
|
+
unused bits in the final Base64 character must be zero. `KeyValuePairPayload` is for
|
|
47
|
+
interoperable, structured custom metadata; consumers that do not understand an
|
|
48
|
+
application-specific key should preserve it when they re-emit the trace.
|
|
49
|
+
|
|
50
|
+
Gate `params` are JSON booleans or numbers. Integer-valued numbers in gate
|
|
51
|
+
parameters and `KeyValuePairPayload` values (including arrays) must be between
|
|
52
|
+
`-9007199254740991` and `9007199254740991`, inclusive. This also applies to
|
|
53
|
+
integer-valued floating-point notation such as `1e20`, which is rejected.
|
|
54
|
+
Fractional numbers remain supported. Gate parameter interpretation is determined
|
|
55
|
+
by `gate_name`.
|
|
56
|
+
|
|
57
|
+
## Version 0.1.0
|
|
58
|
+
|
|
59
|
+
Version 0.1.0 adds the required `schema_version` field and the `Traces`
|
|
60
|
+
collection document. Every `kind` discriminator is required in a serialized
|
|
61
|
+
trace. Versionless singular traces using the previous numeric opaque-payload
|
|
62
|
+
tag are described by the [`legacy` schema](legacy.md) and can be upgraded by
|
|
63
|
+
the language packages.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Legacy trace format
|
|
2
|
+
|
|
3
|
+
Schema: [`../../schemas/trace/legacy.schema.json`](../../schemas/trace/legacy.schema.json)
|
|
4
|
+
|
|
5
|
+
Selene currently emits trace documents without a `schema_version` through
|
|
6
|
+
`CircuitExtractor` and `selene_core.trace`. These documents use JSON integers
|
|
7
|
+
for indices, qubit IDs, timestamps, durations, and `OpaquePayload.tag`.
|
|
8
|
+
|
|
9
|
+
A missing `schema_version` identifies this format. Producers using the
|
|
10
|
+
`selene-formats` packages emit the versioned format by default and also support
|
|
11
|
+
legacy serialization for singular traces. Their adapters validate legacy input
|
|
12
|
+
and upgrade it to the current in-memory model. Legacy output omits
|
|
13
|
+
`schema_version` and serializes opaque tags as JSON integers; current validation
|
|
14
|
+
bounds still apply. Collections have no legacy format.
|
|
15
|
+
|
|
16
|
+
`OpaquePayload.data` accepts the standard or URL-safe Base64 alphabet, with
|
|
17
|
+
optional padding. Unused bits in the final Base64 character must be zero.
|
|
18
|
+
|
|
19
|
+
The supported legacy schema applies the current JavaScript-safe bounds to
|
|
20
|
+
integer-valued gate parameters and key-value payload values, including arrays:
|
|
21
|
+
`-9007199254740991` through `9007199254740991`. Fractional numbers remain
|
|
22
|
+
supported. Historical traces with values outside those bounds cannot be
|
|
23
|
+
upgraded by these adapters.
|
|
24
|
+
|
|
25
|
+
Legacy opaque tags may exceed JavaScript's safe integer range. TypeScript
|
|
26
|
+
consumers must pass the original JSON text to `parseTraceJson` to preserve such
|
|
27
|
+
tags; parsing them first with `JSON.parse` loses information irreversibly.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Versioning
|
|
2
|
+
|
|
3
|
+
Public schemas use semantic versioning. A document's `schema_version` identifies
|
|
4
|
+
its schema contract, not a Selene release. Schema files use their full version
|
|
5
|
+
in their filenames.
|
|
6
|
+
|
|
7
|
+
The only exception is the versionless legacy trace format. A trace with no
|
|
8
|
+
`schema_version` is interpreted as that legacy format and may be upgraded by
|
|
9
|
+
the model packages. New schemas and producers must always include a version.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": "0.1.0",
|
|
3
|
+
"events": [
|
|
4
|
+
{
|
|
5
|
+
"source": { "kind": "UserProgram", "index": 0 },
|
|
6
|
+
"event": {
|
|
7
|
+
"kind": "Gate",
|
|
8
|
+
"qubits": [0, 1],
|
|
9
|
+
"gate_name": "RZZ",
|
|
10
|
+
"params": [0.25, true],
|
|
11
|
+
"predicates": [{ "predicate": "ready", "result": true }]
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"source": { "kind": "Runtime", "start_time": 20, "end_time": 50 },
|
|
16
|
+
"event": { "kind": "Measurement", "qubit": 0 }
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"source": { "kind": "ErrorModel", "index": 0 },
|
|
20
|
+
"event": { "kind": "Reset", "qubit": 1 }
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"source": { "kind": "Simulator", "index": 0, "duration_ns": 123 },
|
|
24
|
+
"event": {
|
|
25
|
+
"kind": "Custom",
|
|
26
|
+
"payload": { "kind": "OpaquePayload", "tag": "0x7", "data": "c2VsZW5l" }
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"source": { "kind": "UserProgram", "index": 1 },
|
|
31
|
+
"event": {
|
|
32
|
+
"kind": "Custom",
|
|
33
|
+
"payload": {
|
|
34
|
+
"kind": "KeyValuePairPayload",
|
|
35
|
+
"data": { "name": "analysis", "attempt": 2, "accepted": true }
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"events": [
|
|
3
|
+
{
|
|
4
|
+
"source": { "kind": "UserProgram", "index": 0 },
|
|
5
|
+
"event": {
|
|
6
|
+
"kind": "Gate",
|
|
7
|
+
"qubits": [0],
|
|
8
|
+
"gate_name": "RXY",
|
|
9
|
+
"params": [0.5, 0],
|
|
10
|
+
"predicates": []
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"source": { "kind": "Simulator", "index": 0, "duration_ns": 1 },
|
|
15
|
+
"event": {
|
|
16
|
+
"kind": "Custom",
|
|
17
|
+
"payload": {
|
|
18
|
+
"kind": "OpaquePayload",
|
|
19
|
+
"tag": 11616494188317837126,
|
|
20
|
+
"data": "dHJhY2U="
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "selene-formats"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Selene formats for Python"
|
|
9
|
+
readme = "python/README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "Apache-2.0"
|
|
12
|
+
dependencies = ["pydantic~=2.12", "msgpack>=1.1,<2"]
|
|
13
|
+
authors = [
|
|
14
|
+
{ name = "Quantinuum" },
|
|
15
|
+
]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: Apache Software License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
repository = "https://github.com/quantinuum/selene"
|
|
26
|
+
|
|
27
|
+
[dependency-groups]
|
|
28
|
+
test = ["jsonschema>=4.23", "pytest>=8.3"]
|
|
29
|
+
|
|
30
|
+
[tool.hatch.build.targets.wheel]
|
|
31
|
+
packages = ["python/selene_formats"]
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.wheel.force-include]
|
|
34
|
+
"schemas/trace/0.1.0.schema.json" = "selene_formats/schemas/trace/0.1.0.schema.json"
|
|
35
|
+
"schemas/trace/legacy.schema.json" = "selene_formats/schemas/trace/legacy.schema.json"
|
|
36
|
+
|
|
37
|
+
[tool.hatch.build.targets.sdist.force-include]
|
|
38
|
+
"schemas/trace/0.1.0.schema.json" = "schemas/trace/0.1.0.schema.json"
|
|
39
|
+
"schemas/trace/legacy.schema.json" = "schemas/trace/legacy.schema.json"
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# selene-formats for Python
|
|
2
|
+
|
|
3
|
+
Python models for the versioned, serializable Selene trace protocol. See the
|
|
4
|
+
protocol documentation and JSON Schema in the repository's `selene-formats/`
|
|
5
|
+
directory.
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from selene_formats.trace import (
|
|
9
|
+
SCHEMA_VERSION,
|
|
10
|
+
Trace,
|
|
11
|
+
TraceData,
|
|
12
|
+
Traces,
|
|
13
|
+
parse_trace_json,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
trace = Trace(schema_version=SCHEMA_VERSION, events=[])
|
|
17
|
+
traces = Traces(schema_version=SCHEMA_VERSION, traces=[TraceData(events=[])])
|
|
18
|
+
upgraded = parse_trace_json(versionless_trace_json)
|
|
19
|
+
legacy_json = trace.as_legacy().model_dump_json(indent=2)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`as_legacy()` returns a `LegacyTrace` sharing the current event models and
|
|
23
|
+
validation rules. Its `model_dump()` and `model_dump_json()` omit
|
|
24
|
+
`schema_version` and keep opaque tags numeric. `LegacyTrace` also accepts
|
|
25
|
+
versionless input and defaults its internal version to `0.1.0`. Filtering and
|
|
26
|
+
timing helpers retain legacy serialization. Collections have no legacy format.
|
|
27
|
+
|
|
28
|
+
For trace streams, use the MessagePack API rather than the JSON document parser:
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
from selene_formats.trace_stream import iter_trace_stream, write_trace_stream
|
|
32
|
+
|
|
33
|
+
write_trace_stream("trace.msgpack.gz", trace.events)
|
|
34
|
+
for event in iter_trace_stream("trace.msgpack.gz"):
|
|
35
|
+
print(event)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Use `iter_trace_stream_records` to include instruction metadata. Reads are lazy
|
|
39
|
+
and uncached, so keep the source file available until iteration finishes. See
|
|
40
|
+
the [stream format](../README.md#trace-streams) for framing and error handling.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Access to the JSON Schema for the installed trace-model version."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from importlib.resources import files
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
from importlib.resources.abc import Traversable # Python 3.11+
|
|
8
|
+
except ImportError:
|
|
9
|
+
from importlib.abc import Traversable # Python 3.10
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _get_trace_schema_file(filename: str) -> Traversable:
|
|
15
|
+
schema_file = files("selene_formats").joinpath(f"schemas/trace/{filename}")
|
|
16
|
+
if not schema_file.is_file():
|
|
17
|
+
# The canonical schema lives outside the Python package in a source
|
|
18
|
+
# checkout and is force-included when building a distribution.
|
|
19
|
+
schema_file = Path(__file__).parents[2] / "schemas" / "trace" / filename
|
|
20
|
+
return schema_file
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_trace_schema() -> dict[str, Any]:
|
|
24
|
+
"""Return a new dictionary containing the current trace JSON Schema."""
|
|
25
|
+
schema_file = _get_trace_schema_file("0.1.0.schema.json")
|
|
26
|
+
return json.loads(schema_file.read_text())
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_legacy_trace_schema() -> dict[str, Any]:
|
|
30
|
+
"""Return a new dictionary containing the versionless legacy trace schema."""
|
|
31
|
+
schema_file = _get_trace_schema_file("legacy.schema.json")
|
|
32
|
+
return json.loads(schema_file.read_text())
|