Instructions to use itsalissonsilva/QuantumCoder-9B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use itsalissonsilva/QuantumCoder-9B with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3.5-9B") model = PeftModel.from_pretrained(base_model, "itsalissonsilva/QuantumCoder-9B") - Notebooks
- Google Colab
- Kaggle
Release independently executed all-framework quantum adapter with stress failures, helper parity and original negative study preserved
Browse files- LICENSE +202 -0
- NOTICE +1 -0
- README.md +70 -0
- adapter_config.json +42 -0
- adapter_model.safetensors +3 -0
- prompt_parity.json +5 -0
- quantum.py +84 -0
- quantum_sandbox_v2.py +317 -0
- release_audit.json +11 -0
- reproduce_execution.py +69 -0
- requirements-evaluation.txt +7 -0
- requirements-inference.txt +8 -0
LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
Apache License
|
| 3 |
+
Version 2.0, January 2004
|
| 4 |
+
http://www.apache.org/licenses/
|
| 5 |
+
|
| 6 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 7 |
+
|
| 8 |
+
1. Definitions.
|
| 9 |
+
|
| 10 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 11 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 12 |
+
|
| 13 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 14 |
+
the copyright owner that is granting the License.
|
| 15 |
+
|
| 16 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 17 |
+
other entities that control, are controlled by, or are under common
|
| 18 |
+
control with that entity. For the purposes of this definition,
|
| 19 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 20 |
+
direction or management of such entity, whether by contract or
|
| 21 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 22 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 23 |
+
|
| 24 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 25 |
+
exercising permissions granted by this License.
|
| 26 |
+
|
| 27 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 28 |
+
including but not limited to software source code, documentation
|
| 29 |
+
source, and configuration files.
|
| 30 |
+
|
| 31 |
+
"Object" form shall mean any form resulting from mechanical
|
| 32 |
+
transformation or translation of a Source form, including but
|
| 33 |
+
not limited to compiled object code, generated documentation,
|
| 34 |
+
and conversions to other media types.
|
| 35 |
+
|
| 36 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 37 |
+
Object form, made available under the License, as indicated by a
|
| 38 |
+
copyright notice that is included in or attached to the work
|
| 39 |
+
(an example is provided in the Appendix below).
|
| 40 |
+
|
| 41 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 42 |
+
form, that is based on (or derived from) the Work and for which the
|
| 43 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 44 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 45 |
+
of this License, Derivative Works shall not include works that remain
|
| 46 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 47 |
+
the Work and Derivative Works thereof.
|
| 48 |
+
|
| 49 |
+
"Contribution" shall mean any work of authorship, including
|
| 50 |
+
the original version of the Work and any modifications or additions
|
| 51 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 52 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 53 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 54 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 55 |
+
means any form of electronic, verbal, or written communication sent
|
| 56 |
+
to the Licensor or its representatives, including but not limited to
|
| 57 |
+
communication on electronic mailing lists, source code control systems,
|
| 58 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 59 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 60 |
+
excluding communication that is conspicuously marked or otherwise
|
| 61 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 62 |
+
|
| 63 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 64 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 65 |
+
subsequently incorporated within the Work.
|
| 66 |
+
|
| 67 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 68 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 69 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 70 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 71 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 72 |
+
Work and such Derivative Works in Source or Object form.
|
| 73 |
+
|
| 74 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 75 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 76 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 77 |
+
(except as stated in this section) patent license to make, have made,
|
| 78 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 79 |
+
where such license applies only to those patent claims licensable
|
| 80 |
+
by such Contributor that are necessarily infringed by their
|
| 81 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 82 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 83 |
+
institute patent litigation against any entity (including a
|
| 84 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 85 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 86 |
+
or contributory patent infringement, then any patent licenses
|
| 87 |
+
granted to You under this License for that Work shall terminate
|
| 88 |
+
as of the date such litigation is filed.
|
| 89 |
+
|
| 90 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 91 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 92 |
+
modifications, and in Source or Object form, provided that You
|
| 93 |
+
meet the following conditions:
|
| 94 |
+
|
| 95 |
+
(a) You must give any other recipients of the Work or
|
| 96 |
+
Derivative Works a copy of this License; and
|
| 97 |
+
|
| 98 |
+
(b) You must cause any modified files to carry prominent notices
|
| 99 |
+
stating that You changed the files; and
|
| 100 |
+
|
| 101 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 102 |
+
that You distribute, all copyright, patent, trademark, and
|
| 103 |
+
attribution notices from the Source form of the Work,
|
| 104 |
+
excluding those notices that do not pertain to any part of
|
| 105 |
+
the Derivative Works; and
|
| 106 |
+
|
| 107 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 108 |
+
distribution, then any Derivative Works that You distribute must
|
| 109 |
+
include a readable copy of the attribution notices contained
|
| 110 |
+
within such NOTICE file, excluding those notices that do not
|
| 111 |
+
pertain to any part of the Derivative Works, in at least one
|
| 112 |
+
of the following places: within a NOTICE text file distributed
|
| 113 |
+
as part of the Derivative Works; within the Source form or
|
| 114 |
+
documentation, if provided along with the Derivative Works; or,
|
| 115 |
+
within a display generated by the Derivative Works, if and
|
| 116 |
+
wherever such third-party notices normally appear. The contents
|
| 117 |
+
of the NOTICE file are for informational purposes only and
|
| 118 |
+
do not modify the License. You may add Your own attribution
|
| 119 |
+
notices within Derivative Works that You distribute, alongside
|
| 120 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 121 |
+
that such additional attribution notices cannot be construed
|
| 122 |
+
as modifying the License.
|
| 123 |
+
|
| 124 |
+
You may add Your own copyright statement to Your modifications and
|
| 125 |
+
may provide additional or different license terms and conditions
|
| 126 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 127 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 128 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 129 |
+
the conditions stated in this License.
|
| 130 |
+
|
| 131 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 132 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 133 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 134 |
+
this License, without any additional terms or conditions.
|
| 135 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 136 |
+
the terms of any separate license agreement you may have executed
|
| 137 |
+
with Licensor regarding such Contributions.
|
| 138 |
+
|
| 139 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 140 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 141 |
+
except as required for reasonable and customary use in describing the
|
| 142 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 143 |
+
|
| 144 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 145 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 146 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 147 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 148 |
+
implied, including, without limitation, any warranties or conditions
|
| 149 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 150 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 151 |
+
appropriateness of using or redistributing the Work and assume any
|
| 152 |
+
risks associated with Your exercise of permissions under this License.
|
| 153 |
+
|
| 154 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 155 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 156 |
+
unless required by applicable law (such as deliberate and grossly
|
| 157 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 158 |
+
liable to You for damages, including any direct, indirect, special,
|
| 159 |
+
incidental, or consequential damages of any character arising as a
|
| 160 |
+
result of this License or out of the use or inability to use the
|
| 161 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 162 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 163 |
+
other commercial damages or losses), even if such Contributor
|
| 164 |
+
has been advised of the possibility of such damages.
|
| 165 |
+
|
| 166 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 167 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 168 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 169 |
+
or other liability obligations and/or rights consistent with this
|
| 170 |
+
License. However, in accepting such obligations, You may act only
|
| 171 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 172 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 173 |
+
defend, and hold each Contributor harmless for any liability
|
| 174 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 175 |
+
of your accepting any such warranty or additional liability.
|
| 176 |
+
|
| 177 |
+
END OF TERMS AND CONDITIONS
|
| 178 |
+
|
| 179 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 180 |
+
|
| 181 |
+
To apply the Apache License to your work, attach the following
|
| 182 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 183 |
+
replaced with your own identifying information. (Don't include
|
| 184 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 185 |
+
comment syntax for the file format. We also recommend that a
|
| 186 |
+
file or class name and description of purpose be included on the
|
| 187 |
+
same "printed page" as the copyright notice for easier
|
| 188 |
+
identification within third-party archives.
|
| 189 |
+
|
| 190 |
+
Copyright 2026 Alibaba Cloud
|
| 191 |
+
|
| 192 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 193 |
+
you may not use this file except in compliance with the License.
|
| 194 |
+
You may obtain a copy of the License at
|
| 195 |
+
|
| 196 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 197 |
+
|
| 198 |
+
Unless required by applicable law or agreed to in writing, software
|
| 199 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 200 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 201 |
+
See the License for the specific language governing permissions and
|
| 202 |
+
limitations under the License.
|
NOTICE
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
QuantumCoder-9B: modified Qwen3.5-9B with a newly trained low-rank adapter by itsalissonsilva. Base model and software are Apache2.0. Original synthetic curriculum is separately CC BY4.0; see curriculum_v2/LICENSE.md. No upstream base weights redistributed.
|
README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
library_name: peft
|
| 4 |
+
pipeline_tag: text-generation
|
| 5 |
+
base_model: Qwen/Qwen3.5-9B
|
| 6 |
+
tags:
|
| 7 |
+
- quantum-computing
|
| 8 |
+
- circuit-to-code
|
| 9 |
+
- lora
|
| 10 |
+
- synthetic-data
|
| 11 |
+
---
|
| 12 |
+
# QuantumCoder-9B
|
| 13 |
+
|
| 14 |
+
A rank 16 Qwen3.5-9B adapter for translating fully specified synthetic quantum circuits into Qiskit, PennyLane or Cirq Python. The independently executed follow-up passes 288/288 held-out circuit/framework cases and 282/288 larger stress cases. The saved-weight helper reproduces all eight fixed validation generations exactly.
|
| 15 |
+
|
| 16 |
+
**A deterministic renderer already solves this structured task perfectly.** This is learned circuit-to-program translation, including framework APIs and little-endian state conventions. It is not quantum algorithm discovery, general quantum programming, full unitary verification or a result on real quantum hardware.
|
| 17 |
+
|
| 18 |
+
## Results
|
| 19 |
+
|
| 20 |
+
One greedy sample, 768 generated-token cap, thinking disabled. Passing requires requested-framework import, supported-Python execution, unit norm and global-phase-invariant zero-input state fidelity greater than 1−1e−6.
|
| 21 |
+
|
| 22 |
+
| Split | Circuit groups | Framework cases | Base passes | Adapter passes |
|
| 23 |
+
|---|---:|---:|---:|---:|
|
| 24 |
+
| Validation |48|144|16 (11.11%)|144 (100%)|
|
| 25 |
+
| Held-out circuits/angles |96|288|36 (12.50%)|288 (100%)|
|
| 26 |
+
| Larger/nonlocal/deeper stress |96|288|47 (16.32%)|282 (97.92%)|
|
| 27 |
+
|
| 28 |
+
Each circuit appears in all three frameworks; these are not 288 independent circuits. Circuit-group bootstrap 95% intervals for adapter-minus-base Pass@1 are [83.33,91.32] percentage points on the held-out split and [77.78,85.42] on stress. Six stress failures remain included. Per-framework results and every scored program are under [v2_execution](v2_execution/).
|
| 29 |
+
|
| 30 |
+
The executor is deliberately restricted and may reject other valid Python/API implementations. These percentages measure supported-program compliance plus state correctness, not unrestricted programming ability. The base executed 130/288 held-out programs and 114/288 stress programs; 36 and 47 respectively had correct states. The adapter executed all 288 in each split. Import presence is a compliance proxy, not a formal data-flow proof.
|
| 31 |
+
|
| 32 |
+
## Data and training
|
| 33 |
+
|
| 34 |
+
The fresh [curriculum](curriculum_v2/) has 456 circuit groups / 1,368 framework views: 216/648 training, 48/144 validation and 96/288 in each test split. Training contains all three frameworks. All 2,000 original-study circuit groups were excluded. Group IDs, rotation-angle sets and input hashes are disjoint across partitions; an independent audit finds no exact zero-input-state duplicates between training and matching-dimension holdouts at fidelity tolerance 1e−8. This does not establish full process-equivalence separation.
|
| 35 |
+
|
| 36 |
+
Training uses 2–4 qubits, adjacent CNOTs and 6–13 gates. Stress uses 5–6 qubits, nonlocal CNOTs and 16–24 gates. Gates are H/X/Z/RY/RZ/CX. All 1,368 reference programs passed the pinned three-framework executor before model scoring. Data are original synthetic circuits with exact statevectors, not experimental measurements.
|
| 37 |
+
|
| 38 |
+
Base [Qwen3.5-9B](https://huggingface.co/Qwen/Qwen3.5-9B), revision `c202236235762e1c871ad0ccb60c8ee5ba337b9a`. One fixed epoch from the base, 648 examples, rank 16/alpha 32 on q_proj/v_proj/in_proj_qkv, AdamW learning rate 2e−5, gradient accumulation 8, seed 20261101, max training sequence 2,048. No test checkpoint selection. Training code, original programs, model outputs and audits remain in this repository.
|
| 39 |
+
|
| 40 |
+
## Inference
|
| 41 |
+
|
| 42 |
+
Download this repository and install `requirements-inference.txt` in a CUDA environment with enough memory for 9B weights (the checked configuration used an A100). From the downloaded repository:
|
| 43 |
+
|
| 44 |
+
```python
|
| 45 |
+
from quantum import QuantumCoder
|
| 46 |
+
coder = QuantumCoder()
|
| 47 |
+
result = coder.generate([{
|
| 48 |
+
"framework": "cirq", "qubits": 2,
|
| 49 |
+
"operations": [["h", [0], 0.0], ["ry", [1], 0.31],
|
| 50 |
+
["rz", [0], 0.67], ["cx", [0, 1], 0.0],
|
| 51 |
+
["h", [1], 0.0], ["z", [0], 0.0]]
|
| 52 |
+
}])[0]
|
| 53 |
+
print(result["program"])
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
The helper returns fallible source text and never executes it. `operations` follows [gate,qubit_indices,angle_in_radians]; non-rotation angles are 0. The measured limits are 2–6 qubits and at most 24 gates. Prompts beyond 2,048 tokens are rejected rather than truncated. Generation matches the frozen greedy 768-token protocol in batches of eight.
|
| 57 |
+
|
| 58 |
+
## Reproduce execution
|
| 59 |
+
|
| 60 |
+
Use an isolated Linux environment with Python 3.11, `libseccomp2` and `requirements-evaluation.txt`. The parent must run as root so workers can drop to UID/GID 65534. From a full repository snapshot, run `python reproduce_execution.py`. It first verifies the frozen sandbox/data hashes, isolation and every selected reference, then re-scores all 1,440 base/adapted programs and checks the published counts. This public reproducer was run successfully before release. Do not substitute direct host execution for the provided runner.
|
| 61 |
+
|
| 62 |
+
Workers clear their environment, deny filesystem opens/network/process execution, apply resource/time limits and screen a bounded Python subset. This is an evaluation harness for these programs, not a general arbitrary-code sandbox service. Original full scoring source and circuit-group bootstrap remain under[v2_execution](v2_execution/); helper parity is under[helper_verification](helper_verification/).
|
| 63 |
+
|
| 64 |
+
## Original negative study
|
| 65 |
+
|
| 66 |
+
The earlier [hf_pilot](hf_pilot/) trained on Qiskit/PennyLane and held out Cirq. Its adapter passed 0/128 Cirq cases versus 3/128 for the base under the original strict executor. Some valid Cirq aliases were unsupported there. The failure and original evaluator remain under [execution](execution/) and [executor_preflight](executor_preflight/). The new study uses fresh groups and explicitly trains all frameworks; it is not a zero-shot Cirq success and does not replace that negative result.
|
| 67 |
+
|
| 68 |
+
## Licensing
|
| 69 |
+
|
| 70 |
+
Adapter/base-derived weights and code: Apache 2.0; base attribution retained in LICENSE/NOTICE. Original synthetic data: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/), attributed to itsalissonsilva. Quantum frameworks have their own upstream licenses and are not redistributed as part of the adapter.
|
adapter_config.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"alora_invocation_tokens": null,
|
| 3 |
+
"alpha_pattern": {},
|
| 4 |
+
"arrow_config": null,
|
| 5 |
+
"auto_mapping": null,
|
| 6 |
+
"base_model_name_or_path": "Qwen/Qwen3.5-9B",
|
| 7 |
+
"bias": "none",
|
| 8 |
+
"corda_config": null,
|
| 9 |
+
"ensure_weight_tying": false,
|
| 10 |
+
"eva_config": null,
|
| 11 |
+
"exclude_modules": null,
|
| 12 |
+
"fan_in_fan_out": false,
|
| 13 |
+
"inference_mode": true,
|
| 14 |
+
"init_lora_weights": true,
|
| 15 |
+
"layer_replication": null,
|
| 16 |
+
"layers_pattern": null,
|
| 17 |
+
"layers_to_transform": null,
|
| 18 |
+
"loftq_config": {},
|
| 19 |
+
"lora_alpha": 32,
|
| 20 |
+
"lora_bias": false,
|
| 21 |
+
"lora_dropout": 0.0,
|
| 22 |
+
"megatron_config": null,
|
| 23 |
+
"megatron_core": "megatron.core",
|
| 24 |
+
"modules_to_save": null,
|
| 25 |
+
"peft_type": "LORA",
|
| 26 |
+
"peft_version": "0.18.1",
|
| 27 |
+
"qalora_group_size": 16,
|
| 28 |
+
"r": 16,
|
| 29 |
+
"rank_pattern": {},
|
| 30 |
+
"revision": null,
|
| 31 |
+
"target_modules": [
|
| 32 |
+
"in_proj_qkv",
|
| 33 |
+
"q_proj",
|
| 34 |
+
"v_proj"
|
| 35 |
+
],
|
| 36 |
+
"target_parameters": null,
|
| 37 |
+
"task_type": "CAUSAL_LM",
|
| 38 |
+
"trainable_token_indices": null,
|
| 39 |
+
"use_dora": false,
|
| 40 |
+
"use_qalora": false,
|
| 41 |
+
"use_rslora": false
|
| 42 |
+
}
|
adapter_model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:0261aa5f75e7966692383136ec7d5ac7fc9ab9caaeb94483ceba5bcbda932823
|
| 3 |
+
size 27799552
|
prompt_parity.json
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cases": 1368,
|
| 3 |
+
"exact_training_prompt_parity": true,
|
| 4 |
+
"helper_sha256": "c11b9a8d6f74fec142a4568b50614ff574f9e2f1211e6260a7ddc0a15dcb256d"
|
| 5 |
+
}
|
quantum.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Generate bounded circuit-to-Python candidates. This module never executes them."""
|
| 2 |
+
|
| 3 |
+
import json
|
| 4 |
+
import math
|
| 5 |
+
|
| 6 |
+
import torch
|
| 7 |
+
from peft import PeftModel
|
| 8 |
+
from transformers import AutoTokenizer,Qwen3_5ForConditionalGeneration
|
| 9 |
+
|
| 10 |
+
BASE="Qwen/Qwen3.5-9B"
|
| 11 |
+
BASE_REVISION="c202236235762e1c871ad0ccb60c8ee5ba337b9a"
|
| 12 |
+
ADAPTER="itsalissonsilva/QuantumCoder-9B"
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def circuit_prompt(framework,qubits,operations):
|
| 16 |
+
if framework not in {"qiskit","pennylane","cirq"}:
|
| 17 |
+
raise ValueError("framework must be qiskit, pennylane or cirq")
|
| 18 |
+
if type(qubits) is not int or not 2<=qubits<=6:
|
| 19 |
+
raise ValueError("The measured scope is two through six qubits")
|
| 20 |
+
if not isinstance(operations,(list,tuple)) or not 1<=len(operations)<=24:
|
| 21 |
+
raise ValueError("Provide one through24 operations")
|
| 22 |
+
normalized=[]
|
| 23 |
+
for operation in operations:
|
| 24 |
+
if not isinstance(operation,(list,tuple)) or len(operation)!=3:
|
| 25 |
+
raise ValueError("Each operation must be [gate,qubit_indices,angle]")
|
| 26 |
+
gate,indices,angle=operation
|
| 27 |
+
if gate not in {"h","x","z","ry","rz","cx"}:
|
| 28 |
+
raise ValueError("Supported gates: h, x, z, ry, rz, cx")
|
| 29 |
+
if not isinstance(indices,(list,tuple)) or len(indices)!=(2 if gate=="cx" else 1):
|
| 30 |
+
raise ValueError("Gate arity mismatch")
|
| 31 |
+
if any(type(k) is not int or not 0<=k<qubits for k in indices) or len(set(indices))!=len(indices):
|
| 32 |
+
raise ValueError("Invalid/repeated qubit index")
|
| 33 |
+
if type(angle) not in (int,float) or not math.isfinite(angle):
|
| 34 |
+
raise ValueError("Angle must be a finite real number")
|
| 35 |
+
if gate not in {"ry","rz"} and angle!=0:
|
| 36 |
+
raise ValueError("Non-rotation gates require angle0")
|
| 37 |
+
normalized.append([gate,list(indices),float(angle)])
|
| 38 |
+
return [
|
| 39 |
+
dict(role="system",content="Return only Python source code using the requested quantum framework. No prose or markdown."),
|
| 40 |
+
dict(role="user",content=f"Write a {framework} program preparing this circuit from zero on {qubits} qubits. Operations [gate,qubits,angle]: {json.dumps(normalized)}. Angles are radians. Store the final statevector in a variable named state. Use little-endian qubit order."),
|
| 41 |
+
]
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
class QuantumCoder:
|
| 45 |
+
def __init__(self,adapter=ADAPTER,revision=None,subfolder=None):
|
| 46 |
+
if not torch.cuda.is_available():
|
| 47 |
+
raise RuntimeError("This measured inference configuration requires a CUDA GPU with enough memory for9B weights")
|
| 48 |
+
self.tokenizer=AutoTokenizer.from_pretrained(BASE,revision=BASE_REVISION)
|
| 49 |
+
self.tokenizer.padding_side="left"
|
| 50 |
+
dtype=torch.bfloat16 if torch.cuda.is_bf16_supported() else torch.float16
|
| 51 |
+
base=Qwen3_5ForConditionalGeneration.from_pretrained(BASE,revision=BASE_REVISION,dtype=dtype,
|
| 52 |
+
device_map="cuda",attn_implementation="sdpa")
|
| 53 |
+
kwargs=dict(revision=revision)
|
| 54 |
+
if subfolder is not None:
|
| 55 |
+
kwargs["subfolder"]=subfolder
|
| 56 |
+
self.model=PeftModel.from_pretrained(base,adapter,**kwargs).eval()
|
| 57 |
+
|
| 58 |
+
@torch.no_grad()
|
| 59 |
+
def generate(self,circuits):
|
| 60 |
+
"""Return program/token metadata for dictionaries with framework/qubits/operations.
|
| 61 |
+
|
| 62 |
+
Programs are fallible text, including possible unsupported APIs. For
|
| 63 |
+
measured execution use the separately provided isolated Linux evaluator.
|
| 64 |
+
"""
|
| 65 |
+
prompts=[]
|
| 66 |
+
for circuit in circuits:
|
| 67 |
+
messages=circuit_prompt(circuit["framework"],circuit["qubits"],circuit["operations"])
|
| 68 |
+
text=self.tokenizer.apply_chat_template(messages,tokenize=False,add_generation_prompt=True,enable_thinking=False)
|
| 69 |
+
if len(self.tokenizer.encode(text))>2048:
|
| 70 |
+
raise ValueError("Prompt exceeds the measured2048-token bound; no truncation applied")
|
| 71 |
+
prompts.append(text)
|
| 72 |
+
results=[]
|
| 73 |
+
eos=self.model.generation_config.eos_token_id
|
| 74 |
+
eos=set(eos if isinstance(eos,list) else [eos])
|
| 75 |
+
for begin in range(0,len(prompts),8):
|
| 76 |
+
inputs=self.tokenizer(prompts[begin:begin+8],padding=True,return_tensors="pt").to("cuda")
|
| 77 |
+
generated=self.model.generate(**inputs,max_new_tokens=768,do_sample=False,
|
| 78 |
+
pad_token_id=self.tokenizer.pad_token_id)
|
| 79 |
+
for tokens in generated[:,inputs["input_ids"].shape[1]:]:
|
| 80 |
+
ids=tokens.tolist();stop=next((i for i,t in enumerate(ids) if t in eos),None)
|
| 81 |
+
used=ids if stop is None else ids[:stop+1]
|
| 82 |
+
results.append(dict(program=self.tokenizer.decode(used,skip_special_tokens=True),generated_tokens=len(used),
|
| 83 |
+
eos_observed=stop is not None,at_token_cap=stop is None and len(used)>=768))
|
| 84 |
+
return results
|
quantum_sandbox_v2.py
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""V2 restricted quantum executor; v1 remains frozen in quantum_sandbox.py.
|
| 2 |
+
|
| 3 |
+
AST screening is combined with nobody UID, cleared environment, process/resource
|
| 4 |
+
limits and seccomp denial of filesystem opens, networking and process execution.
|
| 5 |
+
Libraries are imported/warmed in the parent before any untrusted code runs.
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import ast
|
| 9 |
+
import contextlib
|
| 10 |
+
import ctypes
|
| 11 |
+
import ctypes.util
|
| 12 |
+
import errno
|
| 13 |
+
import importlib
|
| 14 |
+
import io
|
| 15 |
+
import multiprocessing as mp
|
| 16 |
+
import os
|
| 17 |
+
import resource
|
| 18 |
+
|
| 19 |
+
for variable in ["OPENBLAS_NUM_THREADS", "OMP_NUM_THREADS", "MKL_NUM_THREADS"]:
|
| 20 |
+
os.environ[variable] = "1"
|
| 21 |
+
|
| 22 |
+
import numpy as np
|
| 23 |
+
|
| 24 |
+
MODULES = {
|
| 25 |
+
"numpy",
|
| 26 |
+
"numpy.linalg",
|
| 27 |
+
"math",
|
| 28 |
+
"cmath",
|
| 29 |
+
"qiskit",
|
| 30 |
+
"qiskit.quantum_info",
|
| 31 |
+
"pennylane",
|
| 32 |
+
"cirq",
|
| 33 |
+
}
|
| 34 |
+
ATTRIBUTES = set(
|
| 35 |
+
"array asarray zeros ones eye pi sqrt exp sin cos conj conjugate transpose reshape flatten ravel squeeze astype complex64 complex128 float32 float64 norm kron real imag T shape size data QuantumCircuit Statevector from_instruction h x y z ry rx rz cx cz swap s sdg t tdg sx barrier append device qnode state RY RX RZ Rot PhaseShift Identity PauliX PauliY PauliZ Hadamard CNOT CZ SWAP LineQubit range Circuit Simulator simulate final_state_vector H X Y Z CXPowGate ZPowGate XPowGate HPowGate controlled on inverse quantum_info".split()
|
| 36 |
+
)
|
| 37 |
+
# Documented Cirq gate aliases, independent of any v2 model outputs. They were
|
| 38 |
+
# absent from v1's conservative supported API. No isolation rule is relaxed.
|
| 39 |
+
ATTRIBUTES.update({"CX", "Rx", "Ry", "Rz"})
|
| 40 |
+
BUILTINS = {
|
| 41 |
+
"range": lambda *a: bounded_range(*a),
|
| 42 |
+
"enumerate": enumerate,
|
| 43 |
+
"zip": zip,
|
| 44 |
+
"len": len,
|
| 45 |
+
"list": list,
|
| 46 |
+
"tuple": tuple,
|
| 47 |
+
"float": float,
|
| 48 |
+
"int": int,
|
| 49 |
+
"complex": complex,
|
| 50 |
+
"print": print,
|
| 51 |
+
"abs": abs,
|
| 52 |
+
"sum": sum,
|
| 53 |
+
"min": min,
|
| 54 |
+
"max": max,
|
| 55 |
+
"reversed": reversed,
|
| 56 |
+
}
|
| 57 |
+
FORBIDDEN = (
|
| 58 |
+
ast.ClassDef,
|
| 59 |
+
ast.AsyncFunctionDef,
|
| 60 |
+
ast.Await,
|
| 61 |
+
ast.While,
|
| 62 |
+
ast.Try,
|
| 63 |
+
ast.With,
|
| 64 |
+
ast.AsyncWith,
|
| 65 |
+
ast.Raise,
|
| 66 |
+
ast.Delete,
|
| 67 |
+
ast.Global,
|
| 68 |
+
ast.Nonlocal,
|
| 69 |
+
ast.Lambda,
|
| 70 |
+
ast.Yield,
|
| 71 |
+
ast.YieldFrom,
|
| 72 |
+
ast.Match,
|
| 73 |
+
)
|
| 74 |
+
LIB = None
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
def bounded_range(*args):
|
| 78 |
+
value = range(*args)
|
| 79 |
+
if len(value) > 1024:
|
| 80 |
+
raise ValueError("range limit")
|
| 81 |
+
return value
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def screen(program):
|
| 85 |
+
if len(program) > 25000:
|
| 86 |
+
raise ValueError("program length limit")
|
| 87 |
+
tree = ast.parse(program)
|
| 88 |
+
if sum(1 for _ in ast.walk(tree)) > 6000:
|
| 89 |
+
raise ValueError("AST node limit")
|
| 90 |
+
for node in ast.walk(tree):
|
| 91 |
+
if isinstance(node, FORBIDDEN):
|
| 92 |
+
raise ValueError("unsupported syntax: " + type(node).__name__)
|
| 93 |
+
if isinstance(node, ast.Name) and (
|
| 94 |
+
node.id.startswith("_")
|
| 95 |
+
or node.id
|
| 96 |
+
in {
|
| 97 |
+
"eval",
|
| 98 |
+
"exec",
|
| 99 |
+
"compile",
|
| 100 |
+
"open",
|
| 101 |
+
"getattr",
|
| 102 |
+
"setattr",
|
| 103 |
+
"globals",
|
| 104 |
+
"locals",
|
| 105 |
+
"vars",
|
| 106 |
+
"type",
|
| 107 |
+
"object",
|
| 108 |
+
"input",
|
| 109 |
+
"help",
|
| 110 |
+
"breakpoint",
|
| 111 |
+
}
|
| 112 |
+
):
|
| 113 |
+
raise ValueError("forbidden name")
|
| 114 |
+
if isinstance(node, ast.Attribute) and node.attr not in ATTRIBUTES:
|
| 115 |
+
raise ValueError("unsupported attribute: " + node.attr)
|
| 116 |
+
if isinstance(node, ast.Import):
|
| 117 |
+
if any(a.name not in MODULES or (a.asname or "").startswith("_") for a in node.names):
|
| 118 |
+
raise ValueError("unsupported import")
|
| 119 |
+
if isinstance(node, ast.ImportFrom):
|
| 120 |
+
if (
|
| 121 |
+
node.level
|
| 122 |
+
or node.module not in MODULES
|
| 123 |
+
or any(
|
| 124 |
+
a.name not in ATTRIBUTES or (a.asname or "").startswith("_") for a in node.names
|
| 125 |
+
)
|
| 126 |
+
):
|
| 127 |
+
raise ValueError("unsupported from import")
|
| 128 |
+
if isinstance(node, ast.FunctionDef) and node.name.startswith("_"):
|
| 129 |
+
raise ValueError("forbidden function name")
|
| 130 |
+
return tree
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def initialize():
|
| 134 |
+
global LIB
|
| 135 |
+
assert os.name == "posix" and os.getuid() == 0, "Linux root parent required for UID isolation"
|
| 136 |
+
# Resolve/load seccomp before restricting filesystem access.
|
| 137 |
+
library = ctypes.util.find_library("seccomp")
|
| 138 |
+
assert library, "libseccomp is required; never fall back to AST-only execution"
|
| 139 |
+
LIB = ctypes.CDLL(library, use_errno=True)
|
| 140 |
+
LIB.seccomp_init.argtypes = [ctypes.c_uint32]
|
| 141 |
+
LIB.seccomp_init.restype = ctypes.c_void_p
|
| 142 |
+
LIB.seccomp_syscall_resolve_name.argtypes = [ctypes.c_char_p]
|
| 143 |
+
LIB.seccomp_syscall_resolve_name.restype = ctypes.c_int
|
| 144 |
+
LIB.seccomp_rule_add.argtypes = [ctypes.c_void_p, ctypes.c_uint32, ctypes.c_int, ctypes.c_uint]
|
| 145 |
+
LIB.seccomp_load.argtypes = [ctypes.c_void_p]
|
| 146 |
+
LIB.seccomp_release.argtypes = [ctypes.c_void_p]
|
| 147 |
+
from qiskit import QuantumCircuit
|
| 148 |
+
from qiskit.quantum_info import Statevector
|
| 149 |
+
import pennylane as qml
|
| 150 |
+
import cirq
|
| 151 |
+
|
| 152 |
+
qc = QuantumCircuit(2)
|
| 153 |
+
qc.h(0)
|
| 154 |
+
qc.ry(0.3, 1)
|
| 155 |
+
qc.rz(0.17, 0)
|
| 156 |
+
qc.x(0)
|
| 157 |
+
qc.z(1)
|
| 158 |
+
qc.cx(0, 1)
|
| 159 |
+
Statevector.from_instruction(qc)
|
| 160 |
+
device = qml.device("default.qubit", wires=[1, 0])
|
| 161 |
+
|
| 162 |
+
@qml.qnode(device)
|
| 163 |
+
def warm():
|
| 164 |
+
qml.Hadamard(0)
|
| 165 |
+
qml.RY(0.3, wires=1)
|
| 166 |
+
qml.RZ(0.17, wires=0)
|
| 167 |
+
qml.PauliX(0)
|
| 168 |
+
qml.PauliZ(1)
|
| 169 |
+
qml.CNOT(wires=[0, 1])
|
| 170 |
+
return qml.state()
|
| 171 |
+
|
| 172 |
+
warm()
|
| 173 |
+
qubits = cirq.LineQubit.range(2)
|
| 174 |
+
cirq.Simulator(dtype=np.complex128).simulate(
|
| 175 |
+
cirq.Circuit(
|
| 176 |
+
cirq.H(qubits[0]),
|
| 177 |
+
cirq.ry(0.3)(qubits[1]),
|
| 178 |
+
cirq.rz(0.17)(qubits[0]),
|
| 179 |
+
cirq.X(qubits[0]),
|
| 180 |
+
cirq.Z(qubits[1]),
|
| 181 |
+
cirq.CNOT(*qubits),
|
| 182 |
+
),
|
| 183 |
+
qubit_order=list(reversed(qubits)),
|
| 184 |
+
)
|
| 185 |
+
# Warm Python import machinery and serialization before fork/lockdown.
|
| 186 |
+
for module in MODULES:
|
| 187 |
+
importlib.import_module(module)
|
| 188 |
+
importlib.import_module("socket")
|
| 189 |
+
return dict(
|
| 190 |
+
qiskit=importlib.import_module("qiskit").__version__,
|
| 191 |
+
pennylane=qml.__version__,
|
| 192 |
+
cirq=cirq.__version__,
|
| 193 |
+
)
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
def lockdown():
|
| 197 |
+
os.environ.clear()
|
| 198 |
+
os.setgroups([])
|
| 199 |
+
os.setgid(65534)
|
| 200 |
+
os.setuid(65534)
|
| 201 |
+
resource.setrlimit(resource.RLIMIT_CPU, (15, 15))
|
| 202 |
+
# Native numeric runtimes reserve large virtual address spaces. Physical
|
| 203 |
+
# memory remains bounded by the HF CPU job container's memory allocation.
|
| 204 |
+
resource.setrlimit(resource.RLIMIT_AS, (16 * 1024**3, 16 * 1024**3))
|
| 205 |
+
resource.setrlimit(resource.RLIMIT_FSIZE, (0, 0))
|
| 206 |
+
resource.setrlimit(resource.RLIMIT_CORE, (0, 0))
|
| 207 |
+
resource.setrlimit(resource.RLIMIT_NPROC, (32, 32))
|
| 208 |
+
libc = ctypes.CDLL(None, use_errno=True)
|
| 209 |
+
assert libc.prctl(38, 1, 0, 0, 0) == 0, "PR_SET_NO_NEW_PRIVS failed"
|
| 210 |
+
policy = LIB.seccomp_init(0x7FFF0000) # SCMP_ACT_ALLOW
|
| 211 |
+
assert policy
|
| 212 |
+
deny = 0x00050000 | errno.EPERM # SCMP_ACT_ERRNO(EPERM)
|
| 213 |
+
for name in [
|
| 214 |
+
"open",
|
| 215 |
+
"openat",
|
| 216 |
+
"openat2",
|
| 217 |
+
"creat",
|
| 218 |
+
"socket",
|
| 219 |
+
"socketpair",
|
| 220 |
+
"connect",
|
| 221 |
+
"accept",
|
| 222 |
+
"accept4",
|
| 223 |
+
"bind",
|
| 224 |
+
"listen",
|
| 225 |
+
"sendto",
|
| 226 |
+
"sendmsg",
|
| 227 |
+
"execve",
|
| 228 |
+
"execveat",
|
| 229 |
+
"ptrace",
|
| 230 |
+
"process_vm_readv",
|
| 231 |
+
"process_vm_writev",
|
| 232 |
+
"mount",
|
| 233 |
+
"umount2",
|
| 234 |
+
"bpf",
|
| 235 |
+
"userfaultfd",
|
| 236 |
+
]:
|
| 237 |
+
syscall = LIB.seccomp_syscall_resolve_name(name.encode())
|
| 238 |
+
if syscall >= 0:
|
| 239 |
+
assert LIB.seccomp_rule_add(policy, deny, syscall, 0) == 0, name
|
| 240 |
+
assert LIB.seccomp_load(policy) == 0, "seccomp load failed"
|
| 241 |
+
LIB.seccomp_release(policy)
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
def safe_import(name, globals=None, locals=None, fromlist=(), level=0):
|
| 245 |
+
if name not in MODULES or level:
|
| 246 |
+
raise ImportError("module not allowed")
|
| 247 |
+
module = importlib.import_module(name)
|
| 248 |
+
return module if fromlist else importlib.import_module(name.split(".")[0])
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
def worker(program, qubits, connection, mode):
|
| 252 |
+
try:
|
| 253 |
+
lockdown()
|
| 254 |
+
if mode == "isolation_check":
|
| 255 |
+
import socket
|
| 256 |
+
|
| 257 |
+
file_blocked = network_blocked = False
|
| 258 |
+
try:
|
| 259 |
+
open("/etc/hostname").read()
|
| 260 |
+
except PermissionError:
|
| 261 |
+
file_blocked = True
|
| 262 |
+
try:
|
| 263 |
+
socket.socket()
|
| 264 |
+
except PermissionError:
|
| 265 |
+
network_blocked = True
|
| 266 |
+
connection.send(
|
| 267 |
+
dict(
|
| 268 |
+
file_opens_blocked=file_blocked,
|
| 269 |
+
network_blocked=network_blocked,
|
| 270 |
+
uid=os.getuid(),
|
| 271 |
+
environment_empty=not os.environ,
|
| 272 |
+
)
|
| 273 |
+
)
|
| 274 |
+
return
|
| 275 |
+
tree = screen(program)
|
| 276 |
+
safe = dict(BUILTINS, __import__=safe_import)
|
| 277 |
+
namespace = {"__builtins__": safe}
|
| 278 |
+
with contextlib.redirect_stdout(io.StringIO()), contextlib.redirect_stderr(io.StringIO()):
|
| 279 |
+
exec(compile(tree, "<restricted-quantum>", "exec"), namespace, namespace)
|
| 280 |
+
value = np.asarray(namespace["state"], dtype=np.complex128).reshape(-1)
|
| 281 |
+
assert value.shape == (2**qubits,) and np.isfinite(value).all()
|
| 282 |
+
connection.send(
|
| 283 |
+
dict(
|
| 284 |
+
status="executed",
|
| 285 |
+
real=value.real.tolist(),
|
| 286 |
+
imag=value.imag.tolist(),
|
| 287 |
+
norm=float(np.linalg.norm(value)),
|
| 288 |
+
)
|
| 289 |
+
)
|
| 290 |
+
except BaseException as error:
|
| 291 |
+
connection.send(
|
| 292 |
+
dict(status="rejected_or_error", error=type(error).__name__, detail=str(error)[:300])
|
| 293 |
+
)
|
| 294 |
+
finally:
|
| 295 |
+
connection.close()
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
def run(program, qubits, mode="program"):
|
| 299 |
+
assert 1 <= qubits <= 8
|
| 300 |
+
ctx = mp.get_context("fork")
|
| 301 |
+
receive, send = ctx.Pipe(duplex=False)
|
| 302 |
+
process = ctx.Process(target=worker, args=(program, qubits, send, mode))
|
| 303 |
+
process.start()
|
| 304 |
+
send.close()
|
| 305 |
+
if receive.poll(20):
|
| 306 |
+
try:
|
| 307 |
+
result = receive.recv()
|
| 308 |
+
except EOFError:
|
| 309 |
+
result = dict(status="worker_exit", exitcode=process.exitcode)
|
| 310 |
+
else:
|
| 311 |
+
result = dict(status="timeout")
|
| 312 |
+
process.join(1)
|
| 313 |
+
if process.is_alive():
|
| 314 |
+
process.kill()
|
| 315 |
+
process.join(2)
|
| 316 |
+
receive.close()
|
| 317 |
+
return result
|
release_audit.json
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"circuit_groups": 456,
|
| 3 |
+
"framework_views": 1368,
|
| 4 |
+
"cross_split_group_overlap": 0,
|
| 5 |
+
"train_holdout_exact_state_matches": 0,
|
| 6 |
+
"max_train_holdout_state_fidelity": 0.9991002699676015,
|
| 7 |
+
"state_match_tolerance": 1e-08,
|
| 8 |
+
"independent_execution_gate": true,
|
| 9 |
+
"saved_helper_all_passed": true,
|
| 10 |
+
"scope": "Exact zero-input-state duplicate check across matching dimensions; does not assert full unitary/process or semantic equivalence separation."
|
| 11 |
+
}
|
reproduce_execution.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Offline re-scoring of frozen programs; Linux/root/libseccomp are required.
|
| 2 |
+
|
| 3 |
+
Never replace the sandbox with direct exec. All generated programs run only in
|
| 4 |
+
its credential-cleared nobody workers with filesystem/network denial.
|
| 5 |
+
"""
|
| 6 |
+
import ast
|
| 7 |
+
import hashlib
|
| 8 |
+
import json
|
| 9 |
+
import re
|
| 10 |
+
from collections import defaultdict
|
| 11 |
+
from pathlib import Path
|
| 12 |
+
import numpy as np
|
| 13 |
+
import quantum_sandbox_v2 as sandbox
|
| 14 |
+
|
| 15 |
+
ROOT=Path(__file__).resolve().parent
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def score(program,row):
|
| 19 |
+
wrapped=re.fullmatch(r"\s*```(?:python)?\s*\n(.*?)\n```\s*",program,flags=re.S)
|
| 20 |
+
clean=wrapped.group(1) if wrapped else program
|
| 21 |
+
imports=set()
|
| 22 |
+
try:
|
| 23 |
+
for node in ast.walk(ast.parse(clean)):
|
| 24 |
+
if isinstance(node,ast.Import):imports.update(a.name.split(".")[0] for a in node.names)
|
| 25 |
+
elif isinstance(node,ast.ImportFrom):imports.add((node.module or "").split(".")[0])
|
| 26 |
+
except SyntaxError:
|
| 27 |
+
pass
|
| 28 |
+
result=sandbox.run(clean,row["qubits"])
|
| 29 |
+
passed=False
|
| 30 |
+
if result.get("status")=="executed":
|
| 31 |
+
actual=np.array(result["real"])+1j*np.array(result["imag"])
|
| 32 |
+
target=np.array(row["state_real"])+1j*np.array(row["state_imag"])
|
| 33 |
+
passed=abs(result["norm"]-1)<1e-6 and abs(np.vdot(target,actual))**2>1-1e-6 and row["framework"] in imports
|
| 34 |
+
return bool(passed)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def main():
|
| 38 |
+
frozen=json.loads((ROOT/"v2_execution/execution.json").read_text())
|
| 39 |
+
preflight=json.loads((ROOT/"v2_executor_preflight/preflight.json").read_text())
|
| 40 |
+
assert preflight["all_passed"] and len(preflight["reference_checks"])==1368
|
| 41 |
+
assert hashlib.sha256(Path(sandbox.__file__).read_bytes()).hexdigest()==frozen["executor_sha256"]==preflight["executor_sha256"]
|
| 42 |
+
file=ROOT/"curriculum_v2/rows.json"
|
| 43 |
+
assert hashlib.sha256(file.read_bytes()).hexdigest()==preflight["manifest"]["rows_sha256"]
|
| 44 |
+
rows={r["id"]:r for r in json.loads(file.read_text()) if r["split"]!="train"}
|
| 45 |
+
assert len(rows)==720
|
| 46 |
+
versions=sandbox.initialize()
|
| 47 |
+
assert versions==frozen["versions"]
|
| 48 |
+
assert sandbox.run("",1,mode="isolation_check")==preflight["isolation"]
|
| 49 |
+
for row in rows.values():
|
| 50 |
+
assert score(row["program"],row),"Reference failed; stop before scoring generated programs"
|
| 51 |
+
outputs=json.loads((ROOT/"curriculum_v2_run/generation_report.json").read_text())["conditions"]
|
| 52 |
+
totals=defaultdict(lambda:dict(n=0,passed=0))
|
| 53 |
+
for condition in ["base","adapted"]:
|
| 54 |
+
assert len(outputs[condition])==720 and {r["id"] for r in outputs[condition]}==set(rows)
|
| 55 |
+
for output in outputs[condition]:
|
| 56 |
+
row=rows[output["id"]];passed=score(output["program"],row)
|
| 57 |
+
for framework in ["all",row["framework"]]:
|
| 58 |
+
key=condition+"/"+row["split"]+"/"+framework
|
| 59 |
+
totals[key]["n"]+=1;totals[key]["passed"]+=passed
|
| 60 |
+
for key,value in totals.items():
|
| 61 |
+
condition,split,framework=key.split("/")
|
| 62 |
+
original=frozen["summary"][condition][split+"/"+framework]
|
| 63 |
+
assert value==dict(n=original["n"],passed=original["passed"]),(key,value,original)
|
| 64 |
+
result=dict(versions=versions,all_counts_reproduced=True,summary=dict(totals))
|
| 65 |
+
(ROOT/"reproduced_counts.json").write_text(json.dumps(result,indent=2)+"\n")
|
| 66 |
+
print(json.dumps(result,indent=2))
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
if __name__=="__main__":main()
|
requirements-evaluation.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
numpy==2.1.3
|
| 2 |
+
qiskit==2.2.3
|
| 3 |
+
pennylane==0.43.1
|
| 4 |
+
cirq-core==1.6.1
|
| 5 |
+
scipy==1.15.3
|
| 6 |
+
gast==0.6.0
|
| 7 |
+
astunparse==1.6.3
|
requirements-inference.txt
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
torch==2.10.0
|
| 2 |
+
torchvision==0.25.0
|
| 3 |
+
torchaudio==2.10.0
|
| 4 |
+
transformers==5.5.4
|
| 5 |
+
peft==0.18.1
|
| 6 |
+
accelerate==1.12.0
|
| 7 |
+
huggingface_hub==1.33.0
|
| 8 |
+
safetensors==0.5.3
|