qcoder 0.4.0a1__tar.gz → 0.4.0a2__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.
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/CHANGELOG.md +11 -0
- {qcoder-0.4.0a1/src/qcoder.egg-info → qcoder-0.4.0a2}/PKG-INFO +8 -5
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/README.md +7 -4
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/docs/architecture.md +3 -1
- qcoder-0.4.0a2/docs/model-cards/resource-guidance-local-v0.md +33 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/pyproject.toml +4 -1
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/__init__.py +1 -1
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/core/run_config.py +1 -17
- qcoder-0.4.0a2/src/qcoder/engines/guidance/model_pack.py +353 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/guidance/resource.py +82 -0
- qcoder-0.4.0a2/src/qcoder/model_packs/__init__.py +1 -0
- qcoder-0.4.0a2/src/qcoder/model_packs/resource_guidance_local_v0.json +183 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/pipelines/analyze.py +2 -29
- {qcoder-0.4.0a1 → qcoder-0.4.0a2/src/qcoder.egg-info}/PKG-INFO +8 -5
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder.egg-info/SOURCES.txt +6 -41
- qcoder-0.4.0a2/tests/test_guidance_model_pack.py +146 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_resource_guidance.py +56 -0
- qcoder-0.4.0a2/tests/test_smoke.py +23 -0
- qcoder-0.4.0a1/src/qcoder/engines/prediction_model/__init__.py +0 -16
- qcoder-0.4.0a1/src/qcoder/engines/prediction_model/artifact.py +0 -85
- qcoder-0.4.0a1/src/qcoder/engines/prediction_model/engine.py +0 -209
- qcoder-0.4.0a1/src/qcoder/engines/prediction_model/models.py +0 -62
- qcoder-0.4.0a1/src/qcoder/engines/prediction_model/policy.py +0 -45
- qcoder-0.4.0a1/src/qcoder/engines/prediction_model/schema_alignment.py +0 -41
- qcoder-0.4.0a1/src/qcoder/engines/quantumness/__init__.py +0 -8
- qcoder-0.4.0a1/src/qcoder/engines/quantumness/scorer.py +0 -254
- qcoder-0.4.0a1/src/qcoder/tools/analyze.py +0 -88
- qcoder-0.4.0a1/src/qcoder/tools/analyze_shot_scaling.py +0 -239
- qcoder-0.4.0a1/src/qcoder/tools/generate_corpus.py +0 -491
- qcoder-0.4.0a1/src/qcoder/tools/harness.py +0 -15
- qcoder-0.4.0a1/src/qcoder/tools/inspect_corpus_features.py +0 -273
- qcoder-0.4.0a1/src/qcoder/tools/join_runs_features.py +0 -252
- qcoder-0.4.0a1/src/qcoder/tools/mirror.py +0 -15
- qcoder-0.4.0a1/src/qcoder/tools/predict_baseline.py +0 -347
- qcoder-0.4.0a1/src/qcoder/tools/qr_dll_bootstrap.py +0 -31
- qcoder-0.4.0a1/src/qcoder/tools/runner.py +0 -15
- qcoder-0.4.0a1/src/qcoder/tools/runners/__init__.py +0 -1
- qcoder-0.4.0a1/src/qcoder/tools/runners/quantum_rings/__init__.py +0 -1
- qcoder-0.4.0a1/src/qcoder/tools/runners/quantum_rings/v12/__init__.py +0 -1
- qcoder-0.4.0a1/src/qcoder/tools/runners/quantum_rings/v12/harness.py +0 -1350
- qcoder-0.4.0a1/src/qcoder/tools/runners/quantum_rings/v12/mirror.py +0 -459
- qcoder-0.4.0a1/src/qcoder/tools/runners/quantum_rings/v12/runner.py +0 -549
- qcoder-0.4.0a1/src/qcoder/tools/train_baseline_models.py +0 -619
- qcoder-0.4.0a1/src/qcoder/tools/validate_baseline.py +0 -307
- qcoder-0.4.0a1/tests/test_analyze_prediction_integration.py +0 -62
- qcoder-0.4.0a1/tests/test_analyze_shot_scaling.py +0 -103
- qcoder-0.4.0a1/tests/test_generate_corpus.py +0 -113
- qcoder-0.4.0a1/tests/test_harness_schema_labels.py +0 -293
- qcoder-0.4.0a1/tests/test_inspect_corpus_features.py +0 -118
- qcoder-0.4.0a1/tests/test_join_runs_features.py +0 -170
- qcoder-0.4.0a1/tests/test_predict_baseline.py +0 -400
- qcoder-0.4.0a1/tests/test_prediction_artifact_io.py +0 -55
- qcoder-0.4.0a1/tests/test_prediction_fidelity_curve.py +0 -151
- qcoder-0.4.0a1/tests/test_prediction_policy.py +0 -35
- qcoder-0.4.0a1/tests/test_prediction_schema_alignment.py +0 -40
- qcoder-0.4.0a1/tests/test_quantumness_scorer.py +0 -137
- qcoder-0.4.0a1/tests/test_smoke.py +0 -20
- qcoder-0.4.0a1/tests/test_train_baseline_models.py +0 -158
- qcoder-0.4.0a1/tests/test_validate_baseline.py +0 -241
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/LICENSE +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/MANIFEST.in +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/NOTICE +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/setup.cfg +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/__main__.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/cli.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/core/__init__.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/core/context.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/core/qasm2/__init__.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/core/qasm2/adjoint_eligibility.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/core/qasm2/mirror_build.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/core/schema.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/context/__init__.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/context/bundle.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/context/markdown.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/adapters/__init__.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/adapters/cirq_intake.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/adapters/pennylane_intake.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/adapters/qiskit_intake.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/extractor.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/features/compute_v0.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/features/glossary_v0.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/features/schema_v0.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/ir.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/labeling.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/parsers/__init__.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/qasm2_regex_parser.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/reps/cut_profile.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/reps/depth.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/reps/entangling_layers.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/reps/gate_set_stats.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/reps/interaction_graph.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/reps/interaction_graph_metrics.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/feature_extraction/reps/spans.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/guidance/__init__.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/guidance/structural_scores.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/profiles/__init__.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/profiles/feature_profiles_v0.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/review/__init__.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/review/bundle.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/review/counts_v0.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/review/markdown.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/engines/review/qiskit_counts.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/pipelines/batch.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/pipelines/context.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/pipelines/review.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder/tools/batch.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder.egg-info/dependency_links.txt +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder.egg-info/entry_points.txt +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder.egg-info/requires.txt +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/src/qcoder.egg-info/top_level.txt +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/__init__.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_adjoint_eligibility.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_analyze_pipeline.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_batch_pipeline.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_cirq_intake.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_cli_batch_nested_discovery.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_cli_context_review.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_cli_help.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_context_bundle.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_cut_profile.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_entangling_layers.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_examples_smoke.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_feature_glossary.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_feature_profiles.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_gate_set_stats.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_interaction_graph_metrics.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_mirror_build.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_parse_qasm2_text.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_pennylane_intake.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_qiskit_intake.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_review_bundle.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_review_counts_v0.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_review_qiskit_counts.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_schema_stability.py +0 -0
- {qcoder-0.4.0a1 → qcoder-0.4.0a2}/tests/test_temporal_spans.py +0 -0
|
@@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on common practice for pre-1.0 semantic versioning: **`MAJOR.MINOR.PATCH`** with **`aN`** for alpha prereleases.
|
|
6
6
|
|
|
7
|
+
## 0.4.0a2 (alpha)
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Local Guidance Pack shadow metadata** — optional **`guidance_metadata`** records the bundled local resource-guidance candidate pack, including pack identity, version/hash metadata, caveats, and **`shadow_guidance`** with **`applied: false`**; deterministic guidance remains authoritative.
|
|
12
|
+
|
|
13
|
+
### Improved
|
|
14
|
+
|
|
15
|
+
- **Free Single-Run Intelligence** and **BYO LLM** artifact examples clarify that shadow guidance is metadata only.
|
|
16
|
+
- **Release notes** — this alpha has no hosted qCoder compute, no telemetry upload, no qCoder-hosted LLM, no runtime ML dependency, and no optimality, fidelity, runtime, hardware, backend-ranking, or causal-savings claims.
|
|
17
|
+
|
|
7
18
|
## 0.4.0a1 (alpha)
|
|
8
19
|
|
|
9
20
|
qCoder **0.4.0a1** adds opt-in derived **feature profiles**, mixed-width **review** checks, and a **5‑minute preflight→review** path.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qcoder
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.0a2
|
|
4
4
|
Summary: Quantum circuit analysis and structured feature extraction tools.
|
|
5
5
|
Author-email: Quantum Ready Solutions <support@qcoder.ai>
|
|
6
6
|
Maintainer-email: Quantum Ready Solutions <support@qcoder.ai>
|
|
@@ -48,7 +48,7 @@ Stable structural **feature vectors** (`schema_version`, `feature_names`, `featu
|
|
|
48
48
|
pip install qcoder
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
Pre-release lines on PyPI may look like **`0.4.
|
|
51
|
+
Pre-release lines on PyPI may look like **`0.4.0a2`**.
|
|
52
52
|
|
|
53
53
|
**2. Create a small Bell circuit** as `bell.qasm` (OpenQASM 2), or use the copy in **[`examples/circuits/bell.qasm`](examples/circuits/bell.qasm)** from a clone:
|
|
54
54
|
|
|
@@ -108,6 +108,9 @@ In real use, **`counts.json`** comes from **your** simulator or hardware pipelin
|
|
|
108
108
|
|
|
109
109
|
**Examples:** **[`examples/README.md`](examples/README.md)** (Bell QASM + illustrative counts for clones).
|
|
110
110
|
|
|
111
|
+
- **Free single-run intelligence** and **BYO LLM artifact workflow:** [`examples/06_single_run_intelligence.md`](examples/06_single_run_intelligence.md), [`examples/07_byo_llm_artifact_pack.md`](examples/07_byo_llm_artifact_pack.md), copy-paste prompt [`examples/prompts/single_run_artifact_to_action.md`](examples/prompts/single_run_artifact_to_action.md).
|
|
112
|
+
- Full walkthrough on the site: [Single-run intelligence with qCoder](https://qcoder.ai/manual/workflows/single-run-intelligence/).
|
|
113
|
+
|
|
111
114
|
---
|
|
112
115
|
|
|
113
116
|
## What qCoder analyzes
|
|
@@ -116,7 +119,7 @@ qCoder summarizes **circuit structure** from OpenQASM (and optional framework ex
|
|
|
116
119
|
|
|
117
120
|
## Package layout (supported public surface)
|
|
118
121
|
|
|
119
|
-
|
|
122
|
+
**Current supported public surface:**
|
|
120
123
|
|
|
121
124
|
- **`qcoder analyze`** — single-circuit extraction (human or `--json`).
|
|
122
125
|
- **`qcoder batch`** — directory batch to **JSONL**.
|
|
@@ -130,7 +133,7 @@ For **this release**, treat the **supported surface** as:
|
|
|
130
133
|
- **`qcoder[pennylane]`** — optional PennyLane circuit intake into the **same extractor** as OpenQASM.
|
|
131
134
|
- **Documented feature output** — see [qcoder.ai — Feature reference](https://qcoder.ai/manual/feature-reference/) and `engines/feature_extraction/features/schema_v0.py`; JSON carries a **`schema_version`** alongside named fields.
|
|
132
135
|
|
|
133
|
-
|
|
136
|
+
The public package contains the documented deterministic free-product surface above.
|
|
134
137
|
|
|
135
138
|
Brief notes live in **`docs/architecture.md`**.
|
|
136
139
|
|
|
@@ -144,7 +147,7 @@ pip install "qcoder[pennylane]"
|
|
|
144
147
|
|
|
145
148
|
Machine-readable JSON from **`qcoder analyze --json`** includes a derived **`feature_map`** object (`name → value`) for easier reading. The canonical circuit feature bundle remains the nested **`features`** object (`schema_version`, **`feature_names`**, **`features`**).
|
|
146
149
|
|
|
147
|
-
Optional **`--guidance`** adds heuristic shot-count and simulator/MPS starting-point suggestions derived from structural features. These suggestions are transparent, non-guaranteed starting points only; qCoder performs no backend execution and includes no telemetry/upload in this flow.
|
|
150
|
+
Optional **`--guidance`** adds heuristic shot-count and simulator/MPS starting-point suggestions derived from structural features. These suggestions are transparent, non-guaranteed starting points only; qCoder performs no backend execution and includes no telemetry/upload in this flow. When a bundled local guidance pack is present, the guidance JSON may also include **`guidance_metadata`** (pack id/version/hash, shadow suggestions, explicit `fallback_used`) for BYO-LLM workflows; **deterministic** `pressure` / `starting_points` remain the user-visible values until a future release explicitly applies pack output.
|
|
148
151
|
|
|
149
152
|
Optional **`--profiles`** adds deterministic **`feature_profiles`** derived from `feature_map` for compact structural taxonomy. This is an additive interpretation layer with its own schema version and does not modify canonical `features` (`schema_version`, `feature_names`, `features`).
|
|
150
153
|
|
|
@@ -18,7 +18,7 @@ Stable structural **feature vectors** (`schema_version`, `feature_names`, `featu
|
|
|
18
18
|
pip install qcoder
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
Pre-release lines on PyPI may look like **`0.4.
|
|
21
|
+
Pre-release lines on PyPI may look like **`0.4.0a2`**.
|
|
22
22
|
|
|
23
23
|
**2. Create a small Bell circuit** as `bell.qasm` (OpenQASM 2), or use the copy in **[`examples/circuits/bell.qasm`](examples/circuits/bell.qasm)** from a clone:
|
|
24
24
|
|
|
@@ -78,6 +78,9 @@ In real use, **`counts.json`** comes from **your** simulator or hardware pipelin
|
|
|
78
78
|
|
|
79
79
|
**Examples:** **[`examples/README.md`](examples/README.md)** (Bell QASM + illustrative counts for clones).
|
|
80
80
|
|
|
81
|
+
- **Free single-run intelligence** and **BYO LLM artifact workflow:** [`examples/06_single_run_intelligence.md`](examples/06_single_run_intelligence.md), [`examples/07_byo_llm_artifact_pack.md`](examples/07_byo_llm_artifact_pack.md), copy-paste prompt [`examples/prompts/single_run_artifact_to_action.md`](examples/prompts/single_run_artifact_to_action.md).
|
|
82
|
+
- Full walkthrough on the site: [Single-run intelligence with qCoder](https://qcoder.ai/manual/workflows/single-run-intelligence/).
|
|
83
|
+
|
|
81
84
|
---
|
|
82
85
|
|
|
83
86
|
## What qCoder analyzes
|
|
@@ -86,7 +89,7 @@ qCoder summarizes **circuit structure** from OpenQASM (and optional framework ex
|
|
|
86
89
|
|
|
87
90
|
## Package layout (supported public surface)
|
|
88
91
|
|
|
89
|
-
|
|
92
|
+
**Current supported public surface:**
|
|
90
93
|
|
|
91
94
|
- **`qcoder analyze`** — single-circuit extraction (human or `--json`).
|
|
92
95
|
- **`qcoder batch`** — directory batch to **JSONL**.
|
|
@@ -100,7 +103,7 @@ For **this release**, treat the **supported surface** as:
|
|
|
100
103
|
- **`qcoder[pennylane]`** — optional PennyLane circuit intake into the **same extractor** as OpenQASM.
|
|
101
104
|
- **Documented feature output** — see [qcoder.ai — Feature reference](https://qcoder.ai/manual/feature-reference/) and `engines/feature_extraction/features/schema_v0.py`; JSON carries a **`schema_version`** alongside named fields.
|
|
102
105
|
|
|
103
|
-
|
|
106
|
+
The public package contains the documented deterministic free-product surface above.
|
|
104
107
|
|
|
105
108
|
Brief notes live in **`docs/architecture.md`**.
|
|
106
109
|
|
|
@@ -114,7 +117,7 @@ pip install "qcoder[pennylane]"
|
|
|
114
117
|
|
|
115
118
|
Machine-readable JSON from **`qcoder analyze --json`** includes a derived **`feature_map`** object (`name → value`) for easier reading. The canonical circuit feature bundle remains the nested **`features`** object (`schema_version`, **`feature_names`**, **`features`**).
|
|
116
119
|
|
|
117
|
-
Optional **`--guidance`** adds heuristic shot-count and simulator/MPS starting-point suggestions derived from structural features. These suggestions are transparent, non-guaranteed starting points only; qCoder performs no backend execution and includes no telemetry/upload in this flow.
|
|
120
|
+
Optional **`--guidance`** adds heuristic shot-count and simulator/MPS starting-point suggestions derived from structural features. These suggestions are transparent, non-guaranteed starting points only; qCoder performs no backend execution and includes no telemetry/upload in this flow. When a bundled local guidance pack is present, the guidance JSON may also include **`guidance_metadata`** (pack id/version/hash, shadow suggestions, explicit `fallback_used`) for BYO-LLM workflows; **deterministic** `pressure` / `starting_points` remain the user-visible values until a future release explicitly applies pack output.
|
|
118
121
|
|
|
119
122
|
Optional **`--profiles`** adds deterministic **`feature_profiles`** derived from `feature_map` for compact structural taxonomy. This is an additive interpretation layer with its own schema version and does not modify canonical `features` (`schema_version`, `feature_names`, `features`).
|
|
120
123
|
|
|
@@ -21,10 +21,12 @@ The supported product surface described in **`README.md`** (**Package layout**)
|
|
|
21
21
|
|
|
22
22
|
The canonical circuit feature schema remains the existing `features` payload (`schema_version`, `feature_names`, `features`) produced by extraction. Guidance/context/review outputs are additive artifact layers and do not change canonical feature schema/version/order.
|
|
23
23
|
|
|
24
|
-
When requested via CLI flags, qCoder may emit an additional top-level `guidance` block built deterministically from `feature_map`. This guidance is outside the canonical feature schema (`features`) and is intended as transparent heuristic starting points rather than execution-validated recommendations.
|
|
24
|
+
When requested via CLI flags, qCoder may emit an additional top-level `guidance` block built deterministically from `feature_map`. This guidance is outside the canonical feature schema (`features`) and is intended as transparent heuristic starting points rather than execution-validated recommendations. The same block may include **`guidance_metadata`** describing a packaged **shadow-mode** local guidance JSON candidate (read from disk via `importlib.resources`; no network): pack id/version/content hash, optional shadow suggestions, and explicit fallback flags. **Deterministic** MPS `pressure` and `starting_points` stay authoritative in this slice; the pack does not override them yet.
|
|
25
25
|
|
|
26
26
|
qCoder may also emit an optional top-level `feature_profiles` block derived deterministically from `feature_map`. `feature_profiles` is additive, separately versioned (`feature_profiles_schema_version`), and does not alter canonical `features` schema/version/order.
|
|
27
27
|
|
|
28
28
|
The `context` and `review` commands generate deterministic local artifacts (Markdown/JSON) for user-controlled planning and post-run analysis workflows. "LLM-ready/RAG-ready" in this context means users can attach/paste artifacts manually; qCoder itself makes no LLM calls and performs no retrieval, embeddings, network calls, telemetry upload, or database writes. qCoder also does not execute simulators or hardware backends in these flows.
|
|
29
29
|
|
|
30
30
|
Optional framework adapters perform conversion/intake only; they do not execute circuits, simulators, or hardware.
|
|
31
|
+
|
|
32
|
+
The public package contains the documented deterministic free-product surface. Backend-specific runners, learned-prediction experiments, and private analysis prototypes are not part of the public package.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Model card — `resource_guidance_local_v0` (shadow / metadata only)
|
|
2
|
+
|
|
3
|
+
**Status:** Packaged as **candidate** JSON (`0.1.0-candidate`) in the public `qcoder` wheel under `qcoder.model_packs`. **Shadow mode only:** qCoder **does not** apply pack suggestions to `simulation_guidance.mps_bond_dimension.pressure` or `starting_points` in this release slice. Deterministic structural heuristics remain the user-visible source of truth.
|
|
4
|
+
|
|
5
|
+
## Data scope
|
|
6
|
+
|
|
7
|
+
- **Synthetic / public / qCoder-owned generated variants** only (as declared in the pack `training_data` block).
|
|
8
|
+
- **No** real user telemetry, **no** Pro/private workflow exports, **no** unaudited archive dumps.
|
|
9
|
+
|
|
10
|
+
## Runtime posture
|
|
11
|
+
|
|
12
|
+
- **Local** package data only (`importlib.resources`); **no** network calls, **no** hosted inference, **no** telemetry upload from this path.
|
|
13
|
+
- **No** runtime ML dependency (plain JSON; stdlib load and validate).
|
|
14
|
+
|
|
15
|
+
## Non-claims (machine-readable keys also appear in the pack JSON)
|
|
16
|
+
|
|
17
|
+
This pack and any shadow suggestions are **not**:
|
|
18
|
+
|
|
19
|
+
- an optimality proof (`not_optimality_proof`);
|
|
20
|
+
- a fidelity proof (`not_fidelity_proof`);
|
|
21
|
+
- hardware correctness proof (`not_hardware_correctness_proof`);
|
|
22
|
+
- a runtime guarantee (`not_runtime_guarantee`);
|
|
23
|
+
- backend ranking or universal QPU quality scoring (`not_backend_ranking`);
|
|
24
|
+
- causal savings or cost optimality (`not_causal_savings`).
|
|
25
|
+
|
|
26
|
+
## Behavior in qCoder today
|
|
27
|
+
|
|
28
|
+
- **Deterministic fallback preserved:** `build_resource_guidance` continues to set `pressure` and `starting_points` from structural scores only.
|
|
29
|
+
- **`guidance_metadata`:** additive block on the guidance dict documenting pack id/version/hash, `fallback_used`, and `shadow_guidance` with `applied: false` until a future evaluated release explicitly enables application.
|
|
30
|
+
|
|
31
|
+
## Promotion (future)
|
|
32
|
+
|
|
33
|
+
Public promotion requires evaluation gates, reproducible labels, and explicit product/API review before any **non-shadow** application of pack outputs.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "qcoder"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.0a2"
|
|
8
8
|
description = "Quantum circuit analysis and structured feature extraction tools."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -46,6 +46,9 @@ package-dir = {"" = "src"}
|
|
|
46
46
|
[tool.setuptools.packages.find]
|
|
47
47
|
where = ["src"]
|
|
48
48
|
|
|
49
|
+
[tool.setuptools.package-data]
|
|
50
|
+
qcoder = ["model_packs/*.json"]
|
|
51
|
+
|
|
49
52
|
[tool.pytest.ini_options]
|
|
50
53
|
pythonpath = ["src"]
|
|
51
54
|
|
|
@@ -30,7 +30,7 @@ def normalize_precision(x: str | None) -> str:
|
|
|
30
30
|
@dataclass(frozen=True)
|
|
31
31
|
class RunConfig:
|
|
32
32
|
"""
|
|
33
|
-
|
|
33
|
+
User-supplied run context for analyze reports.
|
|
34
34
|
|
|
35
35
|
These are NOT circuit-derived features.
|
|
36
36
|
"""
|
|
@@ -38,10 +38,6 @@ class RunConfig:
|
|
|
38
38
|
backend: str # normalized: "CPU" | "GPU"
|
|
39
39
|
precision: str # normalized: "single" | "double"
|
|
40
40
|
threshold: float | None = None # e.g. bond-dimension/threshold conditioning
|
|
41
|
-
prediction_artifact_path: str | None = None
|
|
42
|
-
prediction_allow_schema_mismatch: bool = False
|
|
43
|
-
prediction_fidelity_target: float | None = None
|
|
44
|
-
prediction_fidelity_metric: str | None = None
|
|
45
41
|
|
|
46
42
|
@staticmethod
|
|
47
43
|
def from_raw(
|
|
@@ -50,10 +46,6 @@ class RunConfig:
|
|
|
50
46
|
backend: str | None = None,
|
|
51
47
|
precision: str | None = None,
|
|
52
48
|
threshold: float | None = None,
|
|
53
|
-
prediction_artifact_path: str | None = None,
|
|
54
|
-
prediction_allow_schema_mismatch: bool | None = None,
|
|
55
|
-
prediction_fidelity_target: float | None = None,
|
|
56
|
-
prediction_fidelity_metric: str | None = None,
|
|
57
49
|
) -> "RunConfig":
|
|
58
50
|
# accept processor OR backend as the same input channel
|
|
59
51
|
raw = processor if processor is not None else backend
|
|
@@ -65,10 +57,6 @@ class RunConfig:
|
|
|
65
57
|
backend=normalize_backend(raw or backend),
|
|
66
58
|
precision=normalize_precision(precision),
|
|
67
59
|
threshold=float(threshold) if threshold is not None else None,
|
|
68
|
-
prediction_artifact_path=prediction_artifact_path,
|
|
69
|
-
prediction_allow_schema_mismatch=prediction_allow_schema_mismatch or False,
|
|
70
|
-
prediction_fidelity_target=prediction_fidelity_target,
|
|
71
|
-
prediction_fidelity_metric=prediction_fidelity_metric,
|
|
72
60
|
)
|
|
73
61
|
|
|
74
62
|
def to_dict(self) -> dict:
|
|
@@ -77,8 +65,4 @@ class RunConfig:
|
|
|
77
65
|
"backend": self.backend,
|
|
78
66
|
"precision": self.precision,
|
|
79
67
|
"threshold": self.threshold,
|
|
80
|
-
"prediction_artifact_path": self.prediction_artifact_path,
|
|
81
|
-
"prediction_allow_schema_mismatch": self.prediction_allow_schema_mismatch,
|
|
82
|
-
"prediction_fidelity_target": self.prediction_fidelity_target,
|
|
83
|
-
"prediction_fidelity_metric": self.prediction_fidelity_metric,
|
|
84
68
|
}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
"""Local resource guidance JSON pack: load, validate, and shadow evaluation (stdlib only, no network)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
import json
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from importlib import resources
|
|
9
|
+
from typing import Any, Mapping
|
|
10
|
+
|
|
11
|
+
PACK_RESOURCE = "resource_guidance_local_v0.json"
|
|
12
|
+
PACK_PACKAGE = "qcoder.model_packs"
|
|
13
|
+
|
|
14
|
+
ALLOWED_OPS = frozenset({"<", "<=", "==", ">=", ">"})
|
|
15
|
+
REQUIRED_NON_CLAIMS = frozenset(
|
|
16
|
+
{
|
|
17
|
+
"not_optimality_proof",
|
|
18
|
+
"not_fidelity_proof",
|
|
19
|
+
"not_hardware_correctness_proof",
|
|
20
|
+
"not_runtime_guarantee",
|
|
21
|
+
"not_backend_ranking",
|
|
22
|
+
"not_causal_savings",
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
EXPECTED_OUTPUT_MAPPING = {
|
|
26
|
+
"mps_pressure": "simulation_guidance.mps_bond_dimension.pressure",
|
|
27
|
+
"mps_ladder": "simulation_guidance.mps_bond_dimension.starting_points",
|
|
28
|
+
}
|
|
29
|
+
REQUIRED_TOP_LEVEL = (
|
|
30
|
+
"model_pack_schema_version",
|
|
31
|
+
"model_pack_id",
|
|
32
|
+
"model_pack_version",
|
|
33
|
+
"target_feature_schema_versions",
|
|
34
|
+
"targets",
|
|
35
|
+
"rule_evaluation",
|
|
36
|
+
"condition_logic",
|
|
37
|
+
"no_match_behavior",
|
|
38
|
+
"training_data",
|
|
39
|
+
"features",
|
|
40
|
+
"support_bounds",
|
|
41
|
+
"outputs",
|
|
42
|
+
"output_mapping",
|
|
43
|
+
"rules",
|
|
44
|
+
"fallback",
|
|
45
|
+
"non_claims",
|
|
46
|
+
)
|
|
47
|
+
EXPECTED_FEATURES = frozenset(
|
|
48
|
+
{
|
|
49
|
+
"n_qubits",
|
|
50
|
+
"n_cbits",
|
|
51
|
+
"n_measure_ops",
|
|
52
|
+
"n_2q_gate_ops",
|
|
53
|
+
"n_param_ops",
|
|
54
|
+
"real_depth",
|
|
55
|
+
"entangling_depth",
|
|
56
|
+
"n_entangling_layers",
|
|
57
|
+
"cut_max",
|
|
58
|
+
"cut_mean",
|
|
59
|
+
"cut_entropy",
|
|
60
|
+
"n_active_cuts",
|
|
61
|
+
"span_avg",
|
|
62
|
+
"span_max",
|
|
63
|
+
"span_long_range_ratio",
|
|
64
|
+
"ig_edge_density",
|
|
65
|
+
"ig_avg_degree",
|
|
66
|
+
"ig_is_connected",
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@dataclass(frozen=True)
|
|
72
|
+
class ResourceGuidancePack:
|
|
73
|
+
"""Validated resource guidance pack (shadow / metadata only in v0)."""
|
|
74
|
+
|
|
75
|
+
model_pack_id: str
|
|
76
|
+
model_pack_version: str
|
|
77
|
+
model_pack_schema_version: str
|
|
78
|
+
sha256_hex: str
|
|
79
|
+
data: dict[str, Any]
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def compute_pack_sha256(raw: bytes) -> str:
|
|
83
|
+
return hashlib.sha256(raw).hexdigest()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _feat(feature_map: Mapping[str, Any], key: str) -> float:
|
|
87
|
+
value = feature_map.get(key, 0.0)
|
|
88
|
+
try:
|
|
89
|
+
return float(value)
|
|
90
|
+
except (TypeError, ValueError):
|
|
91
|
+
return 0.0
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _float(x: Any) -> float | None:
|
|
95
|
+
try:
|
|
96
|
+
return float(x)
|
|
97
|
+
except (TypeError, ValueError):
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _condition_matches(feature_map: Mapping[str, Any], cond: Mapping[str, Any]) -> bool:
|
|
102
|
+
feat = cond.get("feature")
|
|
103
|
+
op = cond.get("op")
|
|
104
|
+
val = cond.get("value")
|
|
105
|
+
if feat not in EXPECTED_FEATURES or op not in ALLOWED_OPS:
|
|
106
|
+
return False
|
|
107
|
+
lhs = _feat(feature_map, str(feat))
|
|
108
|
+
rhs = _float(val)
|
|
109
|
+
if rhs is None:
|
|
110
|
+
return False
|
|
111
|
+
if op == "<":
|
|
112
|
+
return lhs < rhs
|
|
113
|
+
if op == "<=":
|
|
114
|
+
return lhs <= rhs
|
|
115
|
+
if op == "==":
|
|
116
|
+
return lhs == rhs
|
|
117
|
+
if op == ">=":
|
|
118
|
+
return lhs >= rhs
|
|
119
|
+
if op == ">":
|
|
120
|
+
return lhs > rhs
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _trivial_catchall(cond: Mapping[str, Any], *, n_qubits_min: float) -> bool:
|
|
125
|
+
feat = cond.get("feature")
|
|
126
|
+
op = cond.get("op")
|
|
127
|
+
rhs = _float(cond.get("value"))
|
|
128
|
+
if rhs is None or feat not in EXPECTED_FEATURES or op not in ALLOWED_OPS:
|
|
129
|
+
return False
|
|
130
|
+
if feat == "n_qubits" and op == ">=":
|
|
131
|
+
if rhs <= 0:
|
|
132
|
+
return True
|
|
133
|
+
if rhs <= n_qubits_min:
|
|
134
|
+
return True
|
|
135
|
+
if op == ">=" and rhs <= 0:
|
|
136
|
+
return True
|
|
137
|
+
return False
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def validate_resource_guidance_pack(data: Mapping[str, Any]) -> list[str]:
|
|
141
|
+
"""Return a list of validation errors; empty means the pack is acceptable."""
|
|
142
|
+
errors: list[str] = []
|
|
143
|
+
|
|
144
|
+
if not isinstance(data, dict):
|
|
145
|
+
return ["root must be a JSON object"]
|
|
146
|
+
|
|
147
|
+
for key in REQUIRED_TOP_LEVEL:
|
|
148
|
+
if key not in data:
|
|
149
|
+
errors.append(f"missing top-level key: {key}")
|
|
150
|
+
|
|
151
|
+
if data.get("model_pack_schema_version") != "resource_guidance_pack.v0":
|
|
152
|
+
errors.append("model_pack_schema_version must be resource_guidance_pack.v0")
|
|
153
|
+
|
|
154
|
+
targets = data.get("targets")
|
|
155
|
+
if targets != ["mps_pressure", "mps_bond_ladder"]:
|
|
156
|
+
errors.append("targets must be exactly ['mps_pressure', 'mps_bond_ladder']")
|
|
157
|
+
|
|
158
|
+
if data.get("rule_evaluation") != "first_match":
|
|
159
|
+
errors.append("rule_evaluation must be 'first_match'")
|
|
160
|
+
|
|
161
|
+
if data.get("condition_logic") != "all":
|
|
162
|
+
errors.append("condition_logic must be 'all'")
|
|
163
|
+
|
|
164
|
+
if data.get("no_match_behavior") != "fallback_deterministic":
|
|
165
|
+
errors.append("no_match_behavior must be 'fallback_deterministic'")
|
|
166
|
+
|
|
167
|
+
om = data.get("output_mapping")
|
|
168
|
+
if om != EXPECTED_OUTPUT_MAPPING:
|
|
169
|
+
errors.append("output_mapping must match expected public guidance paths")
|
|
170
|
+
|
|
171
|
+
nc = data.get("non_claims", [])
|
|
172
|
+
if not isinstance(nc, list) or frozenset(nc) != REQUIRED_NON_CLAIMS or len(nc) != len(REQUIRED_NON_CLAIMS):
|
|
173
|
+
errors.append("non_claims must contain exactly the required non-claim keys")
|
|
174
|
+
|
|
175
|
+
feats = data.get("features", [])
|
|
176
|
+
if not isinstance(feats, list) or frozenset(feats) != EXPECTED_FEATURES or len(feats) != len(EXPECTED_FEATURES):
|
|
177
|
+
errors.append("features must be the expected unique structural set (18 names)")
|
|
178
|
+
|
|
179
|
+
sb = data.get("support_bounds", {})
|
|
180
|
+
nqb = sb.get("n_qubits", {}) if isinstance(sb, dict) else {}
|
|
181
|
+
n_min = _float(nqb.get("min")) if isinstance(nqb, dict) else None
|
|
182
|
+
n_max = _float(nqb.get("max")) if isinstance(nqb, dict) else None
|
|
183
|
+
if n_min is None or n_max is None:
|
|
184
|
+
errors.append("support_bounds.n_qubits must include numeric min and max")
|
|
185
|
+
n_qubits_min = 1.0
|
|
186
|
+
else:
|
|
187
|
+
n_qubits_min = float(n_min)
|
|
188
|
+
|
|
189
|
+
ladders = data.get("outputs", {}).get("mps_ladders", {}) if isinstance(data.get("outputs"), dict) else {}
|
|
190
|
+
if not isinstance(ladders, dict):
|
|
191
|
+
errors.append("outputs.mps_ladders must be an object")
|
|
192
|
+
else:
|
|
193
|
+
for label in ("low", "medium", "high"):
|
|
194
|
+
if label not in ladders or not isinstance(ladders[label], list):
|
|
195
|
+
errors.append(f"outputs.mps_ladders.{label} must be a non-empty array")
|
|
196
|
+
|
|
197
|
+
ladder_keys = frozenset(ladders.keys()) if isinstance(ladders, dict) else frozenset()
|
|
198
|
+
|
|
199
|
+
rules = data.get("rules", [])
|
|
200
|
+
if not isinstance(rules, list) or len(rules) < 1:
|
|
201
|
+
errors.append("rules must be a non-empty array")
|
|
202
|
+
return errors
|
|
203
|
+
|
|
204
|
+
for i, rule in enumerate(rules):
|
|
205
|
+
if not isinstance(rule, dict):
|
|
206
|
+
errors.append(f"rules[{i}] must be an object")
|
|
207
|
+
continue
|
|
208
|
+
for rk in ("rule_id", "conditions", "output"):
|
|
209
|
+
if rk not in rule:
|
|
210
|
+
errors.append(f"rules[{i}] missing {rk}")
|
|
211
|
+
conds = rule.get("conditions", [])
|
|
212
|
+
if isinstance(conds, list) and len(conds) == 1 and isinstance(conds[0], dict):
|
|
213
|
+
if _trivial_catchall(conds[0], n_qubits_min=n_qubits_min):
|
|
214
|
+
errors.append(
|
|
215
|
+
f"rules[{i}] is a trivial catch-all (forbidden for public guidance packs); "
|
|
216
|
+
"use no_match_behavior fallback instead"
|
|
217
|
+
)
|
|
218
|
+
out = rule.get("output", {})
|
|
219
|
+
if isinstance(out, dict):
|
|
220
|
+
if out.get("mps_pressure") not in ladder_keys:
|
|
221
|
+
errors.append(f"rules[{i}].output.mps_pressure must be a ladder label")
|
|
222
|
+
if out.get("mps_ladder") not in ladder_keys:
|
|
223
|
+
errors.append(f"rules[{i}].output.mps_ladder must be a ladder label")
|
|
224
|
+
if not isinstance(conds, list) or not conds:
|
|
225
|
+
errors.append(f"rules[{i}].conditions must be a non-empty array")
|
|
226
|
+
continue
|
|
227
|
+
for j, c in enumerate(conds):
|
|
228
|
+
if not isinstance(c, dict):
|
|
229
|
+
errors.append(f"rules[{i}].conditions[{j}] must be an object")
|
|
230
|
+
continue
|
|
231
|
+
if c.get("op") not in ALLOWED_OPS:
|
|
232
|
+
errors.append(f"rules[{i}].conditions[{j}].op is not an allowed op")
|
|
233
|
+
if c.get("feature") not in EXPECTED_FEATURES:
|
|
234
|
+
errors.append(f"rules[{i}].conditions[{j}].feature is not a known feature")
|
|
235
|
+
|
|
236
|
+
return errors
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def load_resource_guidance_pack() -> ResourceGuidancePack | None:
|
|
240
|
+
"""Load the bundled resource guidance pack from package data, or None if missing/invalid."""
|
|
241
|
+
try:
|
|
242
|
+
root = resources.files(PACK_PACKAGE)
|
|
243
|
+
path = root.joinpath(PACK_RESOURCE)
|
|
244
|
+
raw = path.read_bytes()
|
|
245
|
+
except (OSError, FileNotFoundError, TypeError, ValueError):
|
|
246
|
+
return None
|
|
247
|
+
|
|
248
|
+
try:
|
|
249
|
+
data = json.loads(raw.decode("utf-8"))
|
|
250
|
+
except (UnicodeDecodeError, json.JSONDecodeError):
|
|
251
|
+
return None
|
|
252
|
+
|
|
253
|
+
if validate_resource_guidance_pack(data):
|
|
254
|
+
return None
|
|
255
|
+
|
|
256
|
+
if not isinstance(data, dict):
|
|
257
|
+
return None
|
|
258
|
+
|
|
259
|
+
digest = compute_pack_sha256(raw)
|
|
260
|
+
return ResourceGuidancePack(
|
|
261
|
+
model_pack_id=str(data.get("model_pack_id", "")),
|
|
262
|
+
model_pack_version=str(data.get("model_pack_version", "")),
|
|
263
|
+
model_pack_schema_version=str(data.get("model_pack_schema_version", "")),
|
|
264
|
+
sha256_hex=digest,
|
|
265
|
+
data=dict(data),
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def evaluate_resource_guidance_pack_shadow(
|
|
270
|
+
features: Mapping[str, Any],
|
|
271
|
+
pack: ResourceGuidancePack,
|
|
272
|
+
*,
|
|
273
|
+
feature_schema_version: str,
|
|
274
|
+
) -> dict[str, Any]:
|
|
275
|
+
"""
|
|
276
|
+
First-match shadow evaluation: suggest pack ladder/pressure without applying to public guidance.
|
|
277
|
+
|
|
278
|
+
Out-of-support ``n_qubits`` or unsupported feature schema version yields no match
|
|
279
|
+
(caller should keep deterministic guidance).
|
|
280
|
+
"""
|
|
281
|
+
tvers = pack.data.get("target_feature_schema_versions", [])
|
|
282
|
+
if not isinstance(tvers, list) or feature_schema_version not in tvers:
|
|
283
|
+
return {
|
|
284
|
+
"matched_rule_id": None,
|
|
285
|
+
"suggested_mps_pressure": None,
|
|
286
|
+
"suggested_mps_ladder": None,
|
|
287
|
+
"suggested_starting_points": None,
|
|
288
|
+
"no_match_reason": "unsupported_feature_schema",
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
sb = pack.data.get("support_bounds", {})
|
|
292
|
+
nqb = sb.get("n_qubits", {}) if isinstance(sb, dict) else {}
|
|
293
|
+
n_min = _float(nqb.get("min")) if isinstance(nqb, dict) else None
|
|
294
|
+
n_max = _float(nqb.get("max")) if isinstance(nqb, dict) else None
|
|
295
|
+
nq = _feat(features, "n_qubits")
|
|
296
|
+
if n_min is not None and nq < n_min:
|
|
297
|
+
return {
|
|
298
|
+
"matched_rule_id": None,
|
|
299
|
+
"suggested_mps_pressure": None,
|
|
300
|
+
"suggested_mps_ladder": None,
|
|
301
|
+
"suggested_starting_points": None,
|
|
302
|
+
"no_match_reason": "out_of_support_bounds",
|
|
303
|
+
}
|
|
304
|
+
if n_max is not None and nq > n_max:
|
|
305
|
+
return {
|
|
306
|
+
"matched_rule_id": None,
|
|
307
|
+
"suggested_mps_pressure": None,
|
|
308
|
+
"suggested_mps_ladder": None,
|
|
309
|
+
"suggested_starting_points": None,
|
|
310
|
+
"no_match_reason": "out_of_support_bounds",
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
rules = pack.data.get("rules", [])
|
|
314
|
+
ladders = pack.data.get("outputs", {}).get("mps_ladders", {})
|
|
315
|
+
if not isinstance(rules, list) or not isinstance(ladders, dict):
|
|
316
|
+
return {
|
|
317
|
+
"matched_rule_id": None,
|
|
318
|
+
"suggested_mps_pressure": None,
|
|
319
|
+
"suggested_mps_ladder": None,
|
|
320
|
+
"suggested_starting_points": None,
|
|
321
|
+
"no_match_reason": "invalid_pack_shape",
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
for rule in rules:
|
|
325
|
+
if not isinstance(rule, dict):
|
|
326
|
+
continue
|
|
327
|
+
conds = rule.get("conditions", [])
|
|
328
|
+
if not isinstance(conds, list) or not conds:
|
|
329
|
+
continue
|
|
330
|
+
if not all(isinstance(c, dict) and _condition_matches(features, c) for c in conds):
|
|
331
|
+
continue
|
|
332
|
+
out = rule.get("output", {})
|
|
333
|
+
if not isinstance(out, dict):
|
|
334
|
+
continue
|
|
335
|
+
ladder_key = out.get("mps_ladder")
|
|
336
|
+
sp = ladders.get(ladder_key) if isinstance(ladder_key, str) else None
|
|
337
|
+
if not isinstance(sp, list):
|
|
338
|
+
sp = None
|
|
339
|
+
return {
|
|
340
|
+
"matched_rule_id": rule.get("rule_id"),
|
|
341
|
+
"suggested_mps_pressure": out.get("mps_pressure"),
|
|
342
|
+
"suggested_mps_ladder": ladder_key,
|
|
343
|
+
"suggested_starting_points": list(sp) if sp is not None else None,
|
|
344
|
+
"no_match_reason": None,
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
"matched_rule_id": None,
|
|
349
|
+
"suggested_mps_pressure": None,
|
|
350
|
+
"suggested_mps_ladder": None,
|
|
351
|
+
"suggested_starting_points": None,
|
|
352
|
+
"no_match_reason": "no_matching_rule",
|
|
353
|
+
}
|