@nm-lang/cli 0.5.0 → 0.7.0
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.
- package/README.md +215 -178
- package/bin/nm.mjs +2 -0
- package/bin/project-create.d.mts +27 -0
- package/bin/project-create.mjs +122 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +122 -26
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -2
- package/python/LICENSE.txt +57 -0
- package/python/NOTICE.txt +11 -0
- package/python/README.md +166 -61
- package/python/examples/magic.ipynb +98 -0
- package/python/nm_bridge.py +64 -4
- package/python/nm_jupyter/__init__.py +20 -0
- package/python/nm_jupyter/extension.py +135 -0
- package/python/pyproject.toml +21 -0
package/dist/version.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export type NMLanguageReleaseChange = {
|
|
|
29
29
|
};
|
|
30
30
|
export declare const nmVersionManifest: {
|
|
31
31
|
readonly languageVersion: "0.2.0";
|
|
32
|
-
readonly packageVersion: "0.
|
|
32
|
+
readonly packageVersion: "0.7.0";
|
|
33
33
|
readonly irVersion: "0.1";
|
|
34
34
|
readonly qasm3SidecarVersion: "0.3";
|
|
35
35
|
readonly learningPackageVersion: "0.1";
|
package/dist/version.js
CHANGED
|
@@ -2,7 +2,7 @@ export const NM_LANGUAGE_PREVIEW_READINESS_FORMAT = "nm-language-preview-readine
|
|
|
2
2
|
export const NM_LANGUAGE_PREVIEW_READINESS_VERSION = "0.1";
|
|
3
3
|
export const nmVersionManifest = {
|
|
4
4
|
languageVersion: "0.2.0",
|
|
5
|
-
packageVersion: "0.
|
|
5
|
+
packageVersion: "0.7.0",
|
|
6
6
|
irVersion: "0.1",
|
|
7
7
|
qasm3SidecarVersion: "0.3",
|
|
8
8
|
learningPackageVersion: "0.1",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nm-lang/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Command-line tools for formatting, linting, testing, workspace snapshots, execution, and exports for N/M quantum programs.",
|
|
6
6
|
"repository": {
|
|
@@ -36,6 +36,10 @@
|
|
|
36
36
|
".": {
|
|
37
37
|
"types": "./dist/index.d.ts",
|
|
38
38
|
"import": "./dist/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./project-create": {
|
|
41
|
+
"types": "./bin/project-create.d.mts",
|
|
42
|
+
"import": "./bin/project-create.mjs"
|
|
39
43
|
}
|
|
40
44
|
},
|
|
41
45
|
"bin": {
|
|
@@ -49,7 +53,7 @@
|
|
|
49
53
|
"NOTICE.txt"
|
|
50
54
|
],
|
|
51
55
|
"dependencies": {
|
|
52
|
-
"@nm-lang/core": "0.
|
|
56
|
+
"@nm-lang/core": "0.7.0",
|
|
53
57
|
"jiti": "^2.7.0"
|
|
54
58
|
},
|
|
55
59
|
"scripts": {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
QuantumSoftware N/M npm Packages — Free Use License
|
|
2
|
+
Version 1.0, 5 October 2026
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2026 QuantumSoftware.tech contributors. All rights reserved.
|
|
5
|
+
|
|
6
|
+
1. Scope
|
|
7
|
+
This license covers QuantumSoftware-owned code and assets in the official
|
|
8
|
+
@nm-lang/core, @nm-lang/cli, @nm-lang/language-server and @nm-lang/mcp npm
|
|
9
|
+
packages. It does not license the rest of the repository or the separately
|
|
10
|
+
distributed VS Code extension. Third-party components remain subject to their
|
|
11
|
+
respective licenses; their notices and permissions take precedence for those
|
|
12
|
+
components.
|
|
13
|
+
|
|
14
|
+
2. Free use
|
|
15
|
+
You may download, install and use these official packages without charge for
|
|
16
|
+
personal, educational and commercial purposes, import their APIs into your own
|
|
17
|
+
programs, and make backup copies for your own use. QuantumSoftware authorizes
|
|
18
|
+
distribution of its official packages through the nm-lang organization on the
|
|
19
|
+
npm registry, including the registry's normal delivery and package-manager
|
|
20
|
+
installation and caching mechanisms.
|
|
21
|
+
|
|
22
|
+
3. Reserved rights
|
|
23
|
+
This is not an open-source license. Except for the permissions above, rights
|
|
24
|
+
to QuantumSoftware-owned code and assets are reserved. Modification,
|
|
25
|
+
redistribution, sublicensing, sale or publication of that code or those assets
|
|
26
|
+
requires separate permission from the rights holders, unless applicable law
|
|
27
|
+
provides otherwise. Do not remove copyright or license notices. These
|
|
28
|
+
restrictions do not override rights granted by any third-party license.
|
|
29
|
+
|
|
30
|
+
4. Your programs
|
|
31
|
+
This license imposes no restrictions on N/M programs you write, their source
|
|
32
|
+
code, or simulation results produced using these packages. It does not
|
|
33
|
+
transfer ownership of your work to QuantumSoftware. This clause does not grant
|
|
34
|
+
additional redistribution rights to QuantumSoftware-owned runtime code bundled
|
|
35
|
+
with your application; those rights are governed by sections 2 and 3.
|
|
36
|
+
|
|
37
|
+
5. No warranty
|
|
38
|
+
THE PACKAGES ARE PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, TO THE
|
|
39
|
+
EXTENT PERMITTED BY APPLICABLE LAW. TO THAT SAME EXTENT, THE RIGHTS HOLDERS
|
|
40
|
+
ARE NOT LIABLE FOR DAMAGES ARISING FROM USE OF THE PACKAGES. RIGHTS THAT
|
|
41
|
+
CANNOT BE EXCLUDED UNDER APPLICABLE LAW ARE NOT AFFECTED.
|
|
42
|
+
|
|
43
|
+
6. Permission requests
|
|
44
|
+
For additional permissions, contact the publisher through:
|
|
45
|
+
https://quantumsoftware.tech/en/#contact
|
|
46
|
+
|
|
47
|
+
Türkçe açıklama
|
|
48
|
+
Resmî dört npm paketi kişisel, eğitim ve ticari amaçlarla ücretsiz kurulup
|
|
49
|
+
kullanılabilir; API'leri kendi programlarınızdan çağırabilir ve kendi kullanımınız
|
|
50
|
+
için yedek kopya alabilirsiniz. Bu bir açık kaynak lisansı değildir.
|
|
51
|
+
QuantumSoftware'a ait kod ve varlıkları değiştirmek veya yeniden dağıtmak için
|
|
52
|
+
ayrıca izin gerekir. Paketleri indirilebilir kılmak, kaynak kodu üzerinde açık
|
|
53
|
+
kaynak hakları vermez. Üçüncü taraf lisanslarının ve yürürlükteki hukukun verdiği
|
|
54
|
+
haklar korunur. Yazdığınız N/M programları ve ürettiğiniz sonuçların mülkiyeti
|
|
55
|
+
size aittir. Uygulamanızla birlikte dağıtacağınız QuantumSoftware çalışma zamanı
|
|
56
|
+
dosyaları için yukarıdaki izin ve kısıtlamalar geçerlidir. Yukarıdaki İngilizce
|
|
57
|
+
metin lisansın koşullarını belirler.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
QuantumSoftware N/M package notices
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 QuantumSoftware.tech contributors. All rights reserved.
|
|
4
|
+
QuantumSoftware-owned code is licensed under LICENSE.txt.
|
|
5
|
+
|
|
6
|
+
Runtime dependencies listed in package.json are installed separately by npm.
|
|
7
|
+
Their own licenses and notices remain applicable. The QuantumSoftware license
|
|
8
|
+
does not restrict the rights granted for those third-party components.
|
|
9
|
+
|
|
10
|
+
jiti 2.x is a separately installed runtime dependency licensed under MIT.
|
|
11
|
+
Its original LICENSE is included in the jiti package.
|
package/python/README.md
CHANGED
|
@@ -1,69 +1,174 @@
|
|
|
1
|
-
# N/M Python/Jupyter
|
|
1
|
+
# N/M Python/Jupyter adapter / adaptörü
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
This source tree adds a **local development wheel**, `nm-jupyter-adapter==0.0.0.dev0`,
|
|
4
|
+
over the stdlib bridge included in `@nm-lang/cli`. This is not a PyPI release or
|
|
5
|
+
an npm/VSIX version change. Install Node and a trusted N/M CLI separately; the
|
|
6
|
+
wheel contains only the adapter, optional extension and usage/license metadata.
|
|
7
|
+
Source-code rights remain reserved under the unchanged LICENSE.txt and NOTICE.txt.
|
|
8
|
+
|
|
9
|
+
Bu kaynak ağacı, `@nm-lang/cli` içindeki standart kütüphane köprüsünü
|
|
10
|
+
`nm-jupyter-adapter==0.0.0.dev0` **yerel geliştirme wheel'i** olarak kurmayı sağlar.
|
|
11
|
+
PyPI yayını veya npm/VSIX sürüm değişikliği değildir. Node ve güvenilir N/M CLI
|
|
12
|
+
ayrıca kurulur. Wheel yalnız adaptörü, isteğe bağlı uzantıyı ve kullanım/lisans
|
|
13
|
+
metaverisini içerir. LICENSE.txt ve NOTICE.txt değişmeden korunur; kaynak hakları saklıdır.
|
|
14
|
+
|
|
15
|
+
## Installation / Kurulum
|
|
16
|
+
|
|
17
|
+
From the repository root, create disposable environments; nothing is installed
|
|
18
|
+
into global Python. / Depo kökünde geçici ortamlar oluşturun; global Python'a
|
|
19
|
+
kurulum yapılmaz.
|
|
20
|
+
|
|
21
|
+
```powershell
|
|
22
|
+
py -m venv .qa/python-adapter/tools
|
|
23
|
+
.qa/python-adapter/tools/Scripts/python.exe -m pip install -r tests/python/requirements-adapter-build.txt
|
|
24
|
+
.qa/python-adapter/tools/Scripts/python.exe -B scripts/build-nm-python-adapter.py
|
|
25
|
+
py -m venv .qa/python-adapter/notebook
|
|
26
|
+
.qa/python-adapter/notebook/Scripts/python.exe -m pip install --no-index --no-deps .qa/python-adapter/dist/nm_jupyter_adapter-0.0.0.dev0-py3-none-any.whl
|
|
27
|
+
# Optional IPython/Jupyter; Python 3.11+ / İsteğe bağlı IPython/Jupyter; Python 3.11+
|
|
28
|
+
.qa/python-adapter/notebook/Scripts/python.exe -m pip install -r tests/python/requirements-notebook.txt
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
On Unix, use `python3` and `bin/python` instead of `py` and `Scripts/python.exe`.
|
|
32
|
+
The stdlib adapter and legacy imports support Python 3.10+. The pinned optional
|
|
33
|
+
IPython 9.17.1 notebook environment requires Python 3.11+; installing the
|
|
34
|
+
`notebook` extra on Python 3.10 does not install IPython. No global kernel is registered.
|
|
35
|
+
Unix'te `python3` ve `bin/python` kullanın. Standart kütüphane adaptörü Python
|
|
36
|
+
3.10+ destekler; sabitlenmiş IPython 9.17.1 notebook ortamı Python 3.11+ gerektirir.
|
|
37
|
+
Python 3.10'da `notebook` ek bağımlılığı IPython kurmaz. Global kernel kaydı yapılmaz.
|
|
38
|
+
|
|
39
|
+
## Explicit CLI selection / Açık CLI seçimi
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from pathlib import Path
|
|
43
|
+
from nm_bridge import NMClient, NMResult # Legacy import stays valid / Eski import korunur.
|
|
44
|
+
|
|
45
|
+
# Select an existing trusted CLI script; replace this example absolute path.
|
|
46
|
+
# Mevcut güvenilir CLI dosyanızı seçin; örnek mutlak yolu değiştirin.
|
|
47
|
+
client = NMClient(cli_path=Path("C:/trusted/nm-cli/bin/nm.mjs"), locale="tr",
|
|
48
|
+
experimental=("hamiltonianEvolution", "measurementGrouping"), timeout=30)
|
|
49
|
+
record = client.train(source, options={"steps": 2, "targetAccuracy": {"absoluteError": 0.5}})
|
|
50
|
+
record # Escaped Jupyter table / Kaçışlanmış Jupyter tablosu
|
|
51
|
+
restored = NMResult.from_json(record.to_json()) # Data only / Yalnız veri
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Standalone wheel clients require `cli_path=` or the existing trusted `command=`
|
|
55
|
+
argument sequence. `cli_path` must resolve to an existing absolute file and is
|
|
56
|
+
mutually exclusive with `command`. No PATH/cwd search for the N/M CLI occurs.
|
|
57
|
+
Inside the original npm `python/` layout, `NMClient()` still selects the adjacent
|
|
58
|
+
`../bin/nm.mjs`; adding that `python/` directory to `sys.path` remains supported.
|
|
59
|
+
`from nm_jupyter import NMClient, NMResult` exposes the same classes.
|
|
60
|
+
The npm default verifies the physical module origin, the parent `package.json`
|
|
61
|
+
identity (`@nm-lang/cli` and its `nm` entry), and local Python distribution
|
|
62
|
+
metadata. Wheel/RECORD ownership or incomplete/ambiguous markers require explicit
|
|
63
|
+
CLI selection even when the wheel target directory happens to be named `python`.
|
|
64
|
+
|
|
65
|
+
Bağımsız wheel, açık `cli_path=` veya mevcut güvenilir `command=` dizisi gerektirir.
|
|
66
|
+
`cli_path`, mevcut bir mutlak dosyaya çözülmelidir ve `command` ile birlikte
|
|
67
|
+
verilemez. N/M CLI için PATH/çalışma dizini araması yapılmaz. npm paketinin özgün
|
|
68
|
+
`python/` diziliminde `NMClient()` komşu `../bin/nm.mjs` dosyasını kullanmaya devam
|
|
69
|
+
eder; bu dizini `sys.path` içine eklemek desteklenir. `nm_jupyter` aynı sınıfları dışa aktarır.
|
|
70
|
+
npm varsayılanı gerçek modül konumunu, üst `package.json` kimliğini ve yerel Python
|
|
71
|
+
dağıtım metaverisini doğrular. Wheel/RECORD sahipliği veya eksik/belirsiz işaretler,
|
|
72
|
+
kurulum hedefinin adı `python` olsa bile açık CLI seçimi gerektirir.
|
|
8
73
|
|
|
9
74
|
Default Node lookup accepts only absolute PATH directories outside the working
|
|
10
|
-
directory and resolves an absolute executable
|
|
11
|
-
|
|
12
|
-
`NM-PY-011`; no bare-name fallback is used.
|
|
13
|
-
|
|
14
|
-
|
|
75
|
+
directory and resolves an absolute executable. Empty/relative entries and cwd
|
|
76
|
+
aliases are skipped on every supported Python version. Missing Node raises
|
|
77
|
+
`NM-PY-011`; no bare-name fallback is used. Missing/invalid CLI selection raises
|
|
78
|
+
`NM-PY-012`. Explicit `command=` remains trusted caller input, unchanged and passed
|
|
79
|
+
with `shell=False`; trust its executable and arguments yourself.
|
|
80
|
+
|
|
15
81
|
Varsayılan Node araması yalnız çalışma dizini dışındaki mutlak PATH dizinlerini
|
|
16
|
-
kullanır
|
|
17
|
-
bulunamazsa `NM-PY-011
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
Python 3.10/3.11 uses a stdlib Win32 compatibility path; only the direct process
|
|
23
|
-
is terminated, so this is not a process-tree sandbox.
|
|
24
|
-
Giriş/çıkış ve EOF aynı süre sınırına bağlıdır; çağrı sonrası I/O iş parçacığı
|
|
25
|
-
kalmaz. Özel başlatıcının alt süreci boruyu açık tutarsa eksik sonuç kabul edilmez.
|
|
26
|
-
Windows Python 3.10/3.11 desteklenir; yalnız doğrudan başlatılan süreç sonlandırılır.
|
|
82
|
+
kullanır. Boş/göreli girdiler ve çalışma dizinine çözülen yollar atlanır. Node
|
|
83
|
+
bulunamazsa `NM-PY-011`, CLI seçimi eksik/geçersizse `NM-PY-012` verilir.
|
|
84
|
+
Yalın program adı fallback'i yoktur. Açık `command=` değiştirilmeden `shell=False`
|
|
85
|
+
ile kullanılır; program ve argümanların güvenilirliğini çağıran sağlar.
|
|
86
|
+
|
|
87
|
+
## Optional explicit cells / İsteğe bağlı açık hücreler
|
|
27
88
|
|
|
28
89
|
```python
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
90
|
+
%load_ext nm_jupyter
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
%%nm --client client --check
|
|
95
|
+
module notebook_check;
|
|
96
|
+
fn main(){let q=qreg[1];H(q[0]);return q;}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Use `--run` for simulation or `--train` for training; exactly one mode and an
|
|
100
|
+
existing Python variable naming an explicitly configured `NMClient` are required
|
|
101
|
+
on every cell. Names are direct identifier lookups, not Python expressions.
|
|
102
|
+
Import/load/save/display never invokes a client. Execution occurs only when you
|
|
103
|
+
explicitly run a cell or call the Python API. `%unload_ext nm_jupyter` removes the magic.
|
|
104
|
+
|
|
105
|
+
Simülasyon için `--run`, eğitim için `--train` seçin. Her hücre tam bir mod ve
|
|
106
|
+
açıkça yapılandırılmış bir `NMClient` Python değişkeni gerektirir. Adlar doğrudan
|
|
107
|
+
aranır; Python ifadesi değildir. Import/uzantı yükleme/kaydetme/gösterim CLI çağırmaz.
|
|
108
|
+
Yürütme yalnız hücreyi veya Python API'yi açıkça çalıştırınca olur.
|
|
109
|
+
|
|
110
|
+
```text
|
|
111
|
+
%%nm --client client --train --steps 2 --learning-rate 0.17 --optimizer adam --objective minimize --objective-target energy --gradient-method parameter-shift --measurement-allocation adaptive --pilot-shots 8 --absolute-error 1e-9
|
|
112
|
+
module notebook_training;
|
|
113
|
+
@seed(27);
|
|
114
|
+
@shots_budget(4096);
|
|
115
|
+
param theta:Angle=0;
|
|
116
|
+
fn main(){
|
|
117
|
+
let q=qreg[1];
|
|
118
|
+
observable Hamiltonian=theta*X(q[0])+0.25*theta*I;
|
|
119
|
+
evolve Hamiltonian for 0.4 steps 1 order 1 on q;
|
|
120
|
+
let energy=expect Y(q[0])+0.5*Z(q[0]);
|
|
121
|
+
return q;
|
|
122
|
+
}
|
|
34
123
|
```
|
|
35
124
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
`
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
125
|
+
The cell returns `NMResult`; in the next Python cell, use `record = _` to retain it.
|
|
126
|
+
Options omitted from the magic remain absent, preserving source training defaults.
|
|
127
|
+
Training flags are accepted only with `--train`. Steps: 1–100; learning rate:
|
|
128
|
+
finite `(0,5]`; adaptive pilot shots: 2–32; absolute error: finite `(0,1000000]`.
|
|
129
|
+
No shot override or feature grant is accepted in the magic. See the full guide
|
|
130
|
+
for the enum choices. Nested SPSA/QNG tuning remains in `NMClient.train(options=...)`.
|
|
131
|
+
|
|
132
|
+
Hücre `NMResult` döndürür; sonraki Python hücresinde `record = _` ile saklayın.
|
|
133
|
+
Verilmeyen eğitim seçenekleri eklenmez; kaynağın varsayılanları korunur. Eğitim
|
|
134
|
+
bayrakları yalnız `--train` ile geçerlidir. Adım 1–100, öğrenme oranı sonlu `(0,5]`,
|
|
135
|
+
adaptif pilot ölçüm 2–32, mutlak hata sonlu `(0,1000000]` olur. Hücreye ölçüm sayısı
|
|
136
|
+
override'ı veya özellik izni eklenmez. İç SPSA/QNG ayarları Python API'sinde kalır.
|
|
137
|
+
|
|
138
|
+
## Limits and records / Sınırlar ve kayıtlar
|
|
139
|
+
|
|
140
|
+
The bridge v1 limits remain: 32 KiB source, 256 KiB request, 4 MiB response,
|
|
141
|
+
64 KiB stderr, request/result JSON depth 32/64, 14 qubits, 8 training parameters,
|
|
142
|
+
100 steps, one inclusive shot budget up to 4096 and a 0.1–60 second deadline.
|
|
143
|
+
Pipe I/O and EOF share the deadline; no I/O threads survive a call. Windows
|
|
144
|
+
Python 3.10/3.11 retains the stdlib Win32 compatibility path. Cancellation kills
|
|
145
|
+
the direct process and yields `NM-PY-009`; this is not a process-tree sandbox.
|
|
146
|
+
|
|
147
|
+
Köprü v1 sınırları korunur: 32 KiB kaynak, 256 KiB istek, 4 MiB yanıt, 64 KiB stderr,
|
|
148
|
+
32/64 JSON derinliği, 14 kübit, 8 parametre, 100 adım, pilotlar dahil en fazla
|
|
149
|
+
4096 ölçüm ve 0.1–60 saniye süre. Giriş/çıkış ve EOF aynı süreye bağlıdır; I/O iş
|
|
150
|
+
parçacığı kalmaz. Windows Python 3.10/3.11 desteği korunur. İptal doğrudan süreci
|
|
151
|
+
sonlandırıp `NM-PY-009` verir; süreç ağacı sandbox'ı değildir.
|
|
152
|
+
|
|
153
|
+
Saved JSON is data and grants no permission. Replay with
|
|
154
|
+
`client.execute(restored.request)` needs independent caller permissions. Compact
|
|
155
|
+
saving preserves wire number spellings; pretty output exceeding 4 MiB is rejected.
|
|
156
|
+
Source snapshots are not checkpoints. Confidence and precision targets do not
|
|
157
|
+
certify convergence, an optimum or hardware accuracy. Required-shot estimates
|
|
158
|
+
are informational final-cost estimates, exclude pilots and never take extra shots.
|
|
159
|
+
Source, options, shot accounting and confidence assumptions remain in the record;
|
|
160
|
+
all user text in the rich table is HTML escaped.
|
|
161
|
+
|
|
162
|
+
Kaydedilmiş JSON veridir; izin vermez. Yeniden yürütme bağımsız çağıran yetkisi
|
|
163
|
+
gerektirir. Kompakt kayıt özgün sayı gösterimini korur; 4 MiB'ı aşan girintili çıktı
|
|
164
|
+
reddedilir. Kaynak checkpoint, hassasiyet hedefi yakınsama/optimum/donanım belgesi
|
|
165
|
+
değildir. Ölçüm tahmini bilgi amaçlıdır; pilotları içermez ve ek ölçüm almaz.
|
|
166
|
+
Özgün kaynak, seçenekler ve ölçüm/güven varsayımları kayıtta kalır; tablo metni kaçışlanır.
|
|
167
|
+
|
|
168
|
+
`examples/magic.ipynb` is an unexecuted TR/EN explicit-cell example. It is included
|
|
169
|
+
with the npm source layout, not bundled into the minimal wheel. The existing
|
|
170
|
+
`examples/training.ipynb` and legacy Python bridge API remain usable.
|
|
171
|
+
|
|
172
|
+
Full guide / Tam rehber: `docs/NM_PYTHON_JUPYTER_ADAPTER_GUIDE.md`.
|
|
173
|
+
Protocol and precision details / Protokol ve hassasiyet:
|
|
174
|
+
`docs/NM_PYTHON_JUPYTER_BRIDGE_GUIDE.md`.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"nbformat": 4,
|
|
3
|
+
"nbformat_minor": 5,
|
|
4
|
+
"metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, "language_info": {"name": "python"}},
|
|
5
|
+
"cells": [
|
|
6
|
+
{"cell_type": "markdown", "id": "scope", "metadata": {}, "source": [
|
|
7
|
+
"# Explicit N/M cells / Açık N/M hücreleri\n",
|
|
8
|
+
"Local development adapter; not a PyPI release. / Yerel geliştirme adaptörü; PyPI yayını değildir.\n",
|
|
9
|
+
"Install the local wheel and optional Python 3.11+ IPython/kernel requirements first. / Önce yerel wheel ve isteğe bağlı Python 3.11+ IPython/kernel gereksinimlerini kurun.\n",
|
|
10
|
+
"Select an existing trusted absolute CLI file by explicitly setting NM_ADAPTER_CLI_PATH before running this setup cell. The adapter does not discover it. / Setup hücresinden önce NM_ADAPTER_CLI_PATH ile güvenilir mutlak CLI dosyasını açıkça seçin.\n",
|
|
11
|
+
"Opening or saving this notebook does not execute it. Outputs are not pre-executed or saved. / Notebook'u açmak veya kaydetmek yürütme başlatmaz; önceden çalıştırılmış çıktı yoktur."
|
|
12
|
+
]},
|
|
13
|
+
{"cell_type": "code", "id": "setup", "metadata": {}, "execution_count": null, "outputs": [], "source": [
|
|
14
|
+
"import os\n",
|
|
15
|
+
"from pathlib import Path\n",
|
|
16
|
+
"from nm_bridge import NMClient, NMResult\n",
|
|
17
|
+
"cli_path = Path(os.environ['NM_ADAPTER_CLI_PATH']) # Explicit trusted user/test selection / Açık güvenilir seçim\n",
|
|
18
|
+
"features = ('hamiltonianEvolution', 'measurementGrouping')\n",
|
|
19
|
+
"client_en = NMClient(cli_path=cli_path, locale='en', experimental=features)\n",
|
|
20
|
+
"client_tr = NMClient(cli_path=cli_path, locale='tr', experimental=features)\n",
|
|
21
|
+
"%load_ext nm_jupyter"
|
|
22
|
+
]},
|
|
23
|
+
{"cell_type": "code", "id": "check-en", "metadata": {}, "execution_count": null, "outputs": [], "source": [
|
|
24
|
+
"%%nm --client client_en --check\n",
|
|
25
|
+
"module magic_check;\n",
|
|
26
|
+
"fn main(){let q=qreg[1];H(q[0]);return q;}\n",
|
|
27
|
+
"// İı çğ üş 😀 <script>source is data</script> $literal {literal}"
|
|
28
|
+
]},
|
|
29
|
+
{"cell_type": "code", "id": "retain-check-en", "metadata": {}, "execution_count": null, "outputs": [], "source": ["checked_en = _\n", "assert checked_en.success, checked_en.to_json()"]},
|
|
30
|
+
{"cell_type": "code", "id": "run-en", "metadata": {}, "execution_count": null, "outputs": [], "source": [
|
|
31
|
+
"%%nm --client client_en --run\n",
|
|
32
|
+
"module magic_run;\n",
|
|
33
|
+
"@seed(17);\n",
|
|
34
|
+
"fn main(){let q=qreg[1];H(q[0]);let cost=expect Z(q[0]);return cost;}\n",
|
|
35
|
+
"// İı çğ üş 😀 <script>source is data</script>"
|
|
36
|
+
]},
|
|
37
|
+
{"cell_type": "code", "id": "retain-run-en", "metadata": {}, "execution_count": null, "outputs": [], "source": ["ran_en = _\n", "assert ran_en.success, ran_en.to_json()"]},
|
|
38
|
+
{"cell_type": "code", "id": "train-en", "metadata": {}, "execution_count": null, "outputs": [], "source": [
|
|
39
|
+
"%%nm --client client_en --train --steps 2 --learning-rate 0.17 --optimizer adam --objective minimize --objective-target energy --gradient-method parameter-shift --measurement-allocation adaptive --pilot-shots 8 --absolute-error 1e-9\n",
|
|
40
|
+
"module magic_training;\n",
|
|
41
|
+
"@seed(27);\n",
|
|
42
|
+
"@shots_budget(4096);\n",
|
|
43
|
+
"param theta:Angle=0;\n",
|
|
44
|
+
"fn main(){\n",
|
|
45
|
+
" let q=qreg[1];\n",
|
|
46
|
+
" observable Hamiltonian=theta*X(q[0])+0.25*theta*I;\n",
|
|
47
|
+
" evolve Hamiltonian for 0.4 steps 1 order 1 on q;\n",
|
|
48
|
+
" let energy=expect Y(q[0])+0.5*Z(q[0]);\n",
|
|
49
|
+
" return q;\n",
|
|
50
|
+
"}\n",
|
|
51
|
+
"// İı çğ üş 😀 <script>source is data</script>"
|
|
52
|
+
]},
|
|
53
|
+
{"cell_type": "code", "id": "retain-train-en", "metadata": {}, "execution_count": null, "outputs": [], "source": ["trained_en = _\n", "assert trained_en.success, trained_en.to_json()"]},
|
|
54
|
+
{"cell_type": "code", "id": "check-tr", "metadata": {}, "execution_count": null, "outputs": [], "source": [
|
|
55
|
+
"%%nm --client client_tr --check\n",
|
|
56
|
+
"module magic_kontrol;\n",
|
|
57
|
+
"@dil(\"tr\");\n",
|
|
58
|
+
"fn main(){let q=qreg[1];H(q[0]);return q;}\n",
|
|
59
|
+
"// İı çğ üş 😀 <script>kaynak veridir</script>"
|
|
60
|
+
]},
|
|
61
|
+
{"cell_type": "code", "id": "retain-check-tr", "metadata": {}, "execution_count": null, "outputs": [], "source": ["checked_tr = _\n", "assert checked_tr.success, checked_tr.to_json()"]},
|
|
62
|
+
{"cell_type": "code", "id": "run-tr", "metadata": {}, "execution_count": null, "outputs": [], "source": [
|
|
63
|
+
"%%nm --client client_tr --run\n",
|
|
64
|
+
"module magic_yurutme;\n",
|
|
65
|
+
"@dil(\"tr\");\n",
|
|
66
|
+
"@seed(17);\n",
|
|
67
|
+
"fn main(){let q=qreg[1];H(q[0]);let cost=expect Z(q[0]);return cost;}\n",
|
|
68
|
+
"// İı çğ üş 😀 <script>kaynak veridir</script>"
|
|
69
|
+
]},
|
|
70
|
+
{"cell_type": "code", "id": "retain-run-tr", "metadata": {}, "execution_count": null, "outputs": [], "source": ["ran_tr = _\n", "assert ran_tr.success, ran_tr.to_json()"]},
|
|
71
|
+
{"cell_type": "code", "id": "train-tr", "metadata": {}, "execution_count": null, "outputs": [], "source": [
|
|
72
|
+
"%%nm --client client_tr --train --steps 2 --learning-rate 0.17 --optimizer adam --objective minimize --objective-target energy --gradient-method parameter-shift --measurement-allocation adaptive --pilot-shots 8 --absolute-error 1e-9\n",
|
|
73
|
+
"module magic_egitimi;\n",
|
|
74
|
+
"@dil(\"tr\");\n",
|
|
75
|
+
"@seed(27);\n",
|
|
76
|
+
"@shots_budget(4096);\n",
|
|
77
|
+
"param theta:Angle=0;\n",
|
|
78
|
+
"fn main(){\n",
|
|
79
|
+
" let q=qreg[1];\n",
|
|
80
|
+
" observable Hamiltonian=theta*X(q[0])+0.25*theta*I;\n",
|
|
81
|
+
" evolve Hamiltonian for 0.4 adımlar 1 order 1 on q;\n",
|
|
82
|
+
" let energy=expect Y(q[0])+0.5*Z(q[0]);\n",
|
|
83
|
+
" return q;\n",
|
|
84
|
+
"}\n",
|
|
85
|
+
"// İı çğ üş 😀 <script>kaynak veridir</script>"
|
|
86
|
+
]},
|
|
87
|
+
{"cell_type": "code", "id": "retained-records", "metadata": {}, "execution_count": null, "outputs": [], "source": [
|
|
88
|
+
"trained_tr = _\n",
|
|
89
|
+
"assert trained_tr.success, trained_tr.to_json()\n",
|
|
90
|
+
"assert trained_tr.result == trained_en.result\n",
|
|
91
|
+
"restored = NMResult.from_json(trained_en.to_json())\n",
|
|
92
|
+
"assert restored.record == trained_en.record\n",
|
|
93
|
+
"denied = NMClient(cli_path=cli_path).execute(restored.request)\n",
|
|
94
|
+
"assert not denied.success and denied.record['error']['code'] == 'NM-PY-003'\n",
|
|
95
|
+
"# Replay needs a separate explicit API call with client permissions. / Yeniden yürütme ayrıca izinli API çağrısı gerektirir."
|
|
96
|
+
]}
|
|
97
|
+
]
|
|
98
|
+
}
|
package/python/nm_bridge.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"""Bounded local N/M JSON/CLI bridge (Python 3.10+, standard library only).
|
|
2
2
|
|
|
3
3
|
Not a Python evaluator, checkpoint, hardware connector or permission-bearing IR.
|
|
4
|
-
The
|
|
4
|
+
The npm CLI must be built/installed separately. No network or shell is used here.
|
|
5
5
|
"""
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
8
|
import copy
|
|
9
9
|
import html
|
|
10
|
+
import importlib.metadata
|
|
10
11
|
import json
|
|
11
12
|
import math
|
|
12
13
|
import os
|
|
@@ -32,6 +33,7 @@ _COPY = {
|
|
|
32
33
|
"cancel": "Bridge cancelled; the process was killed. No completed result is available.",
|
|
33
34
|
"output": "Bridge output exceeded its byte limit; no partial result was accepted.",
|
|
34
35
|
"node": "Node.js was not found in an absolute PATH directory outside the working directory. Install Node.js or supply a trusted command sequence.",
|
|
36
|
+
"cli": "A trusted absolute N/M CLI file is required. Install the adjacent npm CLI or supply cli_path= or a trusted command sequence.",
|
|
35
37
|
"title": "N/M local bridge", "status": "Execution succeeded", "failed": "Execution failed",
|
|
36
38
|
"rejected": "Request rejected", "shots": "Total shots used / budget", "remaining": "Unallocated shots",
|
|
37
39
|
"pilot": "Pilot shots (allocation only)", "held_out": "Held-out estimation shots",
|
|
@@ -54,6 +56,7 @@ _COPY = {
|
|
|
54
56
|
"cancel": "Köprü iptal edildi; işlem sonlandırıldı. Tamamlanmış sonuç yoktur.",
|
|
55
57
|
"output": "Köprü çıktısı bayt sınırını aştı; kısmi sonuç kabul edilmedi.",
|
|
56
58
|
"node": "Çalışma dizini dışındaki mutlak PATH dizinlerinde Node.js bulunamadı. Node.js kurun veya güvenilir bir komut dizisi verin.",
|
|
59
|
+
"cli": "Güvenilir mutlak N/M CLI dosyası gerekir. Komşu npm CLI'yi kurun veya cli_path= ya da güvenilir bir komut dizisi verin.",
|
|
57
60
|
"title": "N/M yerel köprüsü", "status": "Yürütme başarılı", "failed": "Yürütme başarısız",
|
|
58
61
|
"rejected": "İstek reddedildi", "shots": "Kullanılan toplam ölçüm / bütçe", "remaining": "Dağıtılmamış ölçüm",
|
|
59
62
|
"pilot": "Pilot ölçümler (yalnız dağılım için)", "held_out": "Ayrı değerlendirme ölçümleri",
|
|
@@ -325,15 +328,61 @@ class NMResult:
|
|
|
325
328
|
return table + "<details><summary>" + html.escape(labels["source"]) + "</summary><pre>" + html.escape(str(source)) + "</pre></details>"
|
|
326
329
|
|
|
327
330
|
|
|
331
|
+
def _npm_adjacent_cli(module_path: Path) -> Path:
|
|
332
|
+
"""Use the npm default only when the physical module has unambiguous origin.
|
|
333
|
+
|
|
334
|
+
A wheel may be installed with --target into a directory named ``python``.
|
|
335
|
+
Its local distribution identity/RECORD must take precedence over any sibling
|
|
336
|
+
npm-looking layout. Metadata elsewhere on sys.path does not own this module.
|
|
337
|
+
"""
|
|
338
|
+
module_path = module_path.resolve(strict=True)
|
|
339
|
+
directory = module_path.parent
|
|
340
|
+
if module_path.name != "nm_bridge.py" or directory.name != "python":
|
|
341
|
+
raise ValueError("The standalone adapter requires explicit CLI selection")
|
|
342
|
+
package = directory.parent
|
|
343
|
+
marker = package / "package.json"
|
|
344
|
+
if marker.resolve(strict=True).parent != package:
|
|
345
|
+
raise ValueError("Ambiguous npm package marker")
|
|
346
|
+
with marker.open("rb") as stream:
|
|
347
|
+
manifest = _strict_json(stream.read(65537).decode("utf-8"), 65536, safe_integers=True)
|
|
348
|
+
if (not isinstance(manifest, dict) or manifest.get("name") != "@nm-lang/cli"
|
|
349
|
+
or not isinstance(manifest.get("bin"), dict) or manifest["bin"].get("nm") != "./bin/nm.mjs"):
|
|
350
|
+
raise ValueError("The module is not in the original N/M npm package")
|
|
351
|
+
markers = [entry for entry in directory.iterdir() if entry.name.endswith((".dist-info", ".egg-info"))]
|
|
352
|
+
if any(entry.is_symlink() for entry in markers):
|
|
353
|
+
raise ValueError("Ambiguous local Python distribution marker")
|
|
354
|
+
if any(entry.name.lower().replace("_", "-").replace(".", "-").startswith("nm-jupyter-adapter-") for entry in markers):
|
|
355
|
+
raise ValueError("Standalone adapter installation marker")
|
|
356
|
+
distributions = list(importlib.metadata.distributions(path=[str(directory)]))
|
|
357
|
+
if len(distributions) != len(markers):
|
|
358
|
+
raise ValueError("Unrecognized local Python distribution metadata")
|
|
359
|
+
for distribution in distributions:
|
|
360
|
+
names = distribution.metadata.get_all("Name", [])
|
|
361
|
+
name = names[0] if len(names) == 1 else None
|
|
362
|
+
files = distribution.files
|
|
363
|
+
if not isinstance(name, str) or not name or files is None:
|
|
364
|
+
raise ValueError("Incomplete local Python distribution metadata")
|
|
365
|
+
normalized = name.lower().replace("_", "-").replace(".", "-")
|
|
366
|
+
if normalized == "nm-jupyter-adapter" or any(
|
|
367
|
+
Path(distribution.locate_file(file)).resolve() == module_path for file in files):
|
|
368
|
+
raise ValueError("An installed Python distribution owns the bridge")
|
|
369
|
+
cli = (package / "bin/nm.mjs").resolve(strict=True)
|
|
370
|
+
if not cli.is_relative_to(package):
|
|
371
|
+
raise ValueError("The adjacent CLI resolves outside its npm package")
|
|
372
|
+
return cli
|
|
373
|
+
|
|
374
|
+
|
|
328
375
|
class NMClient:
|
|
329
|
-
"""Each call launches one
|
|
376
|
+
"""Each call launches one CLI process, with independently chosen permissions.
|
|
330
377
|
|
|
331
378
|
command is a trusted argument sequence, never a shell string. The default uses
|
|
332
379
|
an absolute Node executable from PATH and the npm package's adjacent nm.mjs.
|
|
333
380
|
Empty/relative PATH entries and the working directory are never searched.
|
|
381
|
+
Standalone wheel users select an absolute trusted script with cli_path=.
|
|
382
|
+
That option and the existing trusted command= sequence are mutually exclusive.
|
|
334
383
|
"""
|
|
335
384
|
def __init__(self, *, experimental: Sequence[str] = (), locale: str = "en", timeout: float = 30,
|
|
336
|
-
command: Sequence[str] | None = None):
|
|
385
|
+
command: Sequence[str] | None = None, cli_path: str | os.PathLike[str] | None = None):
|
|
337
386
|
if locale not in _COPY:
|
|
338
387
|
raise ValueError("locale must be en or tr")
|
|
339
388
|
self.locale = locale
|
|
@@ -342,8 +391,19 @@ class NMClient:
|
|
|
342
391
|
or any(not isinstance(name, str) or not name.isascii() or not name.isalpha() for name in experimental)
|
|
343
392
|
or len(set(experimental)) != len(experimental)):
|
|
344
393
|
raise NMBridgeError("NM-PY-001", "input", locale)
|
|
394
|
+
if cli_path is not None and command is not None:
|
|
395
|
+
raise NMBridgeError("NM-PY-001", "input", locale)
|
|
345
396
|
if command is None:
|
|
346
|
-
|
|
397
|
+
try:
|
|
398
|
+
cli = Path(cli_path) if cli_path is not None else _npm_adjacent_cli(Path(__file__))
|
|
399
|
+
if not cli.is_absolute():
|
|
400
|
+
raise ValueError("CLI path must be absolute")
|
|
401
|
+
cli = cli.resolve(strict=True)
|
|
402
|
+
if not cli.is_file():
|
|
403
|
+
raise ValueError("CLI path must be a file")
|
|
404
|
+
except (OSError, RuntimeError, TypeError, ValueError, UnicodeError, KeyError, IndexError):
|
|
405
|
+
raise NMBridgeError("NM-PY-012", "cli", locale) from None
|
|
406
|
+
command = (_resolve_node(locale), str(cli))
|
|
347
407
|
if (isinstance(command, (str, bytes)) or not isinstance(command, Sequence) or not command
|
|
348
408
|
or any(not isinstance(arg, str) or not arg or "\0" in arg for arg in command)):
|
|
349
409
|
raise NMBridgeError("NM-PY-001", "input", locale)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Optional, explicitly invoked IPython cells over the stdlib N/M bridge.
|
|
2
|
+
|
|
3
|
+
Importing this package neither imports IPython nor launches the CLI. The legacy
|
|
4
|
+
``from nm_bridge import NMClient, NMResult`` remains supported.
|
|
5
|
+
"""
|
|
6
|
+
from nm_bridge import NMBridgeError, NMClient, NMResult
|
|
7
|
+
|
|
8
|
+
__all__ = ["NMBridgeError", "NMClient", "NMResult"]
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def load_ipython_extension(ipython):
|
|
12
|
+
"""Register %%nm only when IPython explicitly loads this extension."""
|
|
13
|
+
from .extension import load_ipython_extension as load
|
|
14
|
+
load(ipython)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def unload_ipython_extension(ipython):
|
|
18
|
+
"""Remove this extension's magic without changing other shell magics."""
|
|
19
|
+
from .extension import unload_ipython_extension as unload
|
|
20
|
+
unload(ipython)
|