qubasic 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. qbasic.py +113 -0
  2. qbasic_core/__init__.py +80 -0
  3. qbasic_core/__main__.py +6 -0
  4. qbasic_core/analysis.py +179 -0
  5. qbasic_core/backend.py +76 -0
  6. qbasic_core/classic.py +419 -0
  7. qbasic_core/control_flow.py +576 -0
  8. qbasic_core/debug.py +327 -0
  9. qbasic_core/demos.py +356 -0
  10. qbasic_core/display.py +274 -0
  11. qbasic_core/engine.py +126 -0
  12. qbasic_core/engine_state.py +109 -0
  13. qbasic_core/errors.py +37 -0
  14. qbasic_core/exec_context.py +24 -0
  15. qbasic_core/executor.py +861 -0
  16. qbasic_core/expression.py +228 -0
  17. qbasic_core/file_io.py +457 -0
  18. qbasic_core/gates.py +284 -0
  19. qbasic_core/help_text.py +167 -0
  20. qbasic_core/io_protocol.py +33 -0
  21. qbasic_core/locc.py +10 -0
  22. qbasic_core/locc_commands.py +221 -0
  23. qbasic_core/locc_display.py +61 -0
  24. qbasic_core/locc_engine.py +195 -0
  25. qbasic_core/locc_execution.py +389 -0
  26. qbasic_core/memory.py +369 -0
  27. qbasic_core/mock_backend.py +66 -0
  28. qbasic_core/noise_mixin.py +96 -0
  29. qbasic_core/parser.py +564 -0
  30. qbasic_core/patterns.py +186 -0
  31. qbasic_core/profiler.py +156 -0
  32. qbasic_core/program_mgmt.py +369 -0
  33. qbasic_core/protocol.py +77 -0
  34. qbasic_core/py.typed +0 -0
  35. qbasic_core/scope.py +74 -0
  36. qbasic_core/screen.py +115 -0
  37. qbasic_core/state_display.py +60 -0
  38. qbasic_core/statements.py +387 -0
  39. qbasic_core/strings.py +107 -0
  40. qbasic_core/subs.py +261 -0
  41. qbasic_core/sweep.py +82 -0
  42. qbasic_core/terminal.py +1697 -0
  43. qubasic-0.1.0.dist-info/METADATA +736 -0
  44. qubasic-0.1.0.dist-info/RECORD +48 -0
  45. qubasic-0.1.0.dist-info/WHEEL +5 -0
  46. qubasic-0.1.0.dist-info/entry_points.txt +2 -0
  47. qubasic-0.1.0.dist-info/licenses/LICENSE +21 -0
  48. qubasic-0.1.0.dist-info/top_level.txt +2 -0
qbasic_core/debug.py ADDED
@@ -0,0 +1,327 @@
1
+ """QBASIC debug — ON ERROR, TRON/TROFF, STOP/CONT, breakpoints, watch, ASSERT, callbacks."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import time
6
+
7
+ MAX_SV_CHECKPOINTS = 1000
8
+ from typing import Any
9
+
10
+ from qbasic_core.engine import (
11
+ ExecResult, ExecOutcome,
12
+ RE_ON_ERROR, RE_RESUME, RE_ERROR_STMT, RE_ASSERT,
13
+ RE_ON_MEASURE, RE_ON_TIMER,
14
+ )
15
+
16
+
17
+ class DebugMixin:
18
+ """Error handling, debugging, and event callbacks for QBasicTerminal.
19
+
20
+ Requires: TerminalProtocol — uses self.program, self.variables,
21
+ self._eval_condition(), self._gosub_stack.
22
+ """
23
+
24
+ def _init_debug(self) -> None:
25
+ self._error_target: int | None = None
26
+ self._err_code: int = 0
27
+ self._err_line: int = 0
28
+ self._in_error_handler: bool = False
29
+ self._trace_mode: bool = False
30
+ self._stopped_ip: int | None = None
31
+ self._cont_skip_stop_ip: int | None = None
32
+ self._breakpoints: set[int] = set()
33
+ self._watches: list[str] = []
34
+ self._on_measure_target: int | None = None
35
+ self._on_timer_target: int | None = None
36
+ self._on_timer_interval: float = 0.0
37
+ self._on_timer_last: float = 0.0
38
+ # Time-travel: statevector checkpoints indexed by gate count
39
+ self._sv_checkpoints: list[tuple[int, Any]] = [] # [(line_num, sv_copy)]
40
+ self._tt_position: int = -1 # current position in checkpoint list
41
+
42
+ # ── Error handling ─────────────────────────────────────────────────
43
+
44
+ def _cf_on_error(self, stmt: str, *, parsed=None) -> tuple[bool, ExecOutcome] | None:
45
+ if parsed is not None:
46
+ target = parsed.target
47
+ else:
48
+ m = RE_ON_ERROR.match(stmt)
49
+ if not m:
50
+ return None
51
+ target = int(m.group(1))
52
+ if target == 0:
53
+ self._error_target = None
54
+ else:
55
+ self._error_target = target
56
+ return True, ExecResult.ADVANCE
57
+
58
+ def _cf_resume(self, stmt: str, sorted_lines: list[int], *, parsed=None) -> tuple[bool, ExecOutcome] | None:
59
+ if parsed is not None:
60
+ self._in_error_handler = False
61
+ arg = parsed.arg
62
+ else:
63
+ m = RE_RESUME.match(stmt)
64
+ if not m:
65
+ return None
66
+ self._in_error_handler = False
67
+ arg = m.group(1)
68
+ if arg is None or arg.strip() == '':
69
+ # RESUME — retry the line that caused the error
70
+ for i, ln in enumerate(sorted_lines):
71
+ if ln == self._err_line:
72
+ return True, i
73
+ return True, ExecResult.ADVANCE
74
+ if arg.strip().upper() == 'NEXT':
75
+ for i, ln in enumerate(sorted_lines):
76
+ if ln == self._err_line:
77
+ return True, i + 1
78
+ return True, ExecResult.ADVANCE
79
+ # RESUME <line>
80
+ target = int(arg.strip())
81
+ for i, ln in enumerate(sorted_lines):
82
+ if ln == target:
83
+ return True, i
84
+ raise RuntimeError(f"RESUME: LINE {target} NOT FOUND")
85
+
86
+ def _cf_error(self, stmt: str, *, parsed=None) -> tuple[bool, ExecOutcome] | None:
87
+ if parsed is not None:
88
+ code = parsed.code
89
+ else:
90
+ m = RE_ERROR_STMT.match(stmt)
91
+ if not m:
92
+ return None
93
+ code = int(m.group(1))
94
+ raise RuntimeError(f"ERROR {code}")
95
+
96
+ def _handle_error(self, err: Exception, line_num: int,
97
+ sorted_lines: list[int]) -> int | None:
98
+ """Handle a runtime error. Returns ip to jump to, or None to propagate."""
99
+ if self._error_target is not None and not self._in_error_handler:
100
+ self._err_code = 1
101
+ self._err_line = line_num
102
+ self._in_error_handler = True
103
+ # Extract error code from "ERROR N" messages
104
+ msg = str(err)
105
+ if msg.startswith('ERROR '):
106
+ try:
107
+ self._err_code = int(msg.split()[1])
108
+ except (IndexError, ValueError):
109
+ pass
110
+ self.variables['ERR'] = self._err_code
111
+ self.variables['ERL'] = self._err_line
112
+ for i, ln in enumerate(sorted_lines):
113
+ if ln == self._error_target:
114
+ return i
115
+ return None
116
+
117
+ # ── ASSERT ─────────────────────────────────────────────────────────
118
+
119
+ def _cf_assert(self, stmt: str, run_vars: dict[str, Any], *, parsed=None) -> tuple[bool, ExecOutcome] | None:
120
+ if parsed is not None:
121
+ cond = parsed.condition
122
+ else:
123
+ m = RE_ASSERT.match(stmt)
124
+ if not m:
125
+ return None
126
+ cond = m.group(1).strip()
127
+ if not self._eval_condition(cond, run_vars):
128
+ raise RuntimeError(f"ASSERTION FAILED: {cond}")
129
+ return True, ExecResult.ADVANCE
130
+
131
+ # ── Time-travel debugging ─────────────────────────────────────────
132
+
133
+ def _checkpoint_sv(self, line_num: int) -> None:
134
+ """Save a statevector checkpoint (for small qubit counts)."""
135
+ if self.last_sv is not None and self.num_qubits <= 16:
136
+ import numpy as np
137
+ self._sv_checkpoints.append((line_num, np.array(self.last_sv).copy()))
138
+ if len(self._sv_checkpoints) > MAX_SV_CHECKPOINTS:
139
+ excess = len(self._sv_checkpoints) - MAX_SV_CHECKPOINTS
140
+ del self._sv_checkpoints[:excess]
141
+ self._tt_position = len(self._sv_checkpoints) - 1
142
+
143
+ def cmd_rewind(self, rest: str = '') -> None:
144
+ """REWIND [N] — go back N steps in the statevector history."""
145
+ if not self._sv_checkpoints:
146
+ self.io.writeln("?NO CHECKPOINTS — use STEP mode to build history")
147
+ return
148
+ n = int(rest.strip()) if rest.strip() else 1
149
+ new_pos = max(0, self._tt_position - n)
150
+ self._tt_position = new_pos
151
+ line_num, sv = self._sv_checkpoints[new_pos]
152
+ self.last_sv = sv.copy()
153
+ self.io.writeln(f"REWIND to step {new_pos} (line {line_num})")
154
+ self._print_sv_compact(sv)
155
+
156
+ def cmd_forward(self, rest: str = '') -> None:
157
+ """FORWARD [N] — go forward N steps in the statevector history."""
158
+ if not self._sv_checkpoints:
159
+ self.io.writeln("?NO CHECKPOINTS")
160
+ return
161
+ n = int(rest.strip()) if rest.strip() else 1
162
+ new_pos = min(len(self._sv_checkpoints) - 1, self._tt_position + n)
163
+ self._tt_position = new_pos
164
+ line_num, sv = self._sv_checkpoints[new_pos]
165
+ self.last_sv = sv.copy()
166
+ self.io.writeln(f"FORWARD to step {new_pos} (line {line_num})")
167
+ self._print_sv_compact(sv)
168
+
169
+ def cmd_history(self, rest: str = '') -> None:
170
+ """HISTORY — show statevector checkpoint list."""
171
+ if not self._sv_checkpoints:
172
+ self.io.writeln("?NO CHECKPOINTS")
173
+ return
174
+ for i, (ln, _) in enumerate(self._sv_checkpoints):
175
+ marker = " <<" if i == self._tt_position else ""
176
+ self.io.writeln(f" [{i}] line {ln}{marker}")
177
+
178
+ # ── TRON / TROFF ───────────────────────────────────────────────────
179
+
180
+ def cmd_tron(self) -> None:
181
+ """TRON — trace on, print each line number during execution."""
182
+ self._trace_mode = True
183
+ self.io.writeln("TRACE ON")
184
+
185
+ def cmd_troff(self) -> None:
186
+ """TROFF — trace off."""
187
+ self._trace_mode = False
188
+ self.io.writeln("TRACE OFF")
189
+
190
+ def _trace_line(self, line_num: int) -> None:
191
+ """Print trace output if trace mode is on."""
192
+ if self._trace_mode:
193
+ self.io.write(f"[{line_num}]" + ' ')
194
+
195
+ # ── STOP / CONT ────────────────────────────────────────────────────
196
+
197
+ def _cf_stop(self, stmt: str, sorted_lines: list[int], ip: int, *, parsed=None) -> tuple[bool, ExecOutcome] | None:
198
+ if parsed is None and stmt.strip().upper() != 'STOP':
199
+ return None
200
+ # CONT sets _cont_skip_stop_ip to replay past this STOP
201
+ if self._cont_skip_stop_ip is not None and self._cont_skip_stop_ip == ip:
202
+ self._cont_skip_stop_ip = None
203
+ return True, ExecResult.ADVANCE
204
+ line_num = sorted_lines[ip]
205
+ self.io.writeln(f"STOPPED AT LINE {line_num}")
206
+ self._stopped_ip = ip
207
+ self._print_watches()
208
+ return True, ExecResult.END
209
+
210
+ def cmd_cont(self) -> None:
211
+ """CONT — continue execution after STOP, resuming from the next line.
212
+
213
+ Re-executes the program from the top but skips the STOP that fired,
214
+ so lines after STOP are reached. Variable state is rebuilt by
215
+ replaying all lines before the STOP.
216
+ """
217
+ if self._stopped_ip is None:
218
+ self.io.writeln("?CANNOT CONTINUE")
219
+ return
220
+ self.io.writeln("CONTINUING...")
221
+ self._cont_skip_stop_ip = self._stopped_ip
222
+ self._stopped_ip = None
223
+ self.cmd_run()
224
+
225
+ # ── Breakpoints ────────────────────────────────────────────────────
226
+
227
+ def cmd_breakpoint(self, rest: str) -> None:
228
+ """BREAK <line> — set/clear/list breakpoints."""
229
+ if not rest.strip():
230
+ if self._breakpoints:
231
+ self.io.writeln(f" Breakpoints: {sorted(self._breakpoints)}")
232
+ else:
233
+ self.io.writeln(" No breakpoints set")
234
+ return
235
+ rest = rest.strip().upper()
236
+ if rest == 'CLEAR':
237
+ self._breakpoints.clear()
238
+ self.io.writeln("BREAKPOINTS CLEARED")
239
+ return
240
+ try:
241
+ line = int(rest)
242
+ if line in self._breakpoints:
243
+ self._breakpoints.discard(line)
244
+ self.io.writeln(f"BREAKPOINT REMOVED: {line}")
245
+ else:
246
+ self._breakpoints.add(line)
247
+ self.io.writeln(f"BREAKPOINT SET: {line}")
248
+ except ValueError:
249
+ self.io.writeln("?USAGE: BREAK <line> | BREAK CLEAR")
250
+
251
+ def _check_breakpoint(self, line_num: int, sorted_lines: list[int], ip: int) -> bool:
252
+ """Check if we should break at this line. Returns True to stop."""
253
+ if line_num in self._breakpoints:
254
+ self.io.writeln(f"BREAKPOINT AT LINE {line_num}")
255
+ self._stopped_ip = ip
256
+ self._print_watches()
257
+ return True
258
+ return False
259
+
260
+ # ── Watch expressions ──────────────────────────────────────────────
261
+
262
+ def cmd_watch(self, rest: str) -> None:
263
+ """WATCH <expr> — add/remove/list watch expressions."""
264
+ if not rest.strip():
265
+ if self._watches:
266
+ self.io.writeln(" Watch expressions:")
267
+ for w in self._watches:
268
+ self.io.writeln(f" {w}")
269
+ else:
270
+ self.io.writeln(" No watches set")
271
+ return
272
+ rest = rest.strip()
273
+ if rest.upper() == 'CLEAR':
274
+ self._watches.clear()
275
+ self.io.writeln("WATCHES CLEARED")
276
+ return
277
+ if rest in self._watches:
278
+ self._watches.remove(rest)
279
+ self.io.writeln(f"WATCH REMOVED: {rest}")
280
+ else:
281
+ self._watches.append(rest)
282
+ self.io.writeln(f"WATCHING: {rest}")
283
+
284
+ def _print_watches(self) -> None:
285
+ for w in self._watches:
286
+ try:
287
+ val = self._safe_eval(w)
288
+ self.io.writeln(f" {w} = {val}")
289
+ except Exception:
290
+ self.io.writeln(f" {w} = ?")
291
+
292
+ # ── Callbacks ──────────────────────────────────────────────────────
293
+
294
+ def _cf_on_measure(self, stmt: str, *, parsed=None) -> tuple[bool, ExecOutcome] | None:
295
+ if parsed is not None:
296
+ self._on_measure_target = parsed.target
297
+ else:
298
+ m = RE_ON_MEASURE.match(stmt)
299
+ if not m:
300
+ return None
301
+ self._on_measure_target = int(m.group(1))
302
+ return True, ExecResult.ADVANCE
303
+
304
+ def _cf_on_timer(self, stmt: str, *, parsed=None) -> tuple[bool, ExecOutcome] | None:
305
+ if parsed is not None:
306
+ self._on_timer_interval = float(parsed.interval)
307
+ self._on_timer_target = parsed.target
308
+ else:
309
+ m = RE_ON_TIMER.match(stmt)
310
+ if not m:
311
+ return None
312
+ self._on_timer_interval = float(m.group(1))
313
+ self._on_timer_target = int(m.group(2))
314
+ self._on_timer_last = time.time()
315
+ return True, ExecResult.ADVANCE
316
+
317
+ def _check_timer_callback(self, sorted_lines: list[int], ip: int) -> int | None:
318
+ """Check if ON TIMER callback should fire. Returns ip to jump to, or None."""
319
+ if self._on_timer_target is not None and self._on_timer_interval > 0:
320
+ now = time.time()
321
+ if now - self._on_timer_last >= self._on_timer_interval:
322
+ self._on_timer_last = now
323
+ self._gosub_stack.append(ip)
324
+ for i, ln in enumerate(sorted_lines):
325
+ if ln == self._on_timer_target:
326
+ return i
327
+ return None
qbasic_core/demos.py ADDED
@@ -0,0 +1,356 @@
1
+ """QBASIC built-in demo circuits."""
2
+
3
+
4
+ class DemoMixin:
5
+ """Built-in quantum computing demos.
6
+
7
+ Requires: TerminalProtocol — uses self.program, self.num_qubits,
8
+ self.shots, self.cmd_new(), self.cmd_run(), self.cmd_list(), self.cmd_locc().
9
+ """
10
+
11
+ def cmd_demo(self, name):
12
+ demos = {
13
+ 'BELL': self._demo_bell,
14
+ 'GHZ': self._demo_ghz,
15
+ 'TELEPORT': self._demo_teleport,
16
+ 'GROVER': self._demo_grover,
17
+ 'QFT': self._demo_qft,
18
+ 'DEUTSCH': self._demo_deutsch,
19
+ 'BERNSTEIN': self._demo_bernstein,
20
+ 'SUPERDENSE': self._demo_superdense,
21
+ 'RANDOM': self._demo_random,
22
+ 'STRESS': self._demo_stress,
23
+ 'LOCC-TELEPORT': self._demo_locc_teleport,
24
+ 'LOCC-COORD': self._demo_locc_coord,
25
+ }
26
+ name = name.upper().strip()
27
+ if not name or name == 'LIST':
28
+ self.io.writeln(" Available demos:")
29
+ for d in demos:
30
+ prefix = " (LOCC)" if d.startswith('LOCC') else ""
31
+ self.io.writeln(f" DEMO {d}{prefix}")
32
+ return
33
+ if name not in demos:
34
+ self.io.writeln(f"?UNKNOWN DEMO: {name}")
35
+ self.io.writeln(f" Try: DEMO LIST")
36
+ return
37
+ demos[name]()
38
+
39
+ def _demo_bell(self):
40
+ self.cmd_new()
41
+ self.num_qubits = 2
42
+ self.program = {
43
+ 10: "REM === Bell State ===",
44
+ 20: "REM The simplest entanglement. Two qubits, perfectly correlated.",
45
+ 30: "H 0",
46
+ 40: "CX 0,1",
47
+ 50: "MEASURE",
48
+ }
49
+ self.io.writeln("LOADED: Bell State (2 qubits)")
50
+ self.cmd_list()
51
+ self.cmd_run()
52
+
53
+ def _demo_ghz(self):
54
+ self.cmd_new()
55
+ n = min(self.num_qubits, 8)
56
+ self.num_qubits = n
57
+ self.program = {
58
+ 10: "REM === GHZ State ===",
59
+ 20: f"REM {n}-qubit Greenberger-Horne-Zeilinger state",
60
+ 30: "REM All qubits entangled: 50% all-zeros, 50% all-ones.",
61
+ 40: "REM Einstein called this 'spooky action at a distance.'",
62
+ 50: "H 0",
63
+ }
64
+ line = 60
65
+ for i in range(1, n):
66
+ self.program[line] = f"CX 0,{i}"
67
+ line += 10
68
+ self.program[line] = "MEASURE"
69
+ self.io.writeln(f"LOADED: GHZ State ({n} qubits)")
70
+ self.cmd_list()
71
+ self.cmd_run()
72
+
73
+ def _demo_teleport(self):
74
+ self.cmd_new()
75
+ self.num_qubits = 3
76
+ self.program = {
77
+ 10: "REM === Quantum Teleportation (circuit only) ===",
78
+ 20: "REM Qubit 0: state to teleport (prepared as |+>)",
79
+ 30: "REM Qubit 1-2: entangled Bell pair (the 'channel')",
80
+ 40: "REM Shows the entangling stage of teleportation.",
81
+ 50: "REM Classical correction requires mid-circuit measurement",
82
+ 60: "REM with feedforward, which needs LOCC mode.",
83
+ 70: "REM >>> For full teleportation: DEMO LOCC-TELEPORT <<<",
84
+ 80: "REM",
85
+ 90: "REM Prepare state to teleport (|+> on qubit 0)",
86
+ 100: "H 0",
87
+ 110: "REM Create Bell pair on qubits 1,2",
88
+ 120: "H 1",
89
+ 130: "CX 1,2",
90
+ 140: "REM Teleportation circuit (without classical correction)",
91
+ 150: "CX 0,1",
92
+ 160: "H 0",
93
+ 170: "MEASURE",
94
+ }
95
+ self.io.writeln("LOADED: Quantum Teleportation — circuit stage (3 qubits)")
96
+ self.io.writeln(" Without correction: uniform over all 8 outcomes.")
97
+ self.io.writeln(" For full protocol with correction: DEMO LOCC-TELEPORT")
98
+ self.cmd_list()
99
+ self.cmd_run()
100
+
101
+ def _demo_grover(self):
102
+ self.cmd_new()
103
+ self.num_qubits = 3
104
+ self.shots = 1024
105
+ self.program = {
106
+ 10: "REM === Grover's Search Algorithm ===",
107
+ 20: "REM Searching for |101> among 8 states",
108
+ 30: "REM Classically: ~4 queries. Quantumly: 2 iterations, ~95%.",
109
+ 40: "REM Quadratic speedup over classical unstructured search.",
110
+ 50: "REM",
111
+ 60: "REM Superposition",
112
+ 70: "H 0 : H 1 : H 2",
113
+ 80: "REM",
114
+ 90: "REM === Grover iteration 1 ===",
115
+ 100: "REM Oracle: flip phase of |101> (X on q1, CCZ, undo X)",
116
+ 110: "X 1",
117
+ 120: "H 2 : CCX 0,1,2 : H 2",
118
+ 130: "X 1",
119
+ 140: "REM Diffusion: 2|s><s| - I",
120
+ 150: "H 0 : H 1 : H 2",
121
+ 160: "X 0 : X 1 : X 2",
122
+ 170: "H 2 : CCX 0,1,2 : H 2",
123
+ 180: "X 0 : X 1 : X 2",
124
+ 190: "H 0 : H 1 : H 2",
125
+ 200: "REM",
126
+ 210: "REM === Grover iteration 2 ===",
127
+ 220: "X 1",
128
+ 230: "H 2 : CCX 0,1,2 : H 2",
129
+ 240: "X 1",
130
+ 250: "H 0 : H 1 : H 2",
131
+ 260: "X 0 : X 1 : X 2",
132
+ 270: "H 2 : CCX 0,1,2 : H 2",
133
+ 280: "X 0 : X 1 : X 2",
134
+ 290: "H 0 : H 1 : H 2",
135
+ 300: "REM",
136
+ 310: "MEASURE",
137
+ }
138
+ self.io.writeln("LOADED: Grover's Search (3 qubits, target=|101>)")
139
+ self.cmd_list()
140
+ self.cmd_run()
141
+
142
+ def _demo_qft(self):
143
+ self.cmd_new()
144
+ self.num_qubits = 4
145
+ self.program = {
146
+ 10: "REM === Quantum Fourier Transform ===",
147
+ 20: "REM The quantum analog of the discrete Fourier transform.",
148
+ 30: "REM Exponentially faster than classical FFT.",
149
+ 40: "REM QFT is typically used as a subroutine (phase info lost on measure).",
150
+ 50: "REM",
151
+ 60: "REM Prepare input state |5> = |0101>",
152
+ 70: "X 0 : X 2",
153
+ 80: "REM",
154
+ 90: "REM QFT on 4 qubits",
155
+ 100: "H 3",
156
+ 110: "CP PI/2, 2, 3",
157
+ 120: "CP PI/4, 1, 3",
158
+ 130: "CP PI/8, 0, 3",
159
+ 140: "H 2",
160
+ 150: "CP PI/2, 1, 2",
161
+ 160: "CP PI/4, 0, 2",
162
+ 170: "H 1",
163
+ 180: "CP PI/2, 0, 1",
164
+ 190: "H 0",
165
+ 200: "REM Swap for bit reversal",
166
+ 210: "SWAP 0,3",
167
+ 220: "SWAP 1,2",
168
+ 230: "MEASURE",
169
+ }
170
+ self.io.writeln("LOADED: QFT on |0101> (4 qubits)")
171
+ self.cmd_list()
172
+ self.cmd_run()
173
+
174
+ def _demo_deutsch(self):
175
+ self.cmd_new()
176
+ self.num_qubits = 2
177
+ self.program = {
178
+ 10: "REM === Deutsch-Jozsa Algorithm ===",
179
+ 20: "REM Determines if a function is constant or balanced",
180
+ 30: "REM in ONE query. Classically needs 2.",
181
+ 40: "REM Published 1992. The first to demonstrate quantum advantage.",
182
+ 50: "REM",
183
+ 60: "REM Oracle qubit in |->",
184
+ 70: "X 1",
185
+ 80: "H 0 : H 1",
186
+ 90: "REM Oracle (balanced function: f(x) = x)",
187
+ 100: "CX 0,1",
188
+ 110: "REM Interfere and measure",
189
+ 120: "H 0",
190
+ 130: "MEASURE",
191
+ }
192
+ self.io.writeln("LOADED: Deutsch-Jozsa (2 qubits, balanced oracle)")
193
+ self.io.writeln(" Expect: qubit 0 = 1 (balanced)")
194
+ self.cmd_list()
195
+ self.cmd_run()
196
+
197
+ def _demo_bernstein(self):
198
+ self.cmd_new()
199
+ self.num_qubits = 5
200
+ self.program = {
201
+ 10: "REM === Bernstein-Vazirani Algorithm ===",
202
+ 20: "REM Finds a hidden bit string s in ONE query.",
203
+ 30: "REM Secret: s = 1011 (4 bits, display order q3q2q1q0)",
204
+ 40: "REM Classically you'd need 4 queries. Quantum: 1.",
205
+ 50: "REM",
206
+ 60: "REM Ancilla in |->",
207
+ 70: "X 4",
208
+ 80: "H 0 : H 1 : H 2 : H 3 : H 4",
209
+ 90: "REM Oracle: CX from each bit where s=1",
210
+ 100: "CX 0,4",
211
+ 110: "CX 1,4",
212
+ 120: "CX 3,4",
213
+ 130: "REM Interfere",
214
+ 140: "H 0 : H 1 : H 2 : H 3",
215
+ 150: "MEASURE",
216
+ }
217
+ self.io.writeln("LOADED: Bernstein-Vazirani (5 qubits, secret=1011)")
218
+ self.io.writeln(" Expect: measurement shows ...1011 (q3q2q1q0)")
219
+ self.cmd_list()
220
+ self.cmd_run()
221
+
222
+ def _demo_superdense(self):
223
+ self.cmd_new()
224
+ self.num_qubits = 2
225
+ self.program = {
226
+ 10: "REM === Superdense Coding ===",
227
+ 20: "REM Send 2 classical bits using 1 qubit.",
228
+ 30: "REM Encoding: 00->I, 01->X, 10->Z, 11->ZX (=iY)",
229
+ 40: "REM Sending message '11'",
230
+ 50: "REM",
231
+ 60: "REM Create Bell pair",
232
+ 70: "H 0",
233
+ 80: "CX 0,1",
234
+ 90: "REM Encode '11': apply Z then X to qubit 0",
235
+ 100: "Z 0",
236
+ 110: "X 0",
237
+ 120: "REM Decode: reverse Bell circuit",
238
+ 130: "CX 0,1",
239
+ 140: "H 0",
240
+ 150: "MEASURE",
241
+ }
242
+ self.io.writeln("LOADED: Superdense Coding (message='11')")
243
+ self.io.writeln(" Expect: |11> with high probability")
244
+ self.cmd_list()
245
+ self.cmd_run()
246
+
247
+ def _demo_random(self):
248
+ self.cmd_new()
249
+ n = min(self.num_qubits, 8)
250
+ self.num_qubits = n
251
+ self.shots = 1
252
+ self.program = {
253
+ 10: "REM === Quantum Random Number Generator ===",
254
+ 20: f"REM {n} qubits = {n}-bit truly random number",
255
+ 30: "REM (as random as a simulator's PRNG allows)",
256
+ }
257
+ line = 40
258
+ for i in range(n):
259
+ self.program[line] = f"H {i}"
260
+ line += 10
261
+ self.program[line] = "MEASURE"
262
+ self.io.writeln(f"LOADED: Quantum RNG ({n} bits)")
263
+ self.cmd_list()
264
+ self.cmd_run()
265
+ self.shots = 1024
266
+
267
+ def _demo_stress(self):
268
+ self.cmd_new()
269
+ n = 20
270
+ self.num_qubits = n
271
+ self.program = {
272
+ 10: f"REM === {n}-Qubit Stress Test ===",
273
+ 20: f"REM H on all {n} qubits + nearest-neighbor CX chain",
274
+ 30: f"REM Creates a highly entangled {n}-qubit state",
275
+ }
276
+ line = 40
277
+ for i in range(n):
278
+ self.program[line] = f"H {i}"
279
+ line += 10
280
+ for i in range(n - 1):
281
+ self.program[line] = f"CX {i},{i+1}"
282
+ line += 10
283
+ for i in range(n):
284
+ self.program[line] = f"RZ PI/4,{i}"
285
+ line += 10
286
+ for i in range(0, n - 1, 2):
287
+ self.program[line] = f"CX {i},{i+1}"
288
+ line += 10
289
+ self.program[line] = "MEASURE"
290
+ self.io.writeln(f"LOADED: {n}-Qubit Stress Test")
291
+ self.cmd_run()
292
+
293
+ def _demo_locc_teleport(self):
294
+ """Quantum teleportation across A/B boundary (JOINT mode)."""
295
+ self.cmd_new()
296
+ self.cmd_locc('JOINT 3 3')
297
+ self.shots = 1024
298
+ self.program = {
299
+ 10: "REM === LOCC Teleportation ===",
300
+ 20: "REM Alice (A) teleports qubit 0 to Bob (B) qubit 0",
301
+ 30: "REM Pre-shared Bell pair: A[2] <-> B[0]",
302
+ 40: "REM",
303
+ 50: "REM Prepare state to teleport: |+> on A[0]",
304
+ 60: "@A H 0",
305
+ 70: "REM Create shared entanglement",
306
+ 80: "SHARE A 2, B 0",
307
+ 90: "REM",
308
+ 100: "REM === Teleportation protocol ===",
309
+ 110: "REM Alice entangles her data qubit with her half of the pair",
310
+ 120: "@A CX 0, 2",
311
+ 130: "@A H 0",
312
+ 140: "REM Alice measures and sends classical bits to Bob",
313
+ 150: "SEND A 0 -> m0",
314
+ 160: "SEND A 2 -> m1",
315
+ 170: "REM Bob applies corrections based on Alice's results",
316
+ 180: "IF m1 THEN @B X 0",
317
+ 190: "IF m0 THEN @B Z 0",
318
+ 200: "REM Bob's qubit 0 now holds Alice's original state",
319
+ 210: "MEASURE",
320
+ }
321
+ self.io.writeln("LOADED: LOCC Teleportation (JOINT 3+3)")
322
+ self.io.writeln(" Alice sends |+> to Bob. Expect Bob's qubit ~ 50/50.")
323
+ self.cmd_list()
324
+ self.cmd_run()
325
+
326
+ def _demo_locc_coord(self):
327
+ """Classical coordination between independent registers (SPLIT mode)."""
328
+ self.cmd_new()
329
+ self.cmd_locc('SPLIT 4 4')
330
+ self.shots = 1024
331
+ self.program = {
332
+ 10: "REM === LOCC Classical Coordination ===",
333
+ 20: "REM Two independent quantum processors sharing classical bits",
334
+ 30: "REM Alice generates a random 2-bit key, Bob copies it",
335
+ 40: "REM",
336
+ 50: "REM Alice: generate random bits",
337
+ 60: "@A H 0 : @A H 1",
338
+ 70: "SEND A 0 -> k0",
339
+ 80: "SEND A 1 -> k1",
340
+ 90: "REM Bob: set qubits to match Alice's key",
341
+ 100: "IF k0 THEN @B X 0",
342
+ 110: "IF k1 THEN @B X 1",
343
+ 120: "REM Both sides now agree on a 2-bit key",
344
+ 130: "REM Alice uses her key to prepare an entangled state",
345
+ 140: "@A H 2",
346
+ 150: "@A CX 2,3",
347
+ 160: "REM Bob does the same — they independently create matching states",
348
+ 170: "@B H 2",
349
+ 180: "@B CX 2,3",
350
+ 190: "MEASURE",
351
+ }
352
+ self.io.writeln("LOADED: LOCC Classical Coordination (SPLIT 4+4)")
353
+ self.io.writeln(" Alice and Bob share a random key, then prepare matching states.")
354
+ self.cmd_list()
355
+ self.cmd_run()
356
+