qubasic 0.9.0__tar.gz → 0.10.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {qubasic-0.9.0 → qubasic-0.10.1}/CHANGELOG.md +26 -0
- {qubasic-0.9.0/qubasic.egg-info → qubasic-0.10.1}/PKG-INFO +21 -4
- {qubasic-0.9.0 → qubasic-0.10.1}/README.md +20 -3
- {qubasic-0.9.0 → qubasic-0.10.1}/pyproject.toml +1 -1
- {qubasic-0.9.0 → qubasic-0.10.1/qubasic.egg-info}/PKG-INFO +21 -4
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic.egg-info/SOURCES.txt +1 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/__init__.py +1 -1
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/control_flow.py +22 -8
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/expression.py +58 -7
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/noise_mixin.py +8 -1
- qubasic-0.10.1/qubasic_core/qec.py +434 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/qol.py +2 -1
- qubasic-0.10.1/qubasic_core/resources.py +173 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/strings.py +12 -14
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/terminal.py +19 -7
- {qubasic-0.9.0 → qubasic-0.10.1}/tests/test_qubasic.py +152 -0
- qubasic-0.9.0/qubasic_core/qec.py +0 -220
- {qubasic-0.9.0 → qubasic-0.10.1}/LICENSE +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/MANIFEST.in +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/examples/bell.qb +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/examples/grover3.qb +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/examples/locc_teleport.qb +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/examples/sweep_rx.qb +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic.egg-info/dependency_links.txt +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic.egg-info/entry_points.txt +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic.egg-info/requires.txt +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic.egg-info/top_level.txt +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/__main__.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/algorithms.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/algos2.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/analysis.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/backend.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/benchmarking.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/bosonic.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/classic.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/cli.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/debug.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/demos.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/display.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/dynamics.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/engine.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/engine_state.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/errors.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/exec_context.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/executor.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/file_io.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/gates.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/help_text.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/io_protocol.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/locc.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/locc_commands.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/locc_display.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/locc_engine.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/locc_execution.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/memory.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/mock_backend.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/parser.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/patterns.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/pauliprop.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/profiler.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/program_mgmt.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/protocol.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/qudits.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/scope.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/screen.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/state_display.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/statements.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/subs.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/qubasic_core/sweep.py +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/setup.cfg +0 -0
- {qubasic-0.9.0 → qubasic-0.10.1}/tests/test_features.py +0 -0
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.1 (2026-06-19)
|
|
4
|
+
|
|
5
|
+
Expression, string, and PRINT fixes in the classic-BASIC layer. The quantum
|
|
6
|
+
engine is unchanged.
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
- Math functions resolve in any case: `SQRT`, `SIN`, `ABS`, `INT`, ... now work as well as their lowercase spellings, matching the rest of the language. Runtime and string functions (`RND`, `LEFT$`, ...) are likewise case-insensitive.
|
|
10
|
+
- `AND`, `OR`, `NOT`, `XOR`, and `<>` work in every expression context (`LET`, `PRINT`, gate parameters), not only in `IF` conditions. `AND`/`OR`/`XOR` are bitwise on integers (`6 AND 3` = 2) while preserving operator precedence below comparison, so `IF a > b AND c > d` still groups correctly; `NOT` is logical.
|
|
11
|
+
- String variables are fully usable: `LET s$ = "foo" + "bar"`, `LET t$ = LEFT$(s$, 3)`, and other computed strings store their real value in both immediate and program mode, instead of being mistaken for a quoted literal or forced through `float()`.
|
|
12
|
+
- `PRINT` surfaces evaluation errors instead of silently printing the unevaluated source text. Assigning a string to a numeric variable reports a `TYPE MISMATCH` rather than crashing on a float conversion.
|
|
13
|
+
|
|
14
|
+
## 0.10.0 (2026-06-19)
|
|
15
|
+
|
|
16
|
+
Completes the frontier set: fault-tolerant QEC extras and a compilation/resources
|
|
17
|
+
group. All offline on Qiskit/Aer/numpy.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
- Surface code: `QEC SURFACE [d]`, a rotated surface code at odd distance d (validated to correct every weight-1 error).
|
|
21
|
+
- Union-find / matching decoder: exact minimum-weight matching of syndrome defects, scalable and dependency-free, selected with the `UF` flag on `LOGICAL_ERROR_RATE`. It tracks the optimal lookup decoder on the repetition and surface codes; the lookup decoder remains the default and the right choice for non-topological codes like Steane and Shor.
|
|
22
|
+
- Magic-state distillation: `DISTILL <p>` runs the 15-to-1 protocol (via the [15,11,3] Hamming detection), with cubic output-error suppression ~35 p^3.
|
|
23
|
+
- Lattice surgery: `LATTICE <a> <b>` performs the joint Zbar_A Zbar_B measurement that merges two repetition patches (the building block of a lattice-surgery CNOT).
|
|
24
|
+
- Fault-tolerant resource estimation: `RESOURCES <target_pL> <physical_p>` reports the surface-code distance, physical qubits per logical, T-count, T-factory overhead, and an approximate runtime.
|
|
25
|
+
- Calibrated device models: `DEVICE linear|ring|heavyhex|all [n] [T1us] [T2us]` builds a per-qubit thermal-relaxation noise model and coupling map for offline hardware-realistic simulation.
|
|
26
|
+
- `NOISE crosstalk <p>`: a correlated two-qubit ZZ crosstalk channel on entangling gates.
|
|
27
|
+
- `OPTIMIZE [level]`: transpiles the program and reports the depth and gate-count reduction.
|
|
28
|
+
|
|
3
29
|
## 0.9.0 (2026-06-19)
|
|
4
30
|
|
|
5
31
|
Frontier and experimental methods. All offline on Qiskit/Aer/numpy; nothing
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qubasic
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.1
|
|
4
4
|
Summary: Quantum BASIC Interactive Terminal
|
|
5
5
|
Author-email: "Charles C. Norton" <machineelv@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -242,7 +242,7 @@ CLEAR x Remove a variable
|
|
|
242
242
|
Arithmetic: `+`, `-`, `*`, `/`, `//`, `%`, `**`
|
|
243
243
|
Comparison: `==`, `!=`, `<>`, `<`, `>`, `<=`, `>=`
|
|
244
244
|
Logical: `AND`, `OR`, `NOT`, `XOR`
|
|
245
|
-
Bitwise: `AND`, `OR`, `XOR
|
|
245
|
+
Bitwise: `AND`, `OR`, `XOR` on integers (`6 AND 3` = 2); `NOT` is logical
|
|
246
246
|
Hex/binary literals: `&HFF`, `&B10110`
|
|
247
247
|
|
|
248
248
|
## Arrays
|
|
@@ -514,11 +514,18 @@ CHANNEL AD = [[1,0],[0,0.95]] ; [[0,0.31],[0,0]] Define a Kraus channel
|
|
|
514
514
|
## Error correction
|
|
515
515
|
|
|
516
516
|
```
|
|
517
|
-
QEC STEANE Show a code (REP [d], STEANE, SHOR) and its stabilizers
|
|
518
|
-
LOGICAL_ERROR_RATE STEANE 0.02 Monte-Carlo logical error rate
|
|
517
|
+
QEC STEANE Show a code (REP [d], STEANE, SHOR, SURFACE [d]) and its stabilizers
|
|
518
|
+
LOGICAL_ERROR_RATE STEANE 0.02 Monte-Carlo logical error rate (optimal lookup decoder)
|
|
519
|
+
LOGICAL_ERROR_RATE SURFACE 0.02 UF Same, with the union-find / matching decoder
|
|
519
520
|
THRESHOLD REP 0.0 0.5 11 Sweep p across distances 3/5/7 (crossing at 0.5)
|
|
521
|
+
DISTILL 0.02 15-to-1 magic-state distillation (output error ~35 p^3)
|
|
522
|
+
LATTICE 0 1 Lattice-surgery joint Zbar-Zbar measurement of two patches
|
|
520
523
|
```
|
|
521
524
|
|
|
525
|
+
Codes: repetition (any odd distance), Steane [[7,1,3]], Shor [[9,1,3]], rotated
|
|
526
|
+
surface. Decoders: an optimal minimum-weight lookup table (all codes) and a
|
|
527
|
+
scalable union-find / matching decoder (topological codes, via the `UF` flag).
|
|
528
|
+
|
|
522
529
|
## Benchmarking and verification
|
|
523
530
|
|
|
524
531
|
```
|
|
@@ -554,6 +561,16 @@ BOSONIC 1 25 Continuous-variable Fock modes
|
|
|
554
561
|
DISPLACE 0 1.0 ...DISPLACE, SQUEEZE, CAT, BS, BSTATE
|
|
555
562
|
```
|
|
556
563
|
|
|
564
|
+
## Compilation and resources
|
|
565
|
+
|
|
566
|
+
```
|
|
567
|
+
RESOURCES 1e-12 0.001 Fault-tolerant estimate (surface-code distance, qubits, runtime)
|
|
568
|
+
DEVICE linear 5 Calibrated offline device model (per-qubit T1/T2 + coupling map)
|
|
569
|
+
DEVICE ring 5 80 60 ...with custom T1/T2 in microseconds (also: heavyhex, all, OFF)
|
|
570
|
+
OPTIMIZE 3 Transpile the program and report the depth/gate reduction
|
|
571
|
+
NOISE crosstalk 0.01 Correlated two-qubit ZZ crosstalk on entangling gates
|
|
572
|
+
```
|
|
573
|
+
|
|
557
574
|
## Noise models
|
|
558
575
|
|
|
559
576
|
```
|
|
@@ -209,7 +209,7 @@ CLEAR x Remove a variable
|
|
|
209
209
|
Arithmetic: `+`, `-`, `*`, `/`, `//`, `%`, `**`
|
|
210
210
|
Comparison: `==`, `!=`, `<>`, `<`, `>`, `<=`, `>=`
|
|
211
211
|
Logical: `AND`, `OR`, `NOT`, `XOR`
|
|
212
|
-
Bitwise: `AND`, `OR`, `XOR
|
|
212
|
+
Bitwise: `AND`, `OR`, `XOR` on integers (`6 AND 3` = 2); `NOT` is logical
|
|
213
213
|
Hex/binary literals: `&HFF`, `&B10110`
|
|
214
214
|
|
|
215
215
|
## Arrays
|
|
@@ -481,11 +481,18 @@ CHANNEL AD = [[1,0],[0,0.95]] ; [[0,0.31],[0,0]] Define a Kraus channel
|
|
|
481
481
|
## Error correction
|
|
482
482
|
|
|
483
483
|
```
|
|
484
|
-
QEC STEANE Show a code (REP [d], STEANE, SHOR) and its stabilizers
|
|
485
|
-
LOGICAL_ERROR_RATE STEANE 0.02 Monte-Carlo logical error rate
|
|
484
|
+
QEC STEANE Show a code (REP [d], STEANE, SHOR, SURFACE [d]) and its stabilizers
|
|
485
|
+
LOGICAL_ERROR_RATE STEANE 0.02 Monte-Carlo logical error rate (optimal lookup decoder)
|
|
486
|
+
LOGICAL_ERROR_RATE SURFACE 0.02 UF Same, with the union-find / matching decoder
|
|
486
487
|
THRESHOLD REP 0.0 0.5 11 Sweep p across distances 3/5/7 (crossing at 0.5)
|
|
488
|
+
DISTILL 0.02 15-to-1 magic-state distillation (output error ~35 p^3)
|
|
489
|
+
LATTICE 0 1 Lattice-surgery joint Zbar-Zbar measurement of two patches
|
|
487
490
|
```
|
|
488
491
|
|
|
492
|
+
Codes: repetition (any odd distance), Steane [[7,1,3]], Shor [[9,1,3]], rotated
|
|
493
|
+
surface. Decoders: an optimal minimum-weight lookup table (all codes) and a
|
|
494
|
+
scalable union-find / matching decoder (topological codes, via the `UF` flag).
|
|
495
|
+
|
|
489
496
|
## Benchmarking and verification
|
|
490
497
|
|
|
491
498
|
```
|
|
@@ -521,6 +528,16 @@ BOSONIC 1 25 Continuous-variable Fock modes
|
|
|
521
528
|
DISPLACE 0 1.0 ...DISPLACE, SQUEEZE, CAT, BS, BSTATE
|
|
522
529
|
```
|
|
523
530
|
|
|
531
|
+
## Compilation and resources
|
|
532
|
+
|
|
533
|
+
```
|
|
534
|
+
RESOURCES 1e-12 0.001 Fault-tolerant estimate (surface-code distance, qubits, runtime)
|
|
535
|
+
DEVICE linear 5 Calibrated offline device model (per-qubit T1/T2 + coupling map)
|
|
536
|
+
DEVICE ring 5 80 60 ...with custom T1/T2 in microseconds (also: heavyhex, all, OFF)
|
|
537
|
+
OPTIMIZE 3 Transpile the program and report the depth/gate reduction
|
|
538
|
+
NOISE crosstalk 0.01 Correlated two-qubit ZZ crosstalk on entangling gates
|
|
539
|
+
```
|
|
540
|
+
|
|
524
541
|
## Noise models
|
|
525
542
|
|
|
526
543
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qubasic
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.1
|
|
4
4
|
Summary: Quantum BASIC Interactive Terminal
|
|
5
5
|
Author-email: "Charles C. Norton" <machineelv@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -242,7 +242,7 @@ CLEAR x Remove a variable
|
|
|
242
242
|
Arithmetic: `+`, `-`, `*`, `/`, `//`, `%`, `**`
|
|
243
243
|
Comparison: `==`, `!=`, `<>`, `<`, `>`, `<=`, `>=`
|
|
244
244
|
Logical: `AND`, `OR`, `NOT`, `XOR`
|
|
245
|
-
Bitwise: `AND`, `OR`, `XOR
|
|
245
|
+
Bitwise: `AND`, `OR`, `XOR` on integers (`6 AND 3` = 2); `NOT` is logical
|
|
246
246
|
Hex/binary literals: `&HFF`, `&B10110`
|
|
247
247
|
|
|
248
248
|
## Arrays
|
|
@@ -514,11 +514,18 @@ CHANNEL AD = [[1,0],[0,0.95]] ; [[0,0.31],[0,0]] Define a Kraus channel
|
|
|
514
514
|
## Error correction
|
|
515
515
|
|
|
516
516
|
```
|
|
517
|
-
QEC STEANE Show a code (REP [d], STEANE, SHOR) and its stabilizers
|
|
518
|
-
LOGICAL_ERROR_RATE STEANE 0.02 Monte-Carlo logical error rate
|
|
517
|
+
QEC STEANE Show a code (REP [d], STEANE, SHOR, SURFACE [d]) and its stabilizers
|
|
518
|
+
LOGICAL_ERROR_RATE STEANE 0.02 Monte-Carlo logical error rate (optimal lookup decoder)
|
|
519
|
+
LOGICAL_ERROR_RATE SURFACE 0.02 UF Same, with the union-find / matching decoder
|
|
519
520
|
THRESHOLD REP 0.0 0.5 11 Sweep p across distances 3/5/7 (crossing at 0.5)
|
|
521
|
+
DISTILL 0.02 15-to-1 magic-state distillation (output error ~35 p^3)
|
|
522
|
+
LATTICE 0 1 Lattice-surgery joint Zbar-Zbar measurement of two patches
|
|
520
523
|
```
|
|
521
524
|
|
|
525
|
+
Codes: repetition (any odd distance), Steane [[7,1,3]], Shor [[9,1,3]], rotated
|
|
526
|
+
surface. Decoders: an optimal minimum-weight lookup table (all codes) and a
|
|
527
|
+
scalable union-find / matching decoder (topological codes, via the `UF` flag).
|
|
528
|
+
|
|
522
529
|
## Benchmarking and verification
|
|
523
530
|
|
|
524
531
|
```
|
|
@@ -554,6 +561,16 @@ BOSONIC 1 25 Continuous-variable Fock modes
|
|
|
554
561
|
DISPLACE 0 1.0 ...DISPLACE, SQUEEZE, CAT, BS, BSTATE
|
|
555
562
|
```
|
|
556
563
|
|
|
564
|
+
## Compilation and resources
|
|
565
|
+
|
|
566
|
+
```
|
|
567
|
+
RESOURCES 1e-12 0.001 Fault-tolerant estimate (surface-code distance, qubits, runtime)
|
|
568
|
+
DEVICE linear 5 Calibrated offline device model (per-qubit T1/T2 + coupling map)
|
|
569
|
+
DEVICE ring 5 80 60 ...with custom T1/T2 in microseconds (also: heavyhex, all, OFF)
|
|
570
|
+
OPTIMIZE 3 Transpile the program and report the depth/gate reduction
|
|
571
|
+
NOISE crosstalk 0.01 Correlated two-qubit ZZ crosstalk on entangling gates
|
|
572
|
+
```
|
|
573
|
+
|
|
557
574
|
## Noise models
|
|
558
575
|
|
|
559
576
|
```
|
|
@@ -12,7 +12,7 @@ from qubasic_core.engine import ExecResult, ExecOutcome
|
|
|
12
12
|
from qubasic_core.parser import parse_stmt
|
|
13
13
|
from qubasic_core.statements import (
|
|
14
14
|
RawStmt, RemStmt, MeasureStmt, EndStmt, ReturnStmt, WendStmt,
|
|
15
|
-
LetArrayStmt, LetStmt, PrintStmt, GotoStmt, GosubStmt,
|
|
15
|
+
LetArrayStmt, LetStmt, LetStrStmt, PrintStmt, GotoStmt, GosubStmt,
|
|
16
16
|
ForStmt, NextStmt, WhileStmt, IfThenStmt,
|
|
17
17
|
DataStmt, ReadStmt, OnGotoStmt, OnGosubStmt,
|
|
18
18
|
SelectCaseStmt, CaseStmt, EndSelectStmt, ElseStmt, EndIfStmt,
|
|
@@ -106,7 +106,20 @@ class ControlFlowMixin:
|
|
|
106
106
|
def _cf_let_var(self, stmt: str, run_vars: dict[str, Any],
|
|
107
107
|
parsed: LetStmt) -> tuple[bool, ExecOutcome]:
|
|
108
108
|
name, expr = parsed.name, parsed.expr
|
|
109
|
-
|
|
109
|
+
raw = self._safe_eval(expr, extra_ns=run_vars)
|
|
110
|
+
if isinstance(raw, str):
|
|
111
|
+
raise RuntimeError(
|
|
112
|
+
f"TYPE MISMATCH: '{name}' is numeric; use '{name}$' for strings")
|
|
113
|
+
val = float(raw)
|
|
114
|
+
run_vars[name] = val
|
|
115
|
+
self.variables[name] = val
|
|
116
|
+
return True, ExecResult.ADVANCE
|
|
117
|
+
|
|
118
|
+
def _cf_let_str(self, stmt: str, run_vars: dict[str, Any],
|
|
119
|
+
parsed: LetStrStmt) -> tuple[bool, ExecOutcome]:
|
|
120
|
+
"""LET v$ = <expr> — assign a string (or number) to a string variable."""
|
|
121
|
+
name, expr = parsed.name, parsed.expr
|
|
122
|
+
val = self._eval_string_expr(expr, run_vars)
|
|
110
123
|
run_vars[name] = val
|
|
111
124
|
self.variables[name] = val
|
|
112
125
|
return True, ExecResult.ADVANCE
|
|
@@ -167,12 +180,12 @@ class ControlFlowMixin:
|
|
|
167
180
|
text = re.sub(r'\bTAB\s*\(([^)]+)\)', _spaces, text, flags=re.IGNORECASE)
|
|
168
181
|
if not text.strip():
|
|
169
182
|
return text # standalone SPC/TAB -> whitespace
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
183
|
+
ns = run_vars.as_dict() if hasattr(run_vars, 'as_dict') else (
|
|
184
|
+
run_vars if isinstance(run_vars, dict) else dict(run_vars))
|
|
185
|
+
# Surface evaluation errors instead of silently printing the raw source
|
|
186
|
+
# text (which used to turn PRINT SQRT(9) into the literal "SQRT(9)" and
|
|
187
|
+
# an undefined variable into its own name).
|
|
188
|
+
return str(self._safe_eval(text, extra_ns=ns))
|
|
176
189
|
|
|
177
190
|
def _cf_print(self, stmt: str, run_vars: dict[str, Any],
|
|
178
191
|
parsed: PrintStmt) -> tuple[bool, ExecOutcome]:
|
|
@@ -400,6 +413,7 @@ class ControlFlowMixin:
|
|
|
400
413
|
WendStmt: lambda s, st, p, ls, sl, ip, rv, ef: s._cf_wend(rv, ls, sl, ip),
|
|
401
414
|
LetArrayStmt: lambda s, st, p, ls, sl, ip, rv, ef: s._cf_let_array(st, rv, p),
|
|
402
415
|
LetStmt: lambda s, st, p, ls, sl, ip, rv, ef: s._cf_let_var(st, rv, p),
|
|
416
|
+
LetStrStmt: lambda s, st, p, ls, sl, ip, rv, ef: s._cf_let_str(st, rv, p),
|
|
403
417
|
PrintStmt: lambda s, st, p, ls, sl, ip, rv, ef: s._cf_print(st, rv, p),
|
|
404
418
|
GotoStmt: lambda s, st, p, ls, sl, ip, rv, ef: s._cf_goto(st, sl, p),
|
|
405
419
|
GosubStmt: lambda s, st, p, ls, sl, ip, rv, ef: s._cf_gosub(st, sl, ip, p),
|
|
@@ -94,6 +94,36 @@ def _rewrite_logical_outside_strings(cond: str) -> str:
|
|
|
94
94
|
return ''.join(parts)
|
|
95
95
|
|
|
96
96
|
|
|
97
|
+
def _as_int(x: Any) -> int:
|
|
98
|
+
"""Coerce a BASIC value to int for bitwise AND/OR/XOR.
|
|
99
|
+
|
|
100
|
+
QBasic rounds non-integers; truth values and non-numerics fold to 1/0 so
|
|
101
|
+
``(a > 0) AND (b > 0)`` works the same as ``6 AND 3``.
|
|
102
|
+
"""
|
|
103
|
+
if isinstance(x, bool):
|
|
104
|
+
return int(x)
|
|
105
|
+
if isinstance(x, int):
|
|
106
|
+
return x
|
|
107
|
+
if isinstance(x, float):
|
|
108
|
+
return int(round(x))
|
|
109
|
+
return 1 if x else 0
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _basic_and(a: Any, b: Any) -> int:
|
|
113
|
+
"""BASIC AND — bitwise on integers, and correct for truth values
|
|
114
|
+
(1 & 1 == 1, 1 & 0 == 0). Parsed from ``and`` so precedence stays below
|
|
115
|
+
comparison: ``a > b AND c > d`` groups as ``(a>b) AND (c>d)``."""
|
|
116
|
+
return _as_int(a) & _as_int(b)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _basic_or(a: Any, b: Any) -> int:
|
|
120
|
+
return _as_int(a) | _as_int(b)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _basic_xor(a: Any, b: Any) -> int:
|
|
124
|
+
return _as_int(a) ^ _as_int(b)
|
|
125
|
+
|
|
126
|
+
|
|
97
127
|
class ExpressionMixin:
|
|
98
128
|
"""AST-based safe expression evaluation. No eval().
|
|
99
129
|
|
|
@@ -126,11 +156,14 @@ class ExpressionMixin:
|
|
|
126
156
|
ast.Eq: operator.eq, ast.NotEq: operator.ne,
|
|
127
157
|
ast.Lt: operator.lt, ast.LtE: operator.le,
|
|
128
158
|
ast.Gt: operator.gt, ast.GtE: operator.ge,
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
ast.
|
|
133
|
-
ast.
|
|
159
|
+
# AND/OR/XOR are BASIC's bitwise-logical operators (6 AND 3 == 2),
|
|
160
|
+
# robust to float operands; NOT stays logical so IF NOT flag works
|
|
161
|
+
# with 0/1 truth values.
|
|
162
|
+
ast.And: _basic_and,
|
|
163
|
+
ast.Or: _basic_or,
|
|
164
|
+
ast.BitAnd: _basic_and,
|
|
165
|
+
ast.BitOr: _basic_or,
|
|
166
|
+
ast.BitXor: _basic_xor,
|
|
134
167
|
ast.Invert: operator.invert,
|
|
135
168
|
}
|
|
136
169
|
|
|
@@ -237,6 +270,13 @@ class ExpressionMixin:
|
|
|
237
270
|
ns['FRE'] = lambda x=0: psutil.virtual_memory().available
|
|
238
271
|
except ImportError:
|
|
239
272
|
ns['FRE'] = lambda x=0: 0
|
|
273
|
+
# BASIC is case-insensitive for built-in functions and constants, so
|
|
274
|
+
# register upper- and lower-case aliases for every builtin (SQRT and
|
|
275
|
+
# sqrt, RND and rnd, LEFT$ and left$). Variables are merged with their
|
|
276
|
+
# own case in _safe_eval and shadow these.
|
|
277
|
+
for _name in list(ns.keys()):
|
|
278
|
+
ns.setdefault(_name.upper(), ns[_name])
|
|
279
|
+
ns.setdefault(_name.lower(), ns[_name])
|
|
240
280
|
self._base_ns = ns
|
|
241
281
|
return ns
|
|
242
282
|
|
|
@@ -301,9 +341,17 @@ class ExpressionMixin:
|
|
|
301
341
|
expr_str = str(expr).strip()
|
|
302
342
|
# Normalize FN prefix: "FN square(x)" -> "square(x)"
|
|
303
343
|
expr_str = re.sub(r'\bFN\s+(\w+)\s*\(', r'\1(', expr_str, flags=re.IGNORECASE)
|
|
344
|
+
# Rewrite BASIC logical/relational operators (AND, OR, NOT, XOR, <>) to
|
|
345
|
+
# the Python forms the AST understands, only outside quoted strings.
|
|
346
|
+
# Applied to every expression (LET, PRINT, gate params), not just IF
|
|
347
|
+
# conditions, so the documented operators work everywhere.
|
|
348
|
+
expr_str = _rewrite_logical_outside_strings(expr_str)
|
|
304
349
|
# Rewrite numeric literals (&H, &B, $hex addresses) and the string
|
|
305
350
|
# sigil, each only outside quoted string literals.
|
|
306
351
|
expr_str = _replace_dollar_outside_strings(expr_str)
|
|
352
|
+
# The operator rewrite can pad a leading token (NOT x -> " not x"); strip
|
|
353
|
+
# so ast.parse(mode='eval') does not reject it as an unexpected indent.
|
|
354
|
+
expr_str = expr_str.strip()
|
|
307
355
|
if not expr_str:
|
|
308
356
|
raise ValueError("EMPTY EXPRESSION")
|
|
309
357
|
try:
|
|
@@ -351,8 +399,11 @@ class ExpressionMixin:
|
|
|
351
399
|
return float(self._safe_eval(expr, extra_ns=run_vars))
|
|
352
400
|
|
|
353
401
|
def _eval_condition(self, cond: str, run_vars: dict[str, Any]) -> bool:
|
|
354
|
-
"""Evaluate a boolean condition.
|
|
355
|
-
|
|
402
|
+
"""Evaluate a boolean condition.
|
|
403
|
+
|
|
404
|
+
The operator rewrite (AND/OR/NOT/XOR/<>) now happens inside _safe_eval,
|
|
405
|
+
so conditions and ordinary expressions share one consistent path.
|
|
406
|
+
"""
|
|
356
407
|
return bool(self._safe_eval(cond, extra_ns=run_vars))
|
|
357
408
|
|
|
358
409
|
def _run_timer(self) -> float:
|
|
@@ -106,10 +106,17 @@ class NoiseMixin:
|
|
|
106
106
|
p1 = float(parts[2]) if len(parts) > 2 else 0.01
|
|
107
107
|
nm.add_all_qubit_quantum_error(reset_error(p0, p1), _1q)
|
|
108
108
|
self.io.writeln(f"NOISE reset p0={p0} p1={p1}")
|
|
109
|
+
elif ntype == 'crosstalk':
|
|
110
|
+
# Correlated (non-product) two-qubit error after each 2-qubit gate:
|
|
111
|
+
# a ZZ Pauli with probability p, otherwise identity.
|
|
112
|
+
p = float(parts[1]) if len(parts) > 1 else 0.01
|
|
113
|
+
err = pauli_error([('ZZ', p), ('II', 1 - p)])
|
|
114
|
+
nm.add_all_qubit_quantum_error(err, _2q)
|
|
115
|
+
self.io.writeln(f"NOISE crosstalk (correlated ZZ on 2-qubit gates) p={p}")
|
|
109
116
|
else:
|
|
110
117
|
self.io.writeln(f"?UNKNOWN NOISE TYPE: {ntype}")
|
|
111
118
|
self.io.writeln(" Types: depolarizing, amplitude_damping, phase_flip, thermal,")
|
|
112
|
-
self.io.writeln(" readout, combined, pauli, reset")
|
|
119
|
+
self.io.writeln(" readout, combined, pauli, reset, crosstalk")
|
|
113
120
|
return
|
|
114
121
|
self._noise_model = nm
|
|
115
122
|
self._noise_spec = rest.strip() # for SAVE round-tripping
|