qcoder 0.1.0a0__py3-none-any.whl

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.
Files changed (62) hide show
  1. qcoder/__init__.py +3 -0
  2. qcoder/__main__.py +6 -0
  3. qcoder/cli.py +116 -0
  4. qcoder/core/__init__.py +1 -0
  5. qcoder/core/context.py +16 -0
  6. qcoder/core/qasm2/__init__.py +1 -0
  7. qcoder/core/qasm2/adjoint_eligibility.py +128 -0
  8. qcoder/core/qasm2/mirror_build.py +234 -0
  9. qcoder/core/run_config.py +84 -0
  10. qcoder/core/schema.py +26 -0
  11. qcoder/engines/feature_extraction/adapters/__init__.py +1 -0
  12. qcoder/engines/feature_extraction/adapters/qiskit_intake.py +46 -0
  13. qcoder/engines/feature_extraction/extractor.py +43 -0
  14. qcoder/engines/feature_extraction/features/compute_v0.py +157 -0
  15. qcoder/engines/feature_extraction/features/schema_v0.py +84 -0
  16. qcoder/engines/feature_extraction/ir.py +41 -0
  17. qcoder/engines/feature_extraction/labeling.py +68 -0
  18. qcoder/engines/feature_extraction/parsers/__init__.py +21 -0
  19. qcoder/engines/feature_extraction/qasm2_regex_parser.py +184 -0
  20. qcoder/engines/feature_extraction/reps/cut_profile.py +106 -0
  21. qcoder/engines/feature_extraction/reps/depth.py +47 -0
  22. qcoder/engines/feature_extraction/reps/entangling_layers.py +57 -0
  23. qcoder/engines/feature_extraction/reps/gate_set_stats.py +82 -0
  24. qcoder/engines/feature_extraction/reps/interaction_graph.py +30 -0
  25. qcoder/engines/feature_extraction/reps/interaction_graph_metrics.py +113 -0
  26. qcoder/engines/feature_extraction/reps/spans.py +89 -0
  27. qcoder/engines/prediction_model/__init__.py +16 -0
  28. qcoder/engines/prediction_model/artifact.py +85 -0
  29. qcoder/engines/prediction_model/engine.py +209 -0
  30. qcoder/engines/prediction_model/models.py +62 -0
  31. qcoder/engines/prediction_model/policy.py +45 -0
  32. qcoder/engines/prediction_model/schema_alignment.py +41 -0
  33. qcoder/engines/quantumness/__init__.py +8 -0
  34. qcoder/engines/quantumness/scorer.py +254 -0
  35. qcoder/pipelines/analyze.py +131 -0
  36. qcoder/pipelines/batch.py +56 -0
  37. qcoder/tools/analyze.py +88 -0
  38. qcoder/tools/analyze_shot_scaling.py +239 -0
  39. qcoder/tools/batch.py +39 -0
  40. qcoder/tools/generate_corpus.py +491 -0
  41. qcoder/tools/harness.py +15 -0
  42. qcoder/tools/inspect_corpus_features.py +273 -0
  43. qcoder/tools/join_runs_features.py +252 -0
  44. qcoder/tools/mirror.py +15 -0
  45. qcoder/tools/predict_baseline.py +347 -0
  46. qcoder/tools/qr_dll_bootstrap.py +31 -0
  47. qcoder/tools/runner.py +15 -0
  48. qcoder/tools/runners/__init__.py +1 -0
  49. qcoder/tools/runners/quantum_rings/__init__.py +1 -0
  50. qcoder/tools/runners/quantum_rings/v12/__init__.py +1 -0
  51. qcoder/tools/runners/quantum_rings/v12/harness.py +1350 -0
  52. qcoder/tools/runners/quantum_rings/v12/mirror.py +459 -0
  53. qcoder/tools/runners/quantum_rings/v12/runner.py +549 -0
  54. qcoder/tools/train_baseline_models.py +619 -0
  55. qcoder/tools/validate_baseline.py +307 -0
  56. qcoder-0.1.0a0.dist-info/METADATA +86 -0
  57. qcoder-0.1.0a0.dist-info/RECORD +62 -0
  58. qcoder-0.1.0a0.dist-info/WHEEL +5 -0
  59. qcoder-0.1.0a0.dist-info/entry_points.txt +2 -0
  60. qcoder-0.1.0a0.dist-info/licenses/LICENSE +201 -0
  61. qcoder-0.1.0a0.dist-info/licenses/NOTICE +11 -0
  62. qcoder-0.1.0a0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,347 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import math
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from qcoder.engines.feature_extraction.extractor import extract_example
11
+
12
+
13
+ DEFAULT_RUNTIME_ARTIFACT = Path("data/artifacts/models/qr12/schema_0.4.0/runtime_ridge.json")
14
+ DEFAULT_BUILD_ARTIFACT = Path("data/artifacts/models/qr12/schema_0.4.0/build_ridge.json")
15
+ DEFAULT_FIDELITY_ARTIFACT = Path("data/artifacts/models/qr12/schema_0.4.0/fidelity_ridge.json")
16
+ DEFAULT_MEMORY_ARTIFACT = Path("data/artifacts/models/qr12/schema_0.4.0/memory_ridge.json")
17
+ DEFAULT_LADDER = [2, 4, 8, 16, 32, 64]
18
+ DEFAULT_SHOTS_TOTAL = 10000
19
+
20
+
21
+ @dataclass(frozen=True)
22
+ class RidgeArtifact:
23
+ schema_version: str
24
+ feature_names: list[str]
25
+ coef: list[float]
26
+ x_mean: list[float]
27
+ x_std: list[float]
28
+ alpha: float
29
+
30
+
31
+ def _parse_ladder(text: str) -> list[int]:
32
+ out: list[int] = []
33
+ for part in (text or "").split(","):
34
+ s = part.strip()
35
+ if not s:
36
+ continue
37
+ v = int(s)
38
+ if v <= 0:
39
+ raise ValueError(f"ladder threshold must be > 0, got {v}")
40
+ out.append(v)
41
+ if not out:
42
+ raise ValueError("empty ladder")
43
+ return out
44
+
45
+
46
+ def load_ridge_artifact(path: str | Path) -> RidgeArtifact:
47
+ p = Path(path)
48
+ try:
49
+ raw = p.read_text(encoding="utf-8")
50
+ except FileNotFoundError as e:
51
+ raise FileNotFoundError(
52
+ f"ridge artifact not found: {p.resolve()} "
53
+ "(train models with qcoder.tools.train_baseline_models or pass explicit artifact paths)"
54
+ ) from e
55
+ data = json.loads(raw)
56
+
57
+ schema_version = data.get("schema_version")
58
+ feature_names = data.get("feature_names")
59
+ coef = data.get("coef")
60
+ x_mean = data.get("x_mean")
61
+ x_std = data.get("x_std")
62
+ alpha = data.get("alpha", 1.0)
63
+
64
+ if not isinstance(schema_version, str) or not schema_version:
65
+ raise ValueError(f"invalid artifact schema_version: {path}")
66
+ if not isinstance(feature_names, list) or not feature_names:
67
+ raise ValueError(f"invalid artifact feature_names: {path}")
68
+ if not isinstance(coef, list) or not isinstance(x_mean, list) or not isinstance(x_std, list):
69
+ raise ValueError(f"invalid artifact vectors: {path}")
70
+
71
+ n = len(feature_names)
72
+ if len(coef) != n or len(x_mean) != n or len(x_std) != n:
73
+ raise ValueError(f"artifact vector length mismatch in {path}")
74
+
75
+ coef_f = [float(v) for v in coef]
76
+ mean_f = [float(v) for v in x_mean]
77
+ std_f = [1.0 if float(v) == 0.0 else float(v) for v in x_std]
78
+
79
+ return RidgeArtifact(
80
+ schema_version=schema_version,
81
+ feature_names=[str(nm) for nm in feature_names],
82
+ coef=coef_f,
83
+ x_mean=mean_f,
84
+ x_std=std_f,
85
+ alpha=float(alpha),
86
+ )
87
+
88
+
89
+ def _build_input_vector(
90
+ artifact: RidgeArtifact,
91
+ *,
92
+ feature_map: dict[str, float],
93
+ threshold: int,
94
+ precision: str,
95
+ shots_total: int | None = None,
96
+ ) -> list[float]:
97
+ precision_is_double = 1.0 if str(precision).strip().lower() in {"double", "fp64"} else 0.0
98
+ cond: dict[str, float] = {
99
+ "bias": 1.0,
100
+ "log2_threshold": math.log2(float(threshold)),
101
+ "precision_is_double": precision_is_double,
102
+ }
103
+ if "log2_shots_runner" in artifact.feature_names:
104
+ cond["log2_shots_runner"] = math.log2(max(1, shots_total if shots_total is not None else DEFAULT_SHOTS_TOTAL))
105
+ x: list[float] = []
106
+ for name in artifact.feature_names:
107
+ if name in cond:
108
+ x.append(cond[name])
109
+ continue
110
+ if name not in feature_map:
111
+ raise ValueError(f"artifact expects missing feature '{name}'")
112
+ x.append(float(feature_map[name]))
113
+ return x
114
+
115
+
116
+ def _predict_linear(artifact: RidgeArtifact, x: list[float]) -> float:
117
+ if len(x) != len(artifact.coef):
118
+ raise ValueError("input vector length mismatch")
119
+ total = 0.0
120
+ for i, v in enumerate(x):
121
+ z = (float(v) - artifact.x_mean[i]) / artifact.x_std[i]
122
+ total += artifact.coef[i] * z
123
+ return total
124
+
125
+
126
+ def _sigmoid(x: float) -> float:
127
+ if x >= 0:
128
+ e = math.exp(-x)
129
+ return 1.0 / (1.0 + e)
130
+ e = math.exp(x)
131
+ return e / (1.0 + e)
132
+
133
+
134
+ def predict_threshold_table(
135
+ *,
136
+ qasm_path: str,
137
+ runtime_artifact_path: str | Path = DEFAULT_RUNTIME_ARTIFACT,
138
+ build_artifact_path: str | Path | None = None,
139
+ memory_artifact_path: str | Path | None = None,
140
+ fidelity_artifact_path: str | Path = DEFAULT_FIDELITY_ARTIFACT,
141
+ ladder: list[int] | None = None,
142
+ precision: str = "double",
143
+ shots_total: int | None = None,
144
+ ) -> dict[str, Any]:
145
+ ex = extract_example(qasm_path)
146
+ fv = ex.global_features
147
+ feature_map = dict(zip(fv.feature_names, fv.features))
148
+
149
+ runtime_art = load_ridge_artifact(runtime_artifact_path)
150
+ build_art = load_ridge_artifact(build_artifact_path) if build_artifact_path is not None else None
151
+ memory_art = load_ridge_artifact(memory_artifact_path) if memory_artifact_path is not None else None
152
+ fidelity_art = load_ridge_artifact(fidelity_artifact_path)
153
+
154
+ if runtime_art.schema_version != fv.schema_version:
155
+ raise ValueError(
156
+ f"runtime artifact schema mismatch: features={fv.schema_version}, artifact={runtime_art.schema_version}"
157
+ )
158
+ if fidelity_art.schema_version != fv.schema_version:
159
+ raise ValueError(
160
+ f"fidelity artifact schema mismatch: features={fv.schema_version}, artifact={fidelity_art.schema_version}"
161
+ )
162
+ if build_art is not None and build_art.schema_version != fv.schema_version:
163
+ raise ValueError(
164
+ f"build artifact schema mismatch: features={fv.schema_version}, artifact={build_art.schema_version}"
165
+ )
166
+ if memory_art is not None and memory_art.schema_version != fv.schema_version:
167
+ raise ValueError(
168
+ f"memory artifact schema mismatch: features={fv.schema_version}, artifact={memory_art.schema_version}"
169
+ )
170
+
171
+ # Backward compatibility: runtime artifact may predict total (old) or execution time (execution_runtime_ridge).
172
+ runtime_artifact_data = json.loads(Path(runtime_artifact_path).read_text(encoding="utf-8"))
173
+ runtime_model_kind = (runtime_artifact_data.get("training_metadata") or {}).get("model_kind")
174
+
175
+ use_ladder = list(ladder or DEFAULT_LADDER)
176
+ shots = shots_total if shots_total is not None else DEFAULT_SHOTS_TOTAL
177
+ rows: list[dict[str, float | int]] = []
178
+ for thr in use_ladder:
179
+ x_rt = _build_input_vector(
180
+ runtime_art, feature_map=feature_map, threshold=int(thr), precision=precision, shots_total=shots
181
+ )
182
+ y_rt = _predict_linear(runtime_art, x_rt)
183
+ pred_build: float | None = None
184
+ pred_exec: float | None = None
185
+ pred_total: float
186
+ if runtime_model_kind == "execution_runtime_ridge":
187
+ # Runtime model predicts execution time; total = build + exec.
188
+ pred_exec = max(0.0, math.expm1(y_rt))
189
+ if build_art is not None:
190
+ x_bd = _build_input_vector(build_art, feature_map=feature_map, threshold=int(thr), precision=precision)
191
+ y_bd = _predict_linear(build_art, x_bd)
192
+ pred_build = max(0.0, math.expm1(y_bd))
193
+ pred_total = float(pred_build) + float(pred_exec)
194
+ else:
195
+ pred_total = float(pred_exec)
196
+ else:
197
+ # Legacy: runtime model predicts total runtime; exec = total - build.
198
+ pred_total = max(0.0, math.expm1(y_rt))
199
+ if build_art is not None:
200
+ x_bd = _build_input_vector(build_art, feature_map=feature_map, threshold=int(thr), precision=precision)
201
+ y_bd = _predict_linear(build_art, x_bd)
202
+ pred_build = max(0.0, math.expm1(y_bd))
203
+ pred_exec = max(0.0, float(pred_total) - float(pred_build))
204
+
205
+ pred_mem_mb: float | None = None
206
+ if memory_art is not None:
207
+ x_mb = _build_input_vector(memory_art, feature_map=feature_map, threshold=int(thr), precision=precision)
208
+ y_mb = _predict_linear(memory_art, x_mb)
209
+ pred_mem_mb = max(0.0, math.expm1(y_mb))
210
+
211
+ x_fd = _build_input_vector(fidelity_art, feature_map=feature_map, threshold=int(thr), precision=precision)
212
+ y_fd = _predict_linear(fidelity_art, x_fd)
213
+ pred_fidelity = _sigmoid(y_fd)
214
+
215
+ rows.append(
216
+ {
217
+ "threshold": int(thr),
218
+ "predicted_total_runtime_s": float(pred_total),
219
+ "predicted_runtime_s": float(pred_total), # backward-compat alias
220
+ "predicted_fidelity": float(pred_fidelity),
221
+ }
222
+ )
223
+ if pred_build is not None and pred_exec is not None:
224
+ rows[-1]["predicted_build_time_s"] = float(pred_build)
225
+ rows[-1]["predicted_exec_time_s"] = float(pred_exec)
226
+ rows[-1]["predicted_exec_time_per_shot_s"] = float(pred_exec) / float(shots)
227
+ rows[-1]["predicted_exec_time_per_1000_shots_s"] = 1000.0 * float(pred_exec) / float(shots)
228
+ if pred_mem_mb is not None:
229
+ rows[-1]["predicted_peak_mem_mb"] = float(pred_mem_mb)
230
+
231
+ return {
232
+ "qasm_path": str(qasm_path),
233
+ "schema_version": fv.schema_version,
234
+ "n_features": len(fv.features),
235
+ "precision": precision,
236
+ "rows": rows,
237
+ }
238
+
239
+
240
+ def _recommend_threshold(rows: list[dict[str, float | int]], target_fidelity: float) -> int | None:
241
+ candidates = [int(r["threshold"]) for r in rows if float(r["predicted_fidelity"]) >= target_fidelity]
242
+ if not candidates:
243
+ return None
244
+ return min(candidates)
245
+
246
+
247
+ def _print_table(result: dict[str, Any], target_fidelity: float | None) -> None:
248
+ print(f"qasm: {result['qasm_path']}")
249
+ print(f"schema: {result['schema_version']} n_features: {result['n_features']} precision: {result['precision']}")
250
+ print("")
251
+ has_build = any(("predicted_build_time_s" in r and "predicted_exec_time_s" in r) for r in result["rows"])
252
+ has_mem = any("predicted_peak_mem_mb" in r for r in result["rows"])
253
+ if has_build and has_mem:
254
+ print(
255
+ f"{'threshold':>9} {'pred_build_time_s':>17} {'pred_exec_time_s':>16} {'pred_exec_per_shot_s':>18} {'pred_exec_per_1000_s':>16} {'pred_total_runtime_s':>20} {'predicted_fidelity':>19} {'pred_peak_mem_mb':>16}"
256
+ )
257
+ print("-" * 149)
258
+ elif has_build:
259
+ print(
260
+ f"{'threshold':>9} {'pred_build_time_s':>17} {'pred_exec_time_s':>16} {'pred_exec_per_shot_s':>18} {'pred_exec_per_1000_s':>16} {'pred_total_runtime_s':>20} {'predicted_fidelity':>19}"
261
+ )
262
+ print("-" * 125)
263
+ else:
264
+ print(f"{'threshold':>9} {'pred_total_runtime_s':>20} {'predicted_fidelity':>19}")
265
+ print("-" * 54)
266
+ for r in result["rows"]:
267
+ if has_build and has_mem:
268
+ print(
269
+ f"{int(r['threshold']):>9} {float(r['predicted_build_time_s']):>17.6f} {float(r['predicted_exec_time_s']):>16.6f} {float(r['predicted_exec_time_per_shot_s']):>18.6e} {float(r['predicted_exec_time_per_1000_shots_s']):>16.6f} {float(r['predicted_total_runtime_s']):>20.6f} {float(r['predicted_fidelity']):>19.6f} {float(r['predicted_peak_mem_mb']):>16.3f}"
270
+ )
271
+ elif has_build:
272
+ print(
273
+ f"{int(r['threshold']):>9} {float(r['predicted_build_time_s']):>17.6f} {float(r['predicted_exec_time_s']):>16.6f} {float(r['predicted_exec_time_per_shot_s']):>18.6e} {float(r['predicted_exec_time_per_1000_shots_s']):>16.6f} {float(r['predicted_total_runtime_s']):>20.6f} {float(r['predicted_fidelity']):>19.6f}"
274
+ )
275
+ else:
276
+ print(
277
+ f"{int(r['threshold']):>9} {float(r['predicted_total_runtime_s']):>20.6f} {float(r['predicted_fidelity']):>19.6f}"
278
+ )
279
+ if target_fidelity is not None:
280
+ rec = _recommend_threshold(result["rows"], target_fidelity)
281
+ print("")
282
+ if rec is None:
283
+ print(f"recommended_threshold(target={target_fidelity:.4f}): none_meets_target")
284
+ else:
285
+ print(f"recommended_threshold(target={target_fidelity:.4f}): {rec}")
286
+
287
+
288
+ def main(argv: list[str] | None = None) -> int:
289
+ ap = argparse.ArgumentParser(description="Predict runtime/fidelity over a threshold ladder for one QASM.")
290
+ ap.add_argument("qasm", help="Path to one .qasm file")
291
+ ap.add_argument("--runtime-artifact", default=str(DEFAULT_RUNTIME_ARTIFACT), help="Path to runtime_ridge.json")
292
+ ap.add_argument(
293
+ "--build-artifact",
294
+ default=None,
295
+ help="Optional path to build_ridge.json. If omitted, defaults to schema build_ridge when present.",
296
+ )
297
+ ap.add_argument(
298
+ "--memory-artifact",
299
+ default=None,
300
+ help="Optional path to memory_ridge.json. If omitted, defaults to schema memory_ridge when present.",
301
+ )
302
+ ap.add_argument("--fidelity-artifact", default=str(DEFAULT_FIDELITY_ARTIFACT), help="Path to fidelity_ridge.json")
303
+ ap.add_argument("--ladder", default="2,4,8,16,32,64", help="Comma-separated threshold ladder")
304
+ ap.add_argument("--precision", default="double", help="single|double (used for precision_is_double)")
305
+ ap.add_argument("--shots-total", type=int, default=None, help="Total-run shot count for runtime prediction (default: 10000)")
306
+ ap.add_argument("--target-fidelity", type=float, default=None, help="Optional target fidelity for recommended threshold")
307
+ ap.add_argument("--json", action="store_true", help="Emit JSON instead of text table")
308
+ args = ap.parse_args(argv)
309
+
310
+ ladder = _parse_ladder(args.ladder)
311
+ build_path: str | Path | None
312
+ if args.build_artifact:
313
+ build_path = args.build_artifact
314
+ elif DEFAULT_BUILD_ARTIFACT.exists():
315
+ build_path = DEFAULT_BUILD_ARTIFACT
316
+ else:
317
+ build_path = None
318
+ mem_path: str | Path | None
319
+ if args.memory_artifact:
320
+ mem_path = args.memory_artifact
321
+ elif DEFAULT_MEMORY_ARTIFACT.exists():
322
+ mem_path = DEFAULT_MEMORY_ARTIFACT
323
+ else:
324
+ mem_path = None
325
+
326
+ result = predict_threshold_table(
327
+ qasm_path=args.qasm,
328
+ runtime_artifact_path=args.runtime_artifact,
329
+ build_artifact_path=build_path,
330
+ memory_artifact_path=mem_path,
331
+ fidelity_artifact_path=args.fidelity_artifact,
332
+ ladder=ladder,
333
+ precision=args.precision,
334
+ shots_total=args.shots_total,
335
+ )
336
+ if args.target_fidelity is not None:
337
+ result["recommended_threshold"] = _recommend_threshold(result["rows"], float(args.target_fidelity))
338
+
339
+ if args.json:
340
+ print(json.dumps(result, indent=2, sort_keys=True))
341
+ else:
342
+ _print_table(result, args.target_fidelity)
343
+ return 0
344
+
345
+
346
+ if __name__ == "__main__":
347
+ raise SystemExit(main())
@@ -0,0 +1,31 @@
1
+ # qr_dll_bootstrap.py
2
+ # Ensure CUDA DLLs are discoverable on Windows before importing QuantumRingsLib.
3
+
4
+ import os
5
+ import platform
6
+
7
+
8
+ def setup_cuda_dll_search_paths() -> None:
9
+ if platform.system().lower() != "windows":
10
+ return
11
+
12
+ candidates = [
13
+ r"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.1\bin",
14
+ r"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.1\bin\x64",
15
+ ]
16
+
17
+ for p in candidates:
18
+ if os.path.isdir(p):
19
+ os.add_dll_directory(p)
20
+
21
+
22
+ def bootstrap() -> None:
23
+ """Canonical QCoder entrypoint for DLL/bootstrap setup."""
24
+ setup_cuda_dll_search_paths()
25
+
26
+
27
+ # Back-compat aliases
28
+ setup_dll_search_paths = setup_cuda_dll_search_paths
29
+
30
+ # Run on import
31
+ bootstrap()
qcoder/tools/runner.py ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ qcoder.tools.runner — entrypoint that delegates to Quantum Rings v12 runner.
4
+ """
5
+ from qcoder.tools.runners.quantum_rings.v12.runner import main, die
6
+
7
+ if __name__ == "__main__":
8
+ try:
9
+ main()
10
+ except SystemExit:
11
+ raise
12
+ except Exception as e:
13
+ import traceback
14
+ traceback.print_exc()
15
+ die(f"Unhandled exception: {e}")
@@ -0,0 +1 @@
1
+ # Runner family implementations (e.g. quantum_rings/v12)
@@ -0,0 +1 @@
1
+ # Quantum Rings SDK runner family
@@ -0,0 +1 @@
1
+ # Quantum Rings SDK v12 harness, runner, mirror