qcoder 0.2.0a1__tar.gz → 0.3.0a1__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.2.0a1 → qcoder-0.3.0a1}/CHANGELOG.md +18 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/PKG-INFO +23 -3
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/README.md +18 -2
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/docs/architecture.md +5 -1
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/pyproject.toml +3 -1
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/__init__.py +1 -1
- qcoder-0.3.0a1/src/qcoder/engines/feature_extraction/adapters/cirq_intake.py +54 -0
- qcoder-0.3.0a1/src/qcoder/engines/feature_extraction/adapters/pennylane_intake.py +86 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/adapters/qiskit_intake.py +17 -2
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder.egg-info/PKG-INFO +23 -3
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder.egg-info/SOURCES.txt +4 -0
- qcoder-0.3.0a1/src/qcoder.egg-info/requires.txt +10 -0
- qcoder-0.3.0a1/tests/test_cirq_intake.py +97 -0
- qcoder-0.3.0a1/tests/test_pennylane_intake.py +105 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_qiskit_intake.py +41 -0
- qcoder-0.2.0a1/src/qcoder.egg-info/requires.txt +0 -4
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/LICENSE +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/MANIFEST.in +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/NOTICE +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/setup.cfg +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/__main__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/cli.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/core/__init__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/core/context.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/core/qasm2/__init__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/core/qasm2/adjoint_eligibility.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/core/qasm2/mirror_build.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/core/run_config.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/core/schema.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/context/__init__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/context/bundle.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/context/markdown.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/adapters/__init__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/extractor.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/features/compute_v0.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/features/glossary_v0.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/features/schema_v0.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/ir.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/labeling.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/parsers/__init__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/qasm2_regex_parser.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/reps/cut_profile.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/reps/depth.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/reps/entangling_layers.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/reps/gate_set_stats.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/reps/interaction_graph.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/reps/interaction_graph_metrics.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/reps/spans.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/guidance/__init__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/guidance/resource.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/prediction_model/__init__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/prediction_model/artifact.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/prediction_model/engine.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/prediction_model/models.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/prediction_model/policy.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/prediction_model/schema_alignment.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/quantumness/__init__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/quantumness/scorer.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/review/__init__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/review/bundle.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/review/counts_v0.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/review/markdown.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/review/qiskit_counts.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/pipelines/analyze.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/pipelines/batch.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/pipelines/context.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/pipelines/review.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/analyze.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/analyze_shot_scaling.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/batch.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/generate_corpus.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/harness.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/inspect_corpus_features.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/join_runs_features.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/mirror.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/predict_baseline.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/qr_dll_bootstrap.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/runner.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/runners/__init__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/runners/quantum_rings/__init__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/runners/quantum_rings/v12/__init__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/runners/quantum_rings/v12/harness.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/runners/quantum_rings/v12/mirror.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/runners/quantum_rings/v12/runner.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/train_baseline_models.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/tools/validate_baseline.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder.egg-info/dependency_links.txt +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder.egg-info/entry_points.txt +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder.egg-info/top_level.txt +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/__init__.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_adjoint_eligibility.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_analyze_pipeline.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_analyze_prediction_integration.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_analyze_shot_scaling.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_batch_pipeline.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_cli_batch_nested_discovery.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_cli_context_review.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_cli_help.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_context_bundle.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_cut_profile.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_entangling_layers.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_feature_glossary.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_gate_set_stats.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_generate_corpus.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_harness_schema_labels.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_inspect_corpus_features.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_interaction_graph_metrics.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_join_runs_features.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_mirror_build.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_parse_qasm2_text.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_predict_baseline.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_prediction_artifact_io.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_prediction_fidelity_curve.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_prediction_policy.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_prediction_schema_alignment.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_quantumness_scorer.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_resource_guidance.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_review_bundle.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_review_counts_v0.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_review_qiskit_counts.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_schema_stability.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_smoke.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_temporal_spans.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_train_baseline_models.py +0 -0
- {qcoder-0.2.0a1 → qcoder-0.3.0a1}/tests/test_validate_baseline.py +0 -0
|
@@ -4,6 +4,24 @@ 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.3.0a1 (alpha)
|
|
8
|
+
|
|
9
|
+
Optional Cirq and PennyLane intake alongside the existing Qiskit adapter. All adapters follow the same structural rules: framework object → OpenQASM 2 text → qCoder's shared parser pipeline.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`qcoder[cirq]`** — optional **Cirq** `Circuit` intake via OpenQASM 2 export (`cirq.qasm`) into the same canonical extractor used for `.qasm` files.
|
|
14
|
+
- **`qcoder[pennylane]`** — optional **PennyLane** intake (`QNode`, and **`QuantumScript`** where the installed version exposes it) via OpenQASM 2 export into the same canonical extractor used for `.qasm` files.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- **Adapter error handling** — Qiskit intake wraps **`qiskit.qasm2.dumps`** failures and QASM-parse failures at the adapter boundary in actionable **`RuntimeError`** messages aligned with Cirq and PennyLane adapters.
|
|
19
|
+
|
|
20
|
+
### Unchanged / scope
|
|
21
|
+
|
|
22
|
+
- **Canonical feature schema** — same version, field order, and feature vector layout as **`0.2.0a1`** (`schema_v0`/compute path).
|
|
23
|
+
- **Intake semantics** — Qiskit, Cirq, and PennyLane adapters are **structure/export intake only**: no transpiler upload, execution, simulator/hardware runs, telemetry, LLM calls, retrieval, or embeddings inside qCoder for these flows.
|
|
24
|
+
|
|
7
25
|
## 0.2.0a1 (alpha)
|
|
8
26
|
|
|
9
27
|
Local-only deterministic CLI tooling for quantum circuit analysis and LLM-ready workflow artifacts.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qcoder
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0a1
|
|
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>
|
|
@@ -22,13 +22,17 @@ License-File: NOTICE
|
|
|
22
22
|
Requires-Dist: numpy
|
|
23
23
|
Provides-Extra: qiskit
|
|
24
24
|
Requires-Dist: qiskit>=1.0; extra == "qiskit"
|
|
25
|
+
Provides-Extra: cirq
|
|
26
|
+
Requires-Dist: cirq-core>=1.4; extra == "cirq"
|
|
27
|
+
Provides-Extra: pennylane
|
|
28
|
+
Requires-Dist: pennylane>=0.44; extra == "pennylane"
|
|
25
29
|
Dynamic: license-file
|
|
26
30
|
|
|
27
31
|
# qCoder
|
|
28
32
|
|
|
29
33
|
**qCoder** helps developers **inspect quantum circuits before they run them.** It reads **OpenQASM** circuits, extracts **repeatable structural features**, and emits **structured JSON** (single file) or **JSONL** (batches)—useful for **notebooks**, **CI**, **pull-request review**, and **AI coding assistants** when you attach or paste deterministic context next to circuit text.
|
|
30
34
|
|
|
31
|
-
**CLI:** **`qcoder analyze`**, **`qcoder batch`**, **`qcoder context`**, and **`qcoder review`**. Optional **Qiskit** intake: **`pip install "qcoder[qiskit]"`**.
|
|
35
|
+
**CLI:** **`qcoder analyze`**, **`qcoder batch`**, **`qcoder context`**, and **`qcoder review`**. Optional **Qiskit / Cirq / PennyLane** intake (structure/export only, no simulator or hardware execution): **`pip install "qcoder[qiskit]"`**, **`pip install "qcoder[cirq]"`**, **`pip install "qcoder[pennylane]"`**.
|
|
32
36
|
|
|
33
37
|
**Company / legal:** Quantum Ready Solutions. **Product docs:** [qcoder.ai](https://qcoder.ai) · [manual](https://qcoder.ai/manual/). **Source:** [github.com/QuantumReadySolutions/qCoder](https://github.com/QuantumReadySolutions/qCoder). **Support:** [support@qcoder.ai](mailto:support@qcoder.ai).
|
|
34
38
|
|
|
@@ -47,6 +51,8 @@ For **this release**, treat the **supported surface** as:
|
|
|
47
51
|
- **`qcoder review`** — deterministic post-run review artifacts (**JSON + Markdown**) from user-provided counts.
|
|
48
52
|
- **Counts intake normalization** — `qcoder.counts.v0` and `qiskit_counts` normalization into the same deterministic review path.
|
|
49
53
|
- **`qcoder[qiskit]`** — optional `QuantumCircuit` intake into the **same extractor** as OpenQASM.
|
|
54
|
+
- **`qcoder[cirq]`** — optional Cirq `Circuit` intake into the **same extractor** as OpenQASM.
|
|
55
|
+
- **`qcoder[pennylane]`** — optional PennyLane circuit intake into the **same extractor** as OpenQASM.
|
|
50
56
|
- **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.
|
|
51
57
|
|
|
52
58
|
Other modules under **`src/qcoder`** may exist for prototyping (extra tooling or engines outside the commands above). Unless documented here, **`docs/`**, or **qcoder.ai**, they do **not** share the same stability expectations as the commands and artifact formats listed above.
|
|
@@ -59,7 +65,7 @@ Brief notes live in **`docs/architecture.md`**.
|
|
|
59
65
|
pip install qcoder
|
|
60
66
|
```
|
|
61
67
|
|
|
62
|
-
Pre-release lines on PyPI use segments such as **`0.
|
|
68
|
+
Pre-release lines on PyPI use segments such as **`0.3.0a1`**.
|
|
63
69
|
|
|
64
70
|
Optional Qiskit adapter:
|
|
65
71
|
|
|
@@ -67,6 +73,18 @@ Optional Qiskit adapter:
|
|
|
67
73
|
pip install "qcoder[qiskit]"
|
|
68
74
|
```
|
|
69
75
|
|
|
76
|
+
Optional Cirq adapter:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install "qcoder[cirq]"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Optional PennyLane adapter:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install "qcoder[pennylane]"
|
|
86
|
+
```
|
|
87
|
+
|
|
70
88
|
Requires **Python 3.11+**. Runtime dependency: **NumPy**.
|
|
71
89
|
|
|
72
90
|
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`**).
|
|
@@ -75,6 +93,8 @@ Optional **`--guidance`** adds heuristic shot-count and simulator/MPS starting-p
|
|
|
75
93
|
|
|
76
94
|
`qcoder context` and `qcoder review` generate deterministic local artifacts (JSON + Markdown) intended for user-controlled AI-assisted planning/review workflows. "LLM-ready/RAG-ready" in this project means users can attach or paste these artifacts manually; qCoder itself performs no retrieval, embeddings, network calls, or telemetry/upload in this flow.
|
|
77
95
|
|
|
96
|
+
The optional Qiskit, Cirq, and PennyLane adapters are structure/export intake paths only. qCoder does not execute simulators or hardware backends in these flows.
|
|
97
|
+
|
|
78
98
|
## CLI quickstart
|
|
79
99
|
|
|
80
100
|
```bash
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**qCoder** helps developers **inspect quantum circuits before they run them.** It reads **OpenQASM** circuits, extracts **repeatable structural features**, and emits **structured JSON** (single file) or **JSONL** (batches)—useful for **notebooks**, **CI**, **pull-request review**, and **AI coding assistants** when you attach or paste deterministic context next to circuit text.
|
|
4
4
|
|
|
5
|
-
**CLI:** **`qcoder analyze`**, **`qcoder batch`**, **`qcoder context`**, and **`qcoder review`**. Optional **Qiskit** intake: **`pip install "qcoder[qiskit]"`**.
|
|
5
|
+
**CLI:** **`qcoder analyze`**, **`qcoder batch`**, **`qcoder context`**, and **`qcoder review`**. Optional **Qiskit / Cirq / PennyLane** intake (structure/export only, no simulator or hardware execution): **`pip install "qcoder[qiskit]"`**, **`pip install "qcoder[cirq]"`**, **`pip install "qcoder[pennylane]"`**.
|
|
6
6
|
|
|
7
7
|
**Company / legal:** Quantum Ready Solutions. **Product docs:** [qcoder.ai](https://qcoder.ai) · [manual](https://qcoder.ai/manual/). **Source:** [github.com/QuantumReadySolutions/qCoder](https://github.com/QuantumReadySolutions/qCoder). **Support:** [support@qcoder.ai](mailto:support@qcoder.ai).
|
|
8
8
|
|
|
@@ -21,6 +21,8 @@ For **this release**, treat the **supported surface** as:
|
|
|
21
21
|
- **`qcoder review`** — deterministic post-run review artifacts (**JSON + Markdown**) from user-provided counts.
|
|
22
22
|
- **Counts intake normalization** — `qcoder.counts.v0` and `qiskit_counts` normalization into the same deterministic review path.
|
|
23
23
|
- **`qcoder[qiskit]`** — optional `QuantumCircuit` intake into the **same extractor** as OpenQASM.
|
|
24
|
+
- **`qcoder[cirq]`** — optional Cirq `Circuit` intake into the **same extractor** as OpenQASM.
|
|
25
|
+
- **`qcoder[pennylane]`** — optional PennyLane circuit intake into the **same extractor** as OpenQASM.
|
|
24
26
|
- **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.
|
|
25
27
|
|
|
26
28
|
Other modules under **`src/qcoder`** may exist for prototyping (extra tooling or engines outside the commands above). Unless documented here, **`docs/`**, or **qcoder.ai**, they do **not** share the same stability expectations as the commands and artifact formats listed above.
|
|
@@ -33,7 +35,7 @@ Brief notes live in **`docs/architecture.md`**.
|
|
|
33
35
|
pip install qcoder
|
|
34
36
|
```
|
|
35
37
|
|
|
36
|
-
Pre-release lines on PyPI use segments such as **`0.
|
|
38
|
+
Pre-release lines on PyPI use segments such as **`0.3.0a1`**.
|
|
37
39
|
|
|
38
40
|
Optional Qiskit adapter:
|
|
39
41
|
|
|
@@ -41,6 +43,18 @@ Optional Qiskit adapter:
|
|
|
41
43
|
pip install "qcoder[qiskit]"
|
|
42
44
|
```
|
|
43
45
|
|
|
46
|
+
Optional Cirq adapter:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pip install "qcoder[cirq]"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Optional PennyLane adapter:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install "qcoder[pennylane]"
|
|
56
|
+
```
|
|
57
|
+
|
|
44
58
|
Requires **Python 3.11+**. Runtime dependency: **NumPy**.
|
|
45
59
|
|
|
46
60
|
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`**).
|
|
@@ -49,6 +63,8 @@ Optional **`--guidance`** adds heuristic shot-count and simulator/MPS starting-p
|
|
|
49
63
|
|
|
50
64
|
`qcoder context` and `qcoder review` generate deterministic local artifacts (JSON + Markdown) intended for user-controlled AI-assisted planning/review workflows. "LLM-ready/RAG-ready" in this project means users can attach or paste these artifacts manually; qCoder itself performs no retrieval, embeddings, network calls, or telemetry/upload in this flow.
|
|
51
65
|
|
|
66
|
+
The optional Qiskit, Cirq, and PennyLane adapters are structure/export intake paths only. qCoder does not execute simulators or hardware backends in these flows.
|
|
67
|
+
|
|
52
68
|
## CLI quickstart
|
|
53
69
|
|
|
54
70
|
```bash
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
- Primary path: **OpenQASM / QASM** text analyzed on the developer machine.
|
|
6
6
|
- Optional path: **`qcoder[qiskit]`** can ingest **Qiskit `QuantumCircuit`** objects into the **same extractor** as OpenQASM.
|
|
7
|
+
- Optional path: **`qcoder[cirq]`** can ingest **Cirq `Circuit`** objects into the **same extractor** as OpenQASM.
|
|
8
|
+
- Optional path: **`qcoder[pennylane]`** can ingest **PennyLane circuits** into the **same extractor** as OpenQASM.
|
|
7
9
|
|
|
8
10
|
The field glossary is defined in **`src/qcoder/engines/feature_extraction/features/schema_v0.py`** (`FEATURE_NAMES_V0`). The [qcoder.ai manual — Feature reference](https://qcoder.ai/manual/feature-reference/) summarizes each field name.
|
|
9
11
|
|
|
@@ -14,10 +16,12 @@ The supported product surface described in **`README.md`** (**Package layout**)
|
|
|
14
16
|
- **`qcoder context`** for deterministic preflight artifacts (**JSON + Markdown**), with optional `--full-features` glossary appendix.
|
|
15
17
|
- **`qcoder review`** for deterministic post-run review artifacts (**JSON + Markdown**) from user-provided counts.
|
|
16
18
|
- Counts normalization from **`qcoder.counts.v0`** and **`qiskit_counts`** into one deterministic review path.
|
|
17
|
-
- Optional **`qcoder[qiskit]`** ingestion into the same extractor as OpenQASM.
|
|
19
|
+
- Optional **`qcoder[qiskit]`**, **`qcoder[cirq]`**, and **`qcoder[pennylane]`** ingestion into the same extractor as OpenQASM.
|
|
18
20
|
|
|
19
21
|
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.
|
|
20
22
|
|
|
21
23
|
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.
|
|
22
24
|
|
|
23
25
|
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.
|
|
26
|
+
|
|
27
|
+
Optional framework adapters perform conversion/intake only; they do not execute circuits, simulators, or hardware.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "qcoder"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0a1"
|
|
8
8
|
description = "Quantum circuit analysis and structured feature extraction tools."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -28,6 +28,8 @@ dependencies = ["numpy"]
|
|
|
28
28
|
|
|
29
29
|
[project.optional-dependencies]
|
|
30
30
|
qiskit = ["qiskit>=1.0"]
|
|
31
|
+
cirq = ["cirq-core>=1.4"]
|
|
32
|
+
pennylane = ["pennylane>=0.44"]
|
|
31
33
|
|
|
32
34
|
[project.urls]
|
|
33
35
|
Homepage = "https://qcoder.ai"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Optional Cirq Circuit intake via OpenQASM 2 export.
|
|
3
|
+
|
|
4
|
+
Cirq is imported only when functions in this module are called.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from ..features.compute_v0 import FeatureVector, compute_features_v0
|
|
12
|
+
from ..ir import CircuitIR
|
|
13
|
+
from ..qasm2_regex_parser import parse_qasm2_text
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _load_cirq() -> tuple[type, Any]:
|
|
17
|
+
try:
|
|
18
|
+
from cirq import Circuit, qasm
|
|
19
|
+
except ImportError as e:
|
|
20
|
+
raise ImportError(
|
|
21
|
+
"qcoder: Cirq is not installed. "
|
|
22
|
+
"Install with: pip install cirq-core or pip install 'qcoder[cirq]' "
|
|
23
|
+
"(optional extra)."
|
|
24
|
+
) from e
|
|
25
|
+
return Circuit, qasm
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def circuit_ir_from_cirq(circuit: Any) -> CircuitIR:
|
|
29
|
+
"""
|
|
30
|
+
Export ``circuit`` with ``cirq.qasm`` and parse as OpenQASM 2 text.
|
|
31
|
+
|
|
32
|
+
Raises ImportError when Cirq is not installed (only at call time).
|
|
33
|
+
Raises TypeError if ``circuit`` is not a ``cirq.Circuit``.
|
|
34
|
+
Raises RuntimeError when exported text cannot be parsed by qCoder's QASM parser.
|
|
35
|
+
"""
|
|
36
|
+
Circuit, qasm = _load_cirq()
|
|
37
|
+
if not isinstance(circuit, Circuit):
|
|
38
|
+
raise TypeError(f"expected cirq.Circuit, got {type(circuit).__name__}")
|
|
39
|
+
|
|
40
|
+
qasm_text = qasm(circuit)
|
|
41
|
+
try:
|
|
42
|
+
return parse_qasm2_text(qasm_text, source_label="cirq.qasm")
|
|
43
|
+
except Exception as e: # pragma: no cover - defensive adapter boundary
|
|
44
|
+
raise RuntimeError(
|
|
45
|
+
"qcoder: cirq.qasm exported OpenQASM that qCoder could not parse. "
|
|
46
|
+
"Try simplifying unsupported operations or inspect the exported QASM text."
|
|
47
|
+
) from e
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def extract_features_from_cirq_circuit(circuit: Any) -> FeatureVector:
|
|
51
|
+
"""``circuit_ir_from_cirq`` + ``compute_features_v0`` (same schema as file intake)."""
|
|
52
|
+
ir = circuit_ir_from_cirq(circuit)
|
|
53
|
+
return compute_features_v0(ir)
|
|
54
|
+
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Optional PennyLane circuit intake via OpenQASM 2 export.
|
|
3
|
+
|
|
4
|
+
PennyLane is imported only when functions in this module are called.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from ..features.compute_v0 import FeatureVector, compute_features_v0
|
|
12
|
+
from ..ir import CircuitIR
|
|
13
|
+
from ..qasm2_regex_parser import parse_qasm2_text
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _load_pennylane() -> tuple[type, type | None, Any]:
|
|
17
|
+
try:
|
|
18
|
+
import pennylane as qml
|
|
19
|
+
from pennylane import QNode
|
|
20
|
+
from pennylane.io import to_openqasm
|
|
21
|
+
except ImportError as e:
|
|
22
|
+
raise ImportError(
|
|
23
|
+
"qcoder: PennyLane is not installed. "
|
|
24
|
+
"Install with: pip install pennylane or pip install 'qcoder[pennylane]' "
|
|
25
|
+
"(optional extra)."
|
|
26
|
+
) from e
|
|
27
|
+
|
|
28
|
+
# Optional: support QuantumScript when available on this PennyLane version.
|
|
29
|
+
try:
|
|
30
|
+
from pennylane.tape import QuantumScript
|
|
31
|
+
except Exception: # pragma: no cover - version-dependent optional type
|
|
32
|
+
QuantumScript = None
|
|
33
|
+
|
|
34
|
+
_ = qml # reserved for future adapter diagnostics
|
|
35
|
+
return QNode, QuantumScript, to_openqasm
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def circuit_ir_from_pennylane(circuit: Any, *args: Any, **kwargs: Any) -> CircuitIR:
|
|
39
|
+
"""
|
|
40
|
+
Export ``circuit`` with ``qml.to_openqasm(..., measure_all=True)`` and parse as OpenQASM 2 text.
|
|
41
|
+
|
|
42
|
+
Raises ImportError when PennyLane is not installed (only at call time).
|
|
43
|
+
Raises TypeError if ``circuit`` is not a supported PennyLane circuit object.
|
|
44
|
+
Raises RuntimeError when export fails or exported text cannot be parsed by qCoder.
|
|
45
|
+
"""
|
|
46
|
+
QNode, QuantumScript, to_openqasm = _load_pennylane()
|
|
47
|
+
accepted_types: tuple[type, ...] = (QNode,) if QuantumScript is None else (QNode, QuantumScript)
|
|
48
|
+
if not isinstance(circuit, accepted_types):
|
|
49
|
+
raise TypeError(
|
|
50
|
+
"expected pennylane.QNode"
|
|
51
|
+
+ ("" if QuantumScript is None else " or pennylane.tape.QuantumScript")
|
|
52
|
+
+ f", got {type(circuit).__name__}"
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
exported = to_openqasm(circuit, measure_all=True)
|
|
57
|
+
# QNode export returns a callable (to supply call args).
|
|
58
|
+
qasm_text = exported(*args, **kwargs) if callable(exported) else exported
|
|
59
|
+
except Exception as e:
|
|
60
|
+
raise RuntimeError(
|
|
61
|
+
"qcoder: PennyLane OpenQASM export failed via qml.to_openqasm. "
|
|
62
|
+
"Try a simpler circuit (QASM2-supported ops) or verify provided QNode arguments."
|
|
63
|
+
) from e
|
|
64
|
+
|
|
65
|
+
if not isinstance(qasm_text, str):
|
|
66
|
+
raise RuntimeError(
|
|
67
|
+
"qcoder: PennyLane OpenQASM export did not return text. "
|
|
68
|
+
"Expected OpenQASM 2 source string from qml.to_openqasm."
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
return parse_qasm2_text(qasm_text, source_label="qml.to_openqasm")
|
|
73
|
+
except Exception as e: # pragma: no cover - defensive adapter boundary
|
|
74
|
+
raise RuntimeError(
|
|
75
|
+
"qcoder: qml.to_openqasm produced OpenQASM that qCoder could not parse. "
|
|
76
|
+
"Try simplifying unsupported operations or inspect the exported QASM text."
|
|
77
|
+
) from e
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def extract_features_from_pennylane_circuit(
|
|
81
|
+
circuit: Any, *args: Any, **kwargs: Any
|
|
82
|
+
) -> FeatureVector:
|
|
83
|
+
"""``circuit_ir_from_pennylane`` + ``compute_features_v0`` (same schema as file intake)."""
|
|
84
|
+
ir = circuit_ir_from_pennylane(circuit, *args, **kwargs)
|
|
85
|
+
return compute_features_v0(ir)
|
|
86
|
+
|
{qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/adapters/qiskit_intake.py
RENAMED
|
@@ -32,12 +32,27 @@ def circuit_ir_from_qiskit(qc: Any) -> CircuitIR:
|
|
|
32
32
|
|
|
33
33
|
Raises ImportError when Qiskit is not installed (only at call time).
|
|
34
34
|
Raises TypeError if ``qc`` is not a ``qiskit.QuantumCircuit``.
|
|
35
|
+
Raises RuntimeError when export fails or exported text cannot be parsed by qCoder's QASM parser.
|
|
35
36
|
"""
|
|
36
37
|
QuantumCircuit, dumps = _load_qiskit()
|
|
37
38
|
if not isinstance(qc, QuantumCircuit):
|
|
38
39
|
raise TypeError(f"expected qiskit.QuantumCircuit, got {type(qc).__name__}")
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
qasm_text = dumps(qc)
|
|
43
|
+
except Exception as e:
|
|
44
|
+
raise RuntimeError(
|
|
45
|
+
"qcoder: OpenQASM 2 export failed via qiskit.qasm2.dumps. "
|
|
46
|
+
"Try a circuit supported by OpenQASM 2 export or inspect the circuit for unsupported constructs."
|
|
47
|
+
) from e
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
return parse_qasm2_text(qasm_text, source_label="qiskit.qasm2.dumps")
|
|
51
|
+
except Exception as e: # pragma: no cover - defensive adapter boundary
|
|
52
|
+
raise RuntimeError(
|
|
53
|
+
"qcoder: qiskit.qasm2.dumps exported OpenQASM that qCoder could not parse. "
|
|
54
|
+
"Try simplifying unsupported operations or inspect the exported QASM text."
|
|
55
|
+
) from e
|
|
41
56
|
|
|
42
57
|
|
|
43
58
|
def extract_features_from_qiskit_circuit(qc: Any) -> FeatureVector:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qcoder
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0a1
|
|
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>
|
|
@@ -22,13 +22,17 @@ License-File: NOTICE
|
|
|
22
22
|
Requires-Dist: numpy
|
|
23
23
|
Provides-Extra: qiskit
|
|
24
24
|
Requires-Dist: qiskit>=1.0; extra == "qiskit"
|
|
25
|
+
Provides-Extra: cirq
|
|
26
|
+
Requires-Dist: cirq-core>=1.4; extra == "cirq"
|
|
27
|
+
Provides-Extra: pennylane
|
|
28
|
+
Requires-Dist: pennylane>=0.44; extra == "pennylane"
|
|
25
29
|
Dynamic: license-file
|
|
26
30
|
|
|
27
31
|
# qCoder
|
|
28
32
|
|
|
29
33
|
**qCoder** helps developers **inspect quantum circuits before they run them.** It reads **OpenQASM** circuits, extracts **repeatable structural features**, and emits **structured JSON** (single file) or **JSONL** (batches)—useful for **notebooks**, **CI**, **pull-request review**, and **AI coding assistants** when you attach or paste deterministic context next to circuit text.
|
|
30
34
|
|
|
31
|
-
**CLI:** **`qcoder analyze`**, **`qcoder batch`**, **`qcoder context`**, and **`qcoder review`**. Optional **Qiskit** intake: **`pip install "qcoder[qiskit]"`**.
|
|
35
|
+
**CLI:** **`qcoder analyze`**, **`qcoder batch`**, **`qcoder context`**, and **`qcoder review`**. Optional **Qiskit / Cirq / PennyLane** intake (structure/export only, no simulator or hardware execution): **`pip install "qcoder[qiskit]"`**, **`pip install "qcoder[cirq]"`**, **`pip install "qcoder[pennylane]"`**.
|
|
32
36
|
|
|
33
37
|
**Company / legal:** Quantum Ready Solutions. **Product docs:** [qcoder.ai](https://qcoder.ai) · [manual](https://qcoder.ai/manual/). **Source:** [github.com/QuantumReadySolutions/qCoder](https://github.com/QuantumReadySolutions/qCoder). **Support:** [support@qcoder.ai](mailto:support@qcoder.ai).
|
|
34
38
|
|
|
@@ -47,6 +51,8 @@ For **this release**, treat the **supported surface** as:
|
|
|
47
51
|
- **`qcoder review`** — deterministic post-run review artifacts (**JSON + Markdown**) from user-provided counts.
|
|
48
52
|
- **Counts intake normalization** — `qcoder.counts.v0` and `qiskit_counts` normalization into the same deterministic review path.
|
|
49
53
|
- **`qcoder[qiskit]`** — optional `QuantumCircuit` intake into the **same extractor** as OpenQASM.
|
|
54
|
+
- **`qcoder[cirq]`** — optional Cirq `Circuit` intake into the **same extractor** as OpenQASM.
|
|
55
|
+
- **`qcoder[pennylane]`** — optional PennyLane circuit intake into the **same extractor** as OpenQASM.
|
|
50
56
|
- **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.
|
|
51
57
|
|
|
52
58
|
Other modules under **`src/qcoder`** may exist for prototyping (extra tooling or engines outside the commands above). Unless documented here, **`docs/`**, or **qcoder.ai**, they do **not** share the same stability expectations as the commands and artifact formats listed above.
|
|
@@ -59,7 +65,7 @@ Brief notes live in **`docs/architecture.md`**.
|
|
|
59
65
|
pip install qcoder
|
|
60
66
|
```
|
|
61
67
|
|
|
62
|
-
Pre-release lines on PyPI use segments such as **`0.
|
|
68
|
+
Pre-release lines on PyPI use segments such as **`0.3.0a1`**.
|
|
63
69
|
|
|
64
70
|
Optional Qiskit adapter:
|
|
65
71
|
|
|
@@ -67,6 +73,18 @@ Optional Qiskit adapter:
|
|
|
67
73
|
pip install "qcoder[qiskit]"
|
|
68
74
|
```
|
|
69
75
|
|
|
76
|
+
Optional Cirq adapter:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install "qcoder[cirq]"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Optional PennyLane adapter:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install "qcoder[pennylane]"
|
|
86
|
+
```
|
|
87
|
+
|
|
70
88
|
Requires **Python 3.11+**. Runtime dependency: **NumPy**.
|
|
71
89
|
|
|
72
90
|
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`**).
|
|
@@ -75,6 +93,8 @@ Optional **`--guidance`** adds heuristic shot-count and simulator/MPS starting-p
|
|
|
75
93
|
|
|
76
94
|
`qcoder context` and `qcoder review` generate deterministic local artifacts (JSON + Markdown) intended for user-controlled AI-assisted planning/review workflows. "LLM-ready/RAG-ready" in this project means users can attach or paste these artifacts manually; qCoder itself performs no retrieval, embeddings, network calls, or telemetry/upload in this flow.
|
|
77
95
|
|
|
96
|
+
The optional Qiskit, Cirq, and PennyLane adapters are structure/export intake paths only. qCoder does not execute simulators or hardware backends in these flows.
|
|
97
|
+
|
|
78
98
|
## CLI quickstart
|
|
79
99
|
|
|
80
100
|
```bash
|
|
@@ -29,6 +29,8 @@ src/qcoder/engines/feature_extraction/ir.py
|
|
|
29
29
|
src/qcoder/engines/feature_extraction/labeling.py
|
|
30
30
|
src/qcoder/engines/feature_extraction/qasm2_regex_parser.py
|
|
31
31
|
src/qcoder/engines/feature_extraction/adapters/__init__.py
|
|
32
|
+
src/qcoder/engines/feature_extraction/adapters/cirq_intake.py
|
|
33
|
+
src/qcoder/engines/feature_extraction/adapters/pennylane_intake.py
|
|
32
34
|
src/qcoder/engines/feature_extraction/adapters/qiskit_intake.py
|
|
33
35
|
src/qcoder/engines/feature_extraction/features/compute_v0.py
|
|
34
36
|
src/qcoder/engines/feature_extraction/features/glossary_v0.py
|
|
@@ -85,6 +87,7 @@ tests/test_analyze_pipeline.py
|
|
|
85
87
|
tests/test_analyze_prediction_integration.py
|
|
86
88
|
tests/test_analyze_shot_scaling.py
|
|
87
89
|
tests/test_batch_pipeline.py
|
|
90
|
+
tests/test_cirq_intake.py
|
|
88
91
|
tests/test_cli_batch_nested_discovery.py
|
|
89
92
|
tests/test_cli_context_review.py
|
|
90
93
|
tests/test_cli_help.py
|
|
@@ -100,6 +103,7 @@ tests/test_interaction_graph_metrics.py
|
|
|
100
103
|
tests/test_join_runs_features.py
|
|
101
104
|
tests/test_mirror_build.py
|
|
102
105
|
tests/test_parse_qasm2_text.py
|
|
106
|
+
tests/test_pennylane_intake.py
|
|
103
107
|
tests/test_predict_baseline.py
|
|
104
108
|
tests/test_prediction_artifact_io.py
|
|
105
109
|
tests/test_prediction_fidelity_curve.py
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
import importlib.util
|
|
5
|
+
import tempfile
|
|
6
|
+
import unittest
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from qcoder.engines.feature_extraction.features.compute_v0 import compute_features_v0
|
|
10
|
+
from qcoder.engines.feature_extraction.parsers import parse_circuit_file
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _cirq_installed() -> bool:
|
|
14
|
+
return importlib.util.find_spec("cirq") is not None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@unittest.skipUnless(_cirq_installed(), "cirq not installed")
|
|
18
|
+
class TestCirqIntakeWithCirq(unittest.TestCase):
|
|
19
|
+
def test_bell_features_match_tempfile_from_qasm_export(self) -> None:
|
|
20
|
+
import cirq
|
|
21
|
+
|
|
22
|
+
from qcoder.engines.feature_extraction.adapters.cirq_intake import (
|
|
23
|
+
extract_features_from_cirq_circuit,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
q0, q1 = cirq.LineQubit.range(2)
|
|
27
|
+
circuit = cirq.Circuit(
|
|
28
|
+
cirq.H(q0),
|
|
29
|
+
cirq.CNOT(q0, q1),
|
|
30
|
+
cirq.measure(q0, q1, key="m"),
|
|
31
|
+
)
|
|
32
|
+
text = cirq.qasm(circuit)
|
|
33
|
+
with tempfile.NamedTemporaryFile(
|
|
34
|
+
mode="w", suffix=".qasm", delete=False, encoding="utf-8"
|
|
35
|
+
) as f:
|
|
36
|
+
f.write(text)
|
|
37
|
+
path = f.name
|
|
38
|
+
try:
|
|
39
|
+
ir_file = parse_circuit_file(path)
|
|
40
|
+
fv_file = compute_features_v0(ir_file)
|
|
41
|
+
finally:
|
|
42
|
+
Path(path).unlink(missing_ok=True)
|
|
43
|
+
|
|
44
|
+
fv_adapt = extract_features_from_cirq_circuit(circuit)
|
|
45
|
+
self.assertEqual(fv_adapt.schema_version, fv_file.schema_version)
|
|
46
|
+
self.assertEqual(fv_adapt.feature_names, fv_file.feature_names)
|
|
47
|
+
self.assertEqual(fv_adapt.features, fv_file.features)
|
|
48
|
+
|
|
49
|
+
def test_circuit_ir_matches_parse_qasm2_text_of_export(self) -> None:
|
|
50
|
+
import cirq
|
|
51
|
+
|
|
52
|
+
from qcoder.engines.feature_extraction.adapters.cirq_intake import (
|
|
53
|
+
circuit_ir_from_cirq,
|
|
54
|
+
)
|
|
55
|
+
from qcoder.engines.feature_extraction.qasm2_regex_parser import parse_qasm2_text
|
|
56
|
+
|
|
57
|
+
q0, q1 = cirq.LineQubit.range(2)
|
|
58
|
+
circuit = cirq.Circuit(
|
|
59
|
+
cirq.H(q0),
|
|
60
|
+
cirq.CNOT(q0, q1),
|
|
61
|
+
cirq.measure(q0, q1, key="m"),
|
|
62
|
+
)
|
|
63
|
+
ir_adapt = circuit_ir_from_cirq(circuit)
|
|
64
|
+
ir_ref = parse_qasm2_text(cirq.qasm(circuit))
|
|
65
|
+
self.assertEqual(ir_adapt, ir_ref)
|
|
66
|
+
|
|
67
|
+
def test_wrong_type_raises_type_error(self) -> None:
|
|
68
|
+
from qcoder.engines.feature_extraction.adapters.cirq_intake import (
|
|
69
|
+
circuit_ir_from_cirq,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
with self.assertRaises(TypeError):
|
|
73
|
+
circuit_ir_from_cirq("not a circuit")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class TestCirqIntakeWithoutCirq(unittest.TestCase):
|
|
77
|
+
"""Runs when cirq is absent; skipped assertions when cirq is present."""
|
|
78
|
+
|
|
79
|
+
def test_adapter_module_importable_without_calling_cirq(self) -> None:
|
|
80
|
+
importlib.import_module("qcoder.engines.feature_extraction.adapters.cirq_intake")
|
|
81
|
+
|
|
82
|
+
def test_missing_cirq_raises_import_error_with_hint(self) -> None:
|
|
83
|
+
if _cirq_installed():
|
|
84
|
+
self.skipTest("cirq is installed")
|
|
85
|
+
from qcoder.engines.feature_extraction.adapters.cirq_intake import (
|
|
86
|
+
circuit_ir_from_cirq,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
with self.assertRaises(ImportError) as ctx:
|
|
90
|
+
circuit_ir_from_cirq(None)
|
|
91
|
+
self.assertIn("Cirq", str(ctx.exception))
|
|
92
|
+
self.assertIn("pip", str(ctx.exception).lower())
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
if __name__ == "__main__":
|
|
96
|
+
unittest.main()
|
|
97
|
+
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
import importlib.util
|
|
5
|
+
import tempfile
|
|
6
|
+
import unittest
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from qcoder.engines.feature_extraction.features.compute_v0 import compute_features_v0
|
|
10
|
+
from qcoder.engines.feature_extraction.parsers import parse_circuit_file
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _pennylane_installed() -> bool:
|
|
14
|
+
return importlib.util.find_spec("pennylane") is not None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@unittest.skipUnless(_pennylane_installed(), "pennylane not installed")
|
|
18
|
+
class TestPennyLaneIntakeWithPennyLane(unittest.TestCase):
|
|
19
|
+
@staticmethod
|
|
20
|
+
def _bell_qnode():
|
|
21
|
+
import pennylane as qml
|
|
22
|
+
|
|
23
|
+
# Analytic device (no device-level shots) avoids shots-on-device deprecation warnings.
|
|
24
|
+
dev = qml.device("default.qubit", wires=2)
|
|
25
|
+
|
|
26
|
+
@qml.qnode(dev)
|
|
27
|
+
def circuit():
|
|
28
|
+
qml.Hadamard(wires=0)
|
|
29
|
+
qml.CNOT(wires=[0, 1])
|
|
30
|
+
return qml.expval(qml.PauliZ(0))
|
|
31
|
+
|
|
32
|
+
return circuit
|
|
33
|
+
|
|
34
|
+
def _qasm_from_qnode(self, qnode) -> str:
|
|
35
|
+
import pennylane as qml
|
|
36
|
+
|
|
37
|
+
exported = qml.to_openqasm(qnode, measure_all=True)
|
|
38
|
+
return exported() if callable(exported) else exported
|
|
39
|
+
|
|
40
|
+
def test_bell_features_match_tempfile_from_qasm_export(self) -> None:
|
|
41
|
+
from qcoder.engines.feature_extraction.adapters.pennylane_intake import (
|
|
42
|
+
extract_features_from_pennylane_circuit,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
qnode = self._bell_qnode()
|
|
46
|
+
text = self._qasm_from_qnode(qnode)
|
|
47
|
+
with tempfile.NamedTemporaryFile(
|
|
48
|
+
mode="w", suffix=".qasm", delete=False, encoding="utf-8"
|
|
49
|
+
) as f:
|
|
50
|
+
f.write(text)
|
|
51
|
+
path = f.name
|
|
52
|
+
try:
|
|
53
|
+
ir_file = parse_circuit_file(path)
|
|
54
|
+
fv_file = compute_features_v0(ir_file)
|
|
55
|
+
finally:
|
|
56
|
+
Path(path).unlink(missing_ok=True)
|
|
57
|
+
|
|
58
|
+
fv_adapt = extract_features_from_pennylane_circuit(qnode)
|
|
59
|
+
self.assertEqual(fv_adapt.schema_version, fv_file.schema_version)
|
|
60
|
+
self.assertEqual(fv_adapt.feature_names, fv_file.feature_names)
|
|
61
|
+
self.assertEqual(fv_adapt.features, fv_file.features)
|
|
62
|
+
|
|
63
|
+
def test_circuit_ir_matches_parse_qasm2_text_of_export(self) -> None:
|
|
64
|
+
from qcoder.engines.feature_extraction.adapters.pennylane_intake import (
|
|
65
|
+
circuit_ir_from_pennylane,
|
|
66
|
+
)
|
|
67
|
+
from qcoder.engines.feature_extraction.qasm2_regex_parser import parse_qasm2_text
|
|
68
|
+
|
|
69
|
+
qnode = self._bell_qnode()
|
|
70
|
+
ir_adapt = circuit_ir_from_pennylane(qnode)
|
|
71
|
+
ir_ref = parse_qasm2_text(self._qasm_from_qnode(qnode))
|
|
72
|
+
self.assertEqual(ir_adapt, ir_ref)
|
|
73
|
+
|
|
74
|
+
def test_wrong_type_raises_type_error(self) -> None:
|
|
75
|
+
from qcoder.engines.feature_extraction.adapters.pennylane_intake import (
|
|
76
|
+
circuit_ir_from_pennylane,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
with self.assertRaises(TypeError):
|
|
80
|
+
circuit_ir_from_pennylane("not a circuit")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class TestPennyLaneIntakeWithoutPennyLane(unittest.TestCase):
|
|
84
|
+
"""Runs when pennylane is absent; skipped assertions when pennylane is present."""
|
|
85
|
+
|
|
86
|
+
def test_adapter_module_importable_without_calling_pennylane(self) -> None:
|
|
87
|
+
importlib.import_module("qcoder.engines.feature_extraction.adapters.pennylane_intake")
|
|
88
|
+
|
|
89
|
+
def test_missing_pennylane_raises_import_error_with_hint(self) -> None:
|
|
90
|
+
if _pennylane_installed():
|
|
91
|
+
self.skipTest("pennylane is installed")
|
|
92
|
+
from qcoder.engines.feature_extraction.adapters.pennylane_intake import (
|
|
93
|
+
circuit_ir_from_pennylane,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
with self.assertRaises(ImportError) as ctx:
|
|
97
|
+
circuit_ir_from_pennylane(None)
|
|
98
|
+
self.assertIn("pennylane", str(ctx.exception).lower())
|
|
99
|
+
self.assertIn("pip", str(ctx.exception).lower())
|
|
100
|
+
self.assertIn("qcoder[pennylane]", str(ctx.exception))
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
unittest.main()
|
|
105
|
+
|
|
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import importlib.util
|
|
4
4
|
import tempfile
|
|
5
5
|
import unittest
|
|
6
|
+
import unittest.mock
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
|
|
8
9
|
from qcoder.engines.feature_extraction.features.compute_v0 import compute_features_v0
|
|
@@ -61,6 +62,46 @@ class TestQiskitIntakeWithQiskit(unittest.TestCase):
|
|
|
61
62
|
ir_ref = parse_qasm2_text(dumps(qc))
|
|
62
63
|
self.assertEqual(ir_adapt, ir_ref)
|
|
63
64
|
|
|
65
|
+
def test_export_failure_raises_runtime_error_with_guidance(self) -> None:
|
|
66
|
+
from qiskit import QuantumCircuit
|
|
67
|
+
|
|
68
|
+
import qcoder.engines.feature_extraction.adapters.qiskit_intake as qi
|
|
69
|
+
|
|
70
|
+
qc = QuantumCircuit(1)
|
|
71
|
+
qc.x(0)
|
|
72
|
+
|
|
73
|
+
def bad_dumps(_qc: object) -> str:
|
|
74
|
+
raise OSError("simulated export failure")
|
|
75
|
+
|
|
76
|
+
with unittest.mock.patch.object(
|
|
77
|
+
qi,
|
|
78
|
+
"_load_qiskit",
|
|
79
|
+
return_value=(QuantumCircuit, bad_dumps),
|
|
80
|
+
):
|
|
81
|
+
with self.assertRaises(RuntimeError) as ctx:
|
|
82
|
+
qi.circuit_ir_from_qiskit(qc)
|
|
83
|
+
msg = str(ctx.exception)
|
|
84
|
+
self.assertIn("qcoder", msg.lower())
|
|
85
|
+
self.assertIn("qiskit.qasm2.dumps", msg.lower())
|
|
86
|
+
|
|
87
|
+
def test_parse_failure_raises_runtime_error_with_guidance(self) -> None:
|
|
88
|
+
from qiskit import QuantumCircuit
|
|
89
|
+
|
|
90
|
+
import qcoder.engines.feature_extraction.adapters.qiskit_intake as qi
|
|
91
|
+
|
|
92
|
+
qc = QuantumCircuit(1)
|
|
93
|
+
qc.x(0)
|
|
94
|
+
with unittest.mock.patch.object(
|
|
95
|
+
qi,
|
|
96
|
+
"parse_qasm2_text",
|
|
97
|
+
side_effect=ValueError("simulated parse failure"),
|
|
98
|
+
):
|
|
99
|
+
with self.assertRaises(RuntimeError) as ctx:
|
|
100
|
+
qi.circuit_ir_from_qiskit(qc)
|
|
101
|
+
msg = str(ctx.exception)
|
|
102
|
+
self.assertIn("qcoder", msg.lower())
|
|
103
|
+
self.assertIn("could not parse", msg.lower())
|
|
104
|
+
|
|
64
105
|
|
|
65
106
|
class TestQiskitIntakeWithoutQiskit(unittest.TestCase):
|
|
66
107
|
"""Runs when qiskit is absent; skipped assertions when qiskit is present."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/adapters/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/features/compute_v0.py
RENAMED
|
File without changes
|
{qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/features/glossary_v0.py
RENAMED
|
File without changes
|
{qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/features/schema_v0.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/qasm2_regex_parser.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/reps/entangling_layers.py
RENAMED
|
File without changes
|
{qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/reps/gate_set_stats.py
RENAMED
|
File without changes
|
{qcoder-0.2.0a1 → qcoder-0.3.0a1}/src/qcoder/engines/feature_extraction/reps/interaction_graph.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|