zena-sdk 0.1.4__cp38-abi3-win_amd64.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 (76) hide show
  1. qsys/__init__.py +31 -0
  2. qsys/__pycache__/__init__.cpython-313.pyc +0 -0
  3. qsys/backends/base.py +39 -0
  4. qsys/backends/local5q.py +8 -0
  5. qsys/circuit/__init__.py +20 -0
  6. qsys/circuit/__pycache__/__init__.cpython-313.pyc +0 -0
  7. qsys/circuit/__pycache__/quantum_circuit.cpython-313.pyc +0 -0
  8. qsys/circuit/quantum_circuit.py +103 -0
  9. qsys/cli/__init__.py +2 -0
  10. qsys/cli/io_cli.py +45 -0
  11. qsys/errors/__init__.py +32 -0
  12. qsys/errors/__pycache__/__init__.cpython-313.pyc +0 -0
  13. qsys/io/__init__.py +21 -0
  14. qsys/io/json_io.py +84 -0
  15. qsys/io/text_io.py +58 -0
  16. qsys/ir/__init__.py +1 -0
  17. qsys/ir/__pycache__/__init__.cpython-313.pyc +0 -0
  18. qsys/ir/__pycache__/types.cpython-313.pyc +0 -0
  19. qsys/ir/from_payload.py +27 -0
  20. qsys/ir/types.py +9 -0
  21. qsys/logging.py +14 -0
  22. qsys/runtime/__init__.py +4 -0
  23. qsys/runtime/__pycache__/__init__.cpython-313.pyc +0 -0
  24. qsys/runtime/__pycache__/execute.cpython-313.pyc +0 -0
  25. qsys/runtime/execute.py +155 -0
  26. qsys/target.py +44 -0
  27. qsys/targets.py +63 -0
  28. qsys/transpiler/__init__.py +6 -0
  29. qsys/transpiler/basis.py +39 -0
  30. qsys/transpiler/opt1q.py +101 -0
  31. qsys/transpiler/passes.py +57 -0
  32. qsys/transpiler/routing.py +136 -0
  33. qsys/transpiler/validate.py +132 -0
  34. qsys/viz/__init__.py +1 -0
  35. qsys/viz/text_drawer.py +89 -0
  36. simulator_statevector/__init__.py +5 -0
  37. simulator_statevector/__pycache__/__init__.cpython-313.pyc +0 -0
  38. simulator_statevector/simulator_statevector.pyd +0 -0
  39. zena/__init__.py +7 -0
  40. zena/__pycache__/__init__.cpython-312.pyc +0 -0
  41. zena/__pycache__/__init__.cpython-313.pyc +0 -0
  42. zena/__pycache__/execute.cpython-312.pyc +0 -0
  43. zena/__pycache__/execute.cpython-313.pyc +0 -0
  44. zena/circuit/__init__.py +2 -0
  45. zena/circuit/__pycache__/__init__.cpython-312.pyc +0 -0
  46. zena/circuit/__pycache__/__init__.cpython-313.pyc +0 -0
  47. zena/circuit/__pycache__/quantum_circuit.cpython-312.pyc +0 -0
  48. zena/circuit/__pycache__/quantum_circuit.cpython-313.pyc +0 -0
  49. zena/circuit/__pycache__/register.cpython-312.pyc +0 -0
  50. zena/circuit/__pycache__/register.cpython-313.pyc +0 -0
  51. zena/circuit/quantum_circuit.py +218 -0
  52. zena/circuit/register.py +28 -0
  53. zena/compiler/__init__.py +72 -0
  54. zena/compiler/__pycache__/__init__.cpython-312.pyc +0 -0
  55. zena/compiler/__pycache__/__init__.cpython-313.pyc +0 -0
  56. zena/dist/zena_sdk-0.1.0-py3-none-any.whl +0 -0
  57. zena/dist/zena_sdk-0.1.0.tar.gz +0 -0
  58. zena/execute.py +35 -0
  59. zena/providers/__init__.py +5 -0
  60. zena/providers/__pycache__/__init__.cpython-312.pyc +0 -0
  61. zena/providers/__pycache__/__init__.cpython-313.pyc +0 -0
  62. zena/providers/__pycache__/aer.cpython-312.pyc +0 -0
  63. zena/providers/__pycache__/aer.cpython-313.pyc +0 -0
  64. zena/providers/__pycache__/backend.cpython-312.pyc +0 -0
  65. zena/providers/__pycache__/backend.cpython-313.pyc +0 -0
  66. zena/providers/__pycache__/job.cpython-312.pyc +0 -0
  67. zena/providers/__pycache__/job.cpython-313.pyc +0 -0
  68. zena/providers/aer.py +71 -0
  69. zena/providers/backend.py +18 -0
  70. zena/providers/job.py +24 -0
  71. zena/visualization/__init__.py +28 -0
  72. zena/visualization/__pycache__/__init__.cpython-312.pyc +0 -0
  73. zena/visualization/__pycache__/__init__.cpython-313.pyc +0 -0
  74. zena_sdk-0.1.4.dist-info/METADATA +70 -0
  75. zena_sdk-0.1.4.dist-info/RECORD +76 -0
  76. zena_sdk-0.1.4.dist-info/WHEEL +4 -0
@@ -0,0 +1,132 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from ..backends.base import Backend
6
+ from ..errors import ValidationError
7
+ from ..ir.types import Instruction
8
+
9
+ # Spec for supported ops in our current IR
10
+ # name -> (num_qubits, num_params, allows_clbits)
11
+ GATE_SPECS = {
12
+ "x": (1, 0, False),
13
+ "sx": (1, 0, False),
14
+ "rz": (1, 1, False),
15
+ "cx": (2, 0, False),
16
+ "measure": (1, 0, True), # (q, c) pair
17
+ }
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class ValidationReport:
22
+ ok: bool
23
+ needs_routing: (
24
+ bool # True if there exists a CX that is not directly allowed by coupling map
25
+ )
26
+ messages: list[str]
27
+
28
+
29
+ def _check_gate_shape(inst: Instruction) -> None:
30
+ name = inst.name
31
+ if name not in GATE_SPECS:
32
+ raise ValidationError(f"Unknown operation: {name}")
33
+
34
+ q_needed, p_needed, allow_c = GATE_SPECS[name]
35
+
36
+ if len(inst.qubits) != q_needed:
37
+ raise ValidationError(
38
+ f"Gate '{name}' expects {q_needed} qubit(s), got {len(inst.qubits)}: {inst.qubits}"
39
+ )
40
+
41
+ if len(inst.params) != p_needed:
42
+ raise ValidationError(
43
+ f"Gate '{name}' expects {p_needed} parameter(s), got {len(inst.params)}: {inst.params}"
44
+ )
45
+
46
+ if inst.clbits is not None and not allow_c:
47
+ raise ValidationError(
48
+ f"Gate '{name}' does not take classical bits (got {inst.clbits})"
49
+ )
50
+
51
+ if inst.clbits is None and allow_c:
52
+ # measure must provide clbits (we encode them in Instruction.clbits)
53
+ raise ValidationError("Measure must specify destination classical bit(s)")
54
+
55
+
56
+ def _check_index_bounds(inst: Instruction, n_qubits: int, n_clbits: int) -> None:
57
+ # Qubit indices must be within 0..n_qubits-1 and distinct for multi-qubit ops
58
+ for q in inst.qubits:
59
+ if q < 0 or q >= n_qubits:
60
+ raise ValidationError(f"Qubit index out of range in op {inst}: q={q}")
61
+
62
+ if len(inst.qubits) != len(set(inst.qubits)):
63
+ raise ValidationError(f"Repeated qubit index in op {inst}")
64
+
65
+ # Classical indices (if any) must be within 0..n_clbits-1 and distinct
66
+ if inst.clbits is not None:
67
+ for c in inst.clbits:
68
+ if c < 0 or c >= n_clbits:
69
+ raise ValidationError(
70
+ f"Classical bit index out of range in op {inst}: c={c}"
71
+ )
72
+ if len(inst.clbits) != len(set(inst.clbits)):
73
+ raise ValidationError(f"Repeated classical bit index in op {inst}")
74
+
75
+
76
+ def _cx_needs_routing(
77
+ control: int, target: int, coupling_map: list[tuple[int, int]]
78
+ ) -> bool:
79
+ """Return True if (control,target) is not directly supported by coupling_map (undirected)."""
80
+ if not coupling_map:
81
+ # If backend provides no map, assume fully connected (dev convenience)
82
+ return False
83
+ return (control, target) not in coupling_map and (
84
+ target,
85
+ control,
86
+ ) not in coupling_map
87
+
88
+
89
+ def validate(circuit, backend: Backend) -> ValidationReport:
90
+ """
91
+ Validate a circuit against basic rules and the backend's size/basis.
92
+
93
+ - Checks gate names, arity, parameter counts.
94
+ - Checks qubit/clbit index ranges and duplicates.
95
+ - Checks that every op name is in backend.target.basis_gates.
96
+ - Does NOT fail for CX connectivity; instead marks needs_routing=True when a CX
97
+ doesn't match the coupling map (routing pass will handle it in 5.3).
98
+ """
99
+ msgs: list[str] = []
100
+ n_qubits = circuit.n_qubits
101
+ n_clbits = getattr(circuit, "n_clbits", 0)
102
+ tgt = backend.target
103
+
104
+ if n_qubits > tgt.n_qubits:
105
+ raise ValidationError(
106
+ f"Circuit uses {n_qubits} qubits but backend supports only {tgt.n_qubits}"
107
+ )
108
+
109
+ needs_routing = False
110
+ basis = set(tgt.basis_gates)
111
+
112
+ for inst in circuit.instructions:
113
+ # Name is supported by our IR and by backend basis
114
+ _check_gate_shape(inst)
115
+ if inst.name not in basis:
116
+ raise ValidationError(
117
+ f"Gate '{inst.name}' not in backend basis_gates: {sorted(basis)}"
118
+ )
119
+
120
+ # Index ranges / duplicates
121
+ _check_index_bounds(inst, n_qubits, n_clbits)
122
+
123
+ # Connectivity hint (don’t fail; mark for routing)
124
+ if inst.name == "cx":
125
+ c, t = inst.qubits
126
+ if _cx_needs_routing(c, t, tgt.coupling_map):
127
+ needs_routing = True
128
+
129
+ if needs_routing:
130
+ msgs.append("Routing required: at least one CX not on a coupling edge.")
131
+
132
+ return ValidationReport(ok=True, needs_routing=needs_routing, messages=msgs)
qsys/viz/__init__.py ADDED
@@ -0,0 +1 @@
1
+ # viz package
@@ -0,0 +1,89 @@
1
+ from __future__ import annotations
2
+ from typing import List
3
+ from ..ir.types import Instruction
4
+
5
+ # Conventions
6
+ # - Qubits are rendered top (q0) → bottom (q{n-1}) for readability.
7
+ # - Columns advance in time, one column per instruction (simple MVP).
8
+ # - Supported ops: x, sx, rz(theta), cx, measure.
9
+ # - For measure, we annotate the destination classical bit as M[c].
10
+ # - Little-endian execution still applies (this is only visualization).
11
+
12
+ CELL_W = 5 # width per column (room for labels like "rz(π/2)" short form later)
13
+
14
+
15
+ def _empty_canvas(n_qubits: int, n_cols: int) -> List[List[str]]:
16
+ rows = []
17
+ for _ in range(n_qubits):
18
+ row = ["─" * CELL_W for _ in range(n_cols)]
19
+ rows.append(row)
20
+ return rows
21
+
22
+
23
+ def _place_label(cell: str, label: str) -> str:
24
+ # Center label within CELL_W using monospaced assumptions
25
+ pad = max(0, CELL_W - len(label))
26
+ left = pad // 2
27
+ right = pad - left
28
+ return " " * left + label + " " * right
29
+
30
+
31
+ def _rz_label(theta: float) -> str:
32
+ # Keep it compact; 3 significant digits
33
+ return f"rz({theta:.3g})"
34
+
35
+
36
+ def draw_ascii(n_qubits: int, instructions: List[Instruction]) -> str:
37
+ n_cols = max(1, len(instructions))
38
+ canvas = _empty_canvas(n_qubits, n_cols)
39
+
40
+ # Helper to map logical qubit index to row (q0 at top)
41
+ def row_of(q: int) -> int:
42
+ return q # q0 at row 0, q1 at row 1, ...
43
+
44
+ for col, inst in enumerate(instructions):
45
+ name, qs, ps, cs = inst.name, inst.qubits, inst.params, inst.clbits
46
+
47
+ if name in ("x", "sx", "rz", "measure"):
48
+ q = qs[0]
49
+ r = row_of(q)
50
+ if name == "x":
51
+ canvas[r][col] = _place_label(canvas[r][col], "X")
52
+ elif name == "sx":
53
+ canvas[r][col] = _place_label(canvas[r][col], "SX")
54
+ elif name == "rz":
55
+ canvas[r][col] = _place_label(canvas[r][col], _rz_label(float(ps[0])))
56
+ elif name == "measure":
57
+ lbl = "M" if cs is None or len(cs) == 0 else f"M[{cs[0]}]"
58
+ canvas[r][col] = _place_label(canvas[r][col], lbl)
59
+ # leave other rows in this column as wires
60
+ continue
61
+
62
+ if name == "cx":
63
+ c, t = qs
64
+ rc = row_of(c)
65
+ rt = row_of(t)
66
+ top, bot = sorted((rc, rt))
67
+ # Place control and target symbols
68
+ canvas[rc][col] = _place_label(canvas[rc][col], "●") # control
69
+ canvas[rt][col] = _place_label(
70
+ canvas[rt][col], "X"
71
+ ) # target (CNOT symbolized as X)
72
+ # Draw vertical wire between them in this column
73
+ for r in range(top + 1, bot):
74
+ canvas[r][col] = _place_label(canvas[r][col], "│")
75
+ continue
76
+
77
+ # Unknown op: show as name
78
+ for q in qs:
79
+ r = row_of(q)
80
+ canvas[r][col] = _place_label(canvas[r][col], name.upper())
81
+
82
+ # Build header with qubit labels
83
+ lines: List[str] = []
84
+ for q in range(n_qubits):
85
+ label = f"q{q}: "
86
+ line = label + "".join(canvas[q])
87
+ lines.append(line)
88
+
89
+ return "\n".join(lines)
@@ -0,0 +1,5 @@
1
+ from .simulator_statevector import *
2
+
3
+ __doc__ = simulator_statevector.__doc__
4
+ if hasattr(simulator_statevector, "__all__"):
5
+ __all__ = simulator_statevector.__all__
zena/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ from .circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
2
+ from .providers.aer import Aer
3
+ from .execute import execute
4
+ from .visualization import plot_histogram
5
+ from .compiler import transpile
6
+
7
+ __version__ = "0.1.0"
Binary file
Binary file
@@ -0,0 +1,2 @@
1
+ from .quantum_circuit import QuantumCircuit
2
+ from .register import QuantumRegister, ClassicalRegister
@@ -0,0 +1,218 @@
1
+ """
2
+ QuantumCircuit class mimicking Qiskit's API, delegating to qsys.
3
+ """
4
+ from typing import Union, List, Optional
5
+ from .register import QuantumRegister, ClassicalRegister
6
+
7
+ # Import the core composer from existing codebase
8
+ # We treat qsys as the internal engine
9
+ try:
10
+ from qsys.circuit.quantum_circuit import QuantumCircuit as QSysCircuit
11
+ except ImportError as e:
12
+ # Fallback/Mock for development if qsys is not in path
13
+ print(f"DEBUG: Failed to import qsys: {e}")
14
+ QSysCircuit = None
15
+
16
+ class QuantumCircuit:
17
+ """
18
+ QuantumCircuit adaptable to Zena SDK.
19
+ """
20
+ def __init__(self, *regs, name: Optional[str] = None):
21
+ self.name = name
22
+ self.qregs = []
23
+ self.cregs = []
24
+ self._qubits = []
25
+ self._clbits = []
26
+
27
+ # Parse arguments similar to Qiskit (int or Register)
28
+ if len(regs) == 0:
29
+ # Empty circuit
30
+ pass
31
+ elif all(isinstance(r, int) for r in regs):
32
+ # Case: QuantumCircuit(n_qubits, n_clbits)
33
+ n_qubits = regs[0]
34
+ n_clbits = regs[1] if len(regs) > 1 else 0
35
+ self.add_register(QuantumRegister(n_qubits, 'q'))
36
+ if n_clbits > 0:
37
+ self.add_register(ClassicalRegister(n_clbits, 'c'))
38
+ else:
39
+ # Case: QuantumCircuit(qreg, creg)
40
+ for r in regs:
41
+ if isinstance(r, (QuantumRegister, ClassicalRegister)):
42
+ self.add_register(r)
43
+ else:
44
+ raise TypeError("Arguments must be integers or Registers")
45
+
46
+ # Initialize the underlying qsys Core Circuit
47
+ if QSysCircuit:
48
+ self._core_circuit = QSysCircuit(len(self._qubits), len(self._clbits))
49
+ else:
50
+ self._core_circuit = None
51
+ print("Warning: qsys.circuit not found. Core delegation disabled.")
52
+
53
+ def add_register(self, register: Union[QuantumRegister, ClassicalRegister]):
54
+ if isinstance(register, QuantumRegister):
55
+ self.qregs.append(register)
56
+ # Flatten qubits mapping (simplistic for now)
57
+ start_index = len(self._qubits)
58
+ self._qubits.extend([i for i in range(start_index, start_index + register.size)])
59
+ elif isinstance(register, ClassicalRegister):
60
+ self.cregs.append(register)
61
+ start_index = len(self._clbits)
62
+ self._clbits.extend([i for i in range(start_index, start_index + register.size)])
63
+
64
+ def h(self, qubit):
65
+ """Apply Hadamard gate."""
66
+ q_idx = self._resolve_index(qubit)
67
+ if self._core_circuit:
68
+ self._core_circuit.h(q_idx)
69
+ return self
70
+
71
+ def x(self, qubit):
72
+ """Apply Pauli-X gate."""
73
+ q_idx = self._resolve_index(qubit)
74
+ if self._core_circuit:
75
+ self._core_circuit.x(q_idx)
76
+ return self
77
+
78
+ def y(self, qubit):
79
+ """Apply Pauli-Y gate."""
80
+ q_idx = self._resolve_index(qubit)
81
+ if self._core_circuit:
82
+ # Note: qsys uses string name 'y' for Instruction, which execute.py handles
83
+ from qsys.ir.types import Instruction
84
+ self._core_circuit._instructions.append(Instruction(name="y", qubits=(q_idx,)))
85
+ return self
86
+
87
+ def z(self, qubit):
88
+ """Apply Pauli-Z gate."""
89
+ q_idx = self._resolve_index(qubit)
90
+ if self._core_circuit:
91
+ from qsys.ir.types import Instruction
92
+ self._core_circuit._instructions.append(Instruction(name="z", qubits=(q_idx,)))
93
+ return self
94
+
95
+ def s(self, qubit):
96
+ """Apply S gate."""
97
+ q_idx = self._resolve_index(qubit)
98
+ if self._core_circuit:
99
+ from qsys.ir.types import Instruction
100
+ self._core_circuit._instructions.append(Instruction(name="s", qubits=(q_idx,)))
101
+ return self
102
+
103
+ def sdg(self, qubit):
104
+ """Apply S-dagger gate."""
105
+ q_idx = self._resolve_index(qubit)
106
+ if self._core_circuit:
107
+ from qsys.ir.types import Instruction
108
+ self._core_circuit._instructions.append(Instruction(name="sdg", qubits=(q_idx,)))
109
+ return self
110
+
111
+ def t(self, qubit):
112
+ """Apply T gate."""
113
+ q_idx = self._resolve_index(qubit)
114
+ if self._core_circuit:
115
+ from qsys.ir.types import Instruction
116
+ self._core_circuit._instructions.append(Instruction(name="t", qubits=(q_idx,)))
117
+ return self
118
+
119
+ def tdg(self, qubit):
120
+ """Apply T-dagger gate."""
121
+ q_idx = self._resolve_index(qubit)
122
+ if self._core_circuit:
123
+ from qsys.ir.types import Instruction
124
+ self._core_circuit._instructions.append(Instruction(name="tdg", qubits=(q_idx,)))
125
+ return self
126
+
127
+ def sx(self, qubit):
128
+ """Apply sqrt-X gate."""
129
+ q_idx = self._resolve_index(qubit)
130
+ if self._core_circuit:
131
+ self._core_circuit.sx(q_idx)
132
+ return self
133
+
134
+ def rx(self, theta, qubit):
135
+ """Apply RX gate."""
136
+ q_idx = self._resolve_index(qubit)
137
+ if self._core_circuit:
138
+ from qsys.ir.types import Instruction
139
+ self._core_circuit._instructions.append(
140
+ Instruction(name="rx", qubits=(q_idx,), params=(float(theta),))
141
+ )
142
+ return self
143
+
144
+ def ry(self, theta, qubit):
145
+ """Apply RY gate."""
146
+ q_idx = self._resolve_index(qubit)
147
+ if self._core_circuit:
148
+ from qsys.ir.types import Instruction
149
+ self._core_circuit._instructions.append(
150
+ Instruction(name="ry", qubits=(q_idx,), params=(float(theta),))
151
+ )
152
+ return self
153
+
154
+ def rz(self, theta, qubit):
155
+ """Apply RZ gate."""
156
+ q_idx = self._resolve_index(qubit)
157
+ if self._core_circuit:
158
+ self._core_circuit.rz(q_idx, theta)
159
+ return self
160
+
161
+ def cx(self, control_qubit, target_qubit):
162
+ """Apply CNOT gate."""
163
+ c_idx = self._resolve_index(control_qubit)
164
+ t_idx = self._resolve_index(target_qubit)
165
+ if self._core_circuit:
166
+ self._core_circuit.cx(c_idx, t_idx)
167
+ return self
168
+
169
+ def swap(self, qubit1, qubit2):
170
+ """Apply SWAP gate."""
171
+ q1_idx = self._resolve_index(qubit1)
172
+ q2_idx = self._resolve_index(qubit2)
173
+ if self._core_circuit:
174
+ from qsys.ir.types import Instruction
175
+ self._core_circuit._instructions.append(Instruction(name="swap", qubits=(q1_idx, q2_idx)))
176
+ return self
177
+
178
+ def measure(self, qubits, clbits):
179
+ """Measure quantum bits into classical bits."""
180
+ if isinstance(qubits, int):
181
+ qubits = [qubits]
182
+ if isinstance(clbits, int):
183
+ clbits = [clbits]
184
+
185
+ if len(qubits) != len(clbits):
186
+ raise ValueError("Number of qubits and classical bits must match.")
187
+
188
+ for q, c in zip(qubits, clbits):
189
+ q_idx = self._resolve_index(q)
190
+ c_idx = self._resolve_cbit_index(c)
191
+ if self._core_circuit:
192
+ self._core_circuit.measure(q_idx, c_idx)
193
+ return self
194
+
195
+ def draw(self, output='text'):
196
+ """Draw the circuit."""
197
+ if self._core_circuit:
198
+ return self._core_circuit.draw(mode=output)
199
+ return "Core circuit not initialized."
200
+
201
+ def _resolve_index(self, qubit) -> int:
202
+ """
203
+ Resolve user input (int or bit object) to flat integer index for qsys.
204
+ For now, we assume user passes integers as indices.
205
+ """
206
+ # TODO: Support Qubit object (e.g. qreg[0])
207
+ if isinstance(qubit, int):
208
+ if qubit < 0 or qubit >= len(self._qubits):
209
+ raise IndexError(f"Qubit index {qubit} out of range.")
210
+ return qubit
211
+ raise TypeError("Qubit must be an integer index for now.")
212
+
213
+ def _resolve_cbit_index(self, cbit) -> int:
214
+ if isinstance(cbit, int):
215
+ if cbit < 0 or cbit >= len(self._clbits):
216
+ raise IndexError(f"Clbit index {cbit} out of range.")
217
+ return cbit
218
+ raise TypeError("Clbit must be an integer index for now.")
@@ -0,0 +1,28 @@
1
+ """
2
+ Quantum and Classical Registers.
3
+ """
4
+ from typing import Optional
5
+
6
+ class Register:
7
+ """Base class for registers."""
8
+ def __init__(self, size: int, name: Optional[str] = None):
9
+ if size <= 0:
10
+ raise ValueError("Register size must be positive")
11
+ self.size = size
12
+ self.name = name
13
+
14
+ def __len__(self):
15
+ return self.size
16
+
17
+ def __repr__(self):
18
+ return f"{self.__class__.__name__}({self.size}, '{self.name}')"
19
+
20
+ class QuantumRegister(Register):
21
+ """Implement a quantum register."""
22
+ def __init__(self, size: int, name: Optional[str] = "q"):
23
+ super().__init__(size, name)
24
+
25
+ class ClassicalRegister(Register):
26
+ """Implement a classical register."""
27
+ def __init__(self, size: int, name: Optional[str] = "c"):
28
+ super().__init__(size, name)
@@ -0,0 +1,72 @@
1
+ """
2
+ Zena Compiler module.
3
+ """
4
+ from typing import Union, List, Optional
5
+ from ..circuit import QuantumCircuit
6
+ from ..providers.backend import Backend
7
+
8
+ # Import qsys transpiler
9
+ try:
10
+ from qsys.transpiler.passes import transpile as qsys_transpile
11
+ except ImportError:
12
+ qsys_transpile = None
13
+
14
+ def transpile(circuits: Union[QuantumCircuit, List[QuantumCircuit]],
15
+ backend: Optional[Backend] = None,
16
+ **kwargs):
17
+ """
18
+ Transpile the circuit(s) for a given backend.
19
+
20
+ Args:
21
+ circuits: Circuit or list of circuits to transpile.
22
+ backend: Backend to target (optional).
23
+
24
+ Returns:
25
+ The transpiled circuit(s).
26
+ """
27
+ if not qsys_transpile:
28
+ print("Warning: qsys transpiler not found. Returning circuit(s) as is.")
29
+ return circuits
30
+
31
+ is_list = isinstance(circuits, list)
32
+ if not is_list:
33
+ circuits = [circuits]
34
+
35
+ transpiled_circuits = []
36
+ for qc in circuits:
37
+ if not hasattr(qc, "_core_circuit") or not qc._core_circuit:
38
+ transpiled_circuits.append(qc)
39
+ continue
40
+
41
+ # Call qsys transpiler on the internal core circuit
42
+ # qsys.transpile expects (core_circuit, backend)
43
+ # Note: In Phase 2, we passed use_transpiler=False because our Zena Backends
44
+ # didn't have .target. To make this work, we'll need to pass the wrapped qsys backend
45
+ # if available, or a default one.
46
+
47
+ # For now, let's just use the opt1q if no backend is provided
48
+ from qsys.transpiler.opt1q import optimize_1q
49
+
50
+ core_qc = qc._core_circuit
51
+
52
+ if backend:
53
+ # If backend is provided, we try to use the full qsys transpile
54
+ # We need to extract the underlying qsys backend from Zena backend if possible
55
+ # Or just pass the Zena backend if it has the required properties (target, etc.)
56
+ try:
57
+ # We expect qsys.transpile to handle cases where backend might be None or simplified
58
+ # but if it needs .target, we might need a fallback.
59
+ transpiled_core = qsys_transpile(core_qc, backend, **kwargs)
60
+ except Exception as e:
61
+ print(f"Warning: full transpile failed ({e}). Falling back to 1q optimization.")
62
+ transpiled_core = optimize_1q(core_qc)
63
+ else:
64
+ # Default optimization if no backend
65
+ transpiled_core = optimize_1q(core_qc)
66
+
67
+ # Update the Zena circuit with the transpiled core
68
+ # In a real SDK, we'd probably return a NEW Zena circuit
69
+ qc._core_circuit = transpiled_core
70
+ transpiled_circuits.append(qc)
71
+
72
+ return transpiled_circuits[0] if not is_list else transpiled_circuits
Binary file
zena/execute.py ADDED
@@ -0,0 +1,35 @@
1
+ """
2
+ Execute function.
3
+ """
4
+ from .providers.aer import Aer
5
+ from .compiler import transpile
6
+
7
+ def execute(experiments, backend=None, shots=1024, **kwargs):
8
+ """
9
+ Execute a list of circuits or a single circuit on a backend.
10
+
11
+ Args:
12
+ experiments (QuantumCircuit or list): Circuit(s) to execute.
13
+ backend (Backend): The backend to execute on.
14
+ shots (int): Number of shots (default: 1024).
15
+
16
+ Returns:
17
+ Job: A job object containing the result.
18
+ """
19
+ if backend is None:
20
+ # Default to statevector simulator if none provided
21
+ backend = Aer.get_backend("statevector_simulator")
22
+
23
+ # Transpile the circuits before execution
24
+ experiments = transpile(experiments, backend=backend)
25
+
26
+ if not isinstance(experiments, list):
27
+ experiments = [experiments]
28
+
29
+ # For now, we only support single circuit execution in this simplified wrapper
30
+ # In full implementation, we would loop and aggregate results
31
+ if len(experiments) > 1:
32
+ raise NotImplementedError("Batch execution not yet fully supported in this simplified wrapper.")
33
+
34
+ circuit = experiments[0]
35
+ return backend.run(circuit, shots=shots, **kwargs)
@@ -0,0 +1,5 @@
1
+ """
2
+ Zena Providers module.
3
+ """
4
+ class Aer:
5
+ pass