Skip to content

Commit c46a138

Browse files
committed
update and fix circuit.compile compile_api bug
1 parent fb5a4fe commit c46a138

12 files changed

+179
-51
lines changed

docs/source/api/compiler/index.rst

Lines changed: 118 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,17 @@ Main Compilation Function
6262
circuit.cx(0, 1)
6363
circuit.cx(1, 2)
6464
65-
# Basic compilation
66-
compiled = compile(circuit)
65+
# Basic compilation (returns CompileResult dict)
66+
result = compile(circuit)
67+
circuit_ir = result["circuit"] # IR object
68+
compiled_source = result["compiled_source"] # None or source string
6769
6870
# Specify optimization
69-
compiled = compile(
71+
result = compile(
7072
circuit,
7173
options={'optimization_level': 2}
7274
)
75+
circuit_ir = result["circuit"]
7376
7477
**Example 2: Pulse Circuit Compilation**:
7578

@@ -86,13 +89,15 @@ Main Compilation Function
8689
"anharmonicity": [-330e6, -320e6]
8790
})
8891
89-
# Compile to TQASM (auto-detects pulse operations)
90-
result = compile(circuit, output="tqasm")
91-
# Returns TQASM code as string
92+
# Compile to QASM3 (returns CompileResult dict)
93+
result = compile(circuit, output="qasm3")
94+
qasm3_code = result["compiled_source"] # QASM3 string with defcal
95+
circuit_ir = result["circuit"] # Original circuit IR
9296
9397
# Or compile to pulse IR (preserves waveform objects)
9498
result = compile(circuit, output="pulse_ir")
95-
# Returns Circuit with pulse operations
99+
pulse_ir = result["compiled_source"] # PulseProgram IR object
100+
circuit_ir = result["circuit"]
96101
97102
**Example 3: Cloud Submission (homebrew_s2)**:
98103

@@ -111,10 +116,93 @@ Main Compilation Function
111116
})
112117
113118
# Compile to TQASM (auto-converts to tyxonq_homebrew_tqasm for homebrew_s2)
114-
tqasm_code = compile(circuit, output="tqasm")
119+
result = compile(circuit, output="tqasm")
120+
tqasm_code = result["compiled_source"] # TQASM string (QASM2 compatible)
115121
116122
# Submit to cloud
117-
result = circuit.run()
123+
result = circuit.run(shots=100)
124+
125+
Pulse Compilation Function
126+
==========================
127+
128+
.. autofunction:: tyxonq.compiler.compile_pulse
129+
130+
**Signature**:
131+
132+
.. code-block:: python
133+
134+
def compile_pulse(
135+
pulse_program, # PulseProgram to compile
136+
output: str = "pulse_ir", # Output format: "pulse_ir", "tqasm", "openqasm3"
137+
device_params: Dict = None, # Device parameters (qubit_freq, anharmonicity, etc.)
138+
calibrations: Dict = None, # Custom pulse calibrations
139+
device: str = None, # Target device for format selection
140+
options: Dict = None, # Compilation options (inline_pulses, etc.)
141+
**kwargs
142+
) -> PulseCompileResult
143+
144+
**Returns**:
145+
146+
``PulseCompileResult`` TypedDict with three fields:
147+
148+
.. code-block:: python
149+
150+
{
151+
"pulse_program": PulseProgram, # Original PulseProgram IR
152+
"compiled_pulse_schedule": Optional[str], # Compiled schedule (TQASM/QASM3) or IR object
153+
"metadata": Dict[str, Any] # Compilation metadata
154+
}
155+
156+
**Output Format Options**:
157+
158+
- ``"pulse_ir"`` (default): TyxonQ native Pulse IR
159+
- compiled_pulse_schedule: PulseProgram IR object
160+
- ``"tqasm"`` / ``"tqasm0.2"``: TQASM 0.2 format (cloud-ready)
161+
- compiled_pulse_schedule: TQASM string with defcal
162+
- ``"openqasm3"``: OpenQASM 3.0 with pulse extensions
163+
- compiled_pulse_schedule: QASM3 string with defcal
164+
165+
**Example 1: Basic Pulse Compilation**:
166+
167+
.. code-block:: python
168+
169+
from tyxonq.core.ir.pulse import PulseProgram
170+
from tyxonq.compiler import compile_pulse
171+
172+
# Create pulse program
173+
prog = PulseProgram(1)
174+
prog.drag(0, amp=1.0, duration=160, sigma=40, beta=0.2, qubit_freq=5.0e9)
175+
176+
# Compile to Pulse IR (default)
177+
result = compile_pulse(prog, device_params={
178+
"qubit_freq": [5.0e9],
179+
"anharmonicity": [-330e6]
180+
})
181+
pulse_ir = result["pulse_program"] # PulseProgram IR
182+
schedule = result["compiled_pulse_schedule"] # None (IR format)
183+
184+
**Example 2: Compile to TQASM for Cloud**:
185+
186+
.. code-block:: python
187+
188+
# Compile to TQASM with full defcal definitions
189+
result = compile_pulse(
190+
prog,
191+
output="tqasm",
192+
device_params={
193+
"qubit_freq": [5.0e9],
194+
"anharmonicity": [-330e6]
195+
},
196+
options={"inline_pulses": True} # Include full defcal definitions
197+
)
198+
tqasm_code = result["compiled_pulse_schedule"] # TQASM string with defcal
199+
200+
# Submit to cloud
201+
circuit = Circuit(1)
202+
task = circuit.device(provider="tyxonq", device="homebrew_s2").run(
203+
source=tqasm_code,
204+
shots=100
205+
)
118206
119207
Optimization Levels
120208
===================
@@ -565,4 +653,25 @@ See Also
565653
- :doc:`/user_guide/compiler/index` - Compiler User Guide
566654
- :doc:`/api/core/index` - Core API
567655
- :doc:`/api/devices/index` - Devices API
656+
- :doc:`/examples/basic_examples` - Compilation Examples
657+
# Benchmark different levels
658+
for level in [0, 1, 2, 3]:
659+
start = time.time()
660+
compiled = circuit.compile(optimization_level=level)
661+
duration = time.time() - start
662+
663+
print(f"Level {level}:")
664+
print(f" Time: {duration:.3f}s")
665+
print(f" Depth: {compiled.depth()}")
666+
print(f" Gates: {compiled.size()}")
667+
668+
See Also
669+
========
670+
671+
- :doc:`/user_guide/compiler/index` - Compiler User Guide
672+
- :doc:`/api/core/index` - Core API
673+
- :doc:`/api/devices/index` - Devices API
674+
- :doc:`/examples/basic_examples` - Compilation Examples
675+
- :doc:`/api/core/index` - Core API
676+
- :doc:`/api/devices/index` - Devices API
568677
- :doc:`/examples/basic_examples` - Compilation Examples

docs/source/user_guide/compiler/index.rst

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,17 @@ Usage Examples
6868
6969
import tyxonq as tq
7070
71-
circuit = tq.Circuit(2).h(0).cnot(0, 1)
71+
circuit = tq.Circuit(2).h(0).cx(0, 1)
7272
73-
# Use default compiler
73+
# Use default compiler (Circuit.compile() 返回 self)
7474
compiled = circuit.compile()
75+
print(f"Compiled source: {compiled._compiled_source}")
7576
7677
# Specify compiler engine
77-
compiled_qiskit = circuit.compile(compile_engine='qiskit')
78+
compiled = circuit.compile(compile_engine='qiskit')
7879
7980
# Set optimization level
80-
compiled_opt = circuit.compile(
81+
compiled = circuit.compile(
8182
compile_engine='native',
8283
options={'optimization_level': 2}
8384
)
@@ -99,15 +100,18 @@ Decomposition Stage
99100
100101
# RX gate decomposition: RX(θ) = H · RZ(θ) · H
101102
circuit = tq.Circuit(1).rx(0, 0.5)
102-
decomposed = circuit.compile()
103+
compiled = circuit.compile() # 返回 Circuit 对象
104+
decomposed_ir = compiled
103105
104106
# RY gate decomposition: RY(θ) = S† · H · RZ(θ) · H · S
105107
circuit = tq.Circuit(1).ry(0, 0.5)
106-
decomposed = circuit.compile()
108+
compiled = circuit.compile() # 返回 Circuit 对象
109+
decomposed_ir = compiled
107110
108111
# RZZ gate decomposition: RZZ(θ) = CNOT · RZ(θ) · CNOT
109112
circuit = tq.Circuit(2).rzz(0, 1, 0.5)
110-
decomposed = circuit.compile()
113+
compiled = circuit.compile() # 返回 Circuit 对象
114+
decomposed_ir = compiled
111115
112116
Rewriting Stage
113117
---------------
@@ -169,12 +173,13 @@ The shot scheduler manages measurement allocation and execution planning:
169173
# Circuit with measurement grouping
170174
circuit = (
171175
tq.Circuit(3)
172-
.h(0).cnot(0, 1).cnot(1, 2)
176+
.h(0).cx(0, 1).cx(1, 2)
173177
.measure_z(0).measure_z(1).measure_z(2)
174178
)
175179
176180
# Automatic scheduling during execution
177181
result = circuit.run(shots=1000)
182+
# result 是 list of unified results
178183
179184
Gradient Processing Stage
180185
-------------------------

examples/circuit_compiler.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,17 @@ def qiskit_compile_levels():
2323
compiled = []
2424
for lvl in levels:
2525
try:
26-
# output='ir' uses native compiler by default; request qiskit artifacts explicitly below
27-
cc = c.compile(
26+
# compile() returns Circuit object with compiled_source stored in _compiled_source
27+
compiled_circuit = c.compile(
2828
compile_engine="default",
2929
output="ir",
3030
options={"optimization_level": lvl, "basis_gates": ["cx", "cz", "h", "rz"]},
3131
)
32+
# Extract circuit IR object
33+
cc = compiled_circuit
3234
compiled.append((lvl, cc))
3335
except Exception as e:
34-
print(f"qiskit compile failed at level {lvl}: {e}")
36+
print(f"compile failed at level {lvl}: {e}")
3537
for lvl, cc in compiled:
3638
# Directly use our Circuit.draw() which compiles to qiskit under the hood
3739
print(f"level {lvl} drawing:")
@@ -42,10 +44,13 @@ def main():
4244
qiskit_compile_levels()
4345
try:
4446
c = build_demo_circuit()
45-
qasm = c.compile(compile_engine="qiskit", output="qasm2", options={"basis_gates": ["cx", "cz", "h", "rz"]})
47+
# compile() returns Circuit object with compiled_source stored in _compiled_source
48+
compiled_circuit = c.compile(compile_engine="qiskit", output="qasm2", options={"basis_gates": ["cx", "cz", "h", "rz"]})
49+
# Extract compiled source (QASM2 string)
50+
qasm = compiled_circuit._compiled_source
4651
print("qasm2 length:", len(qasm))
47-
except Exception:
48-
pass
52+
except Exception as e:
53+
print(f"Error: {e}")
4954

5055

5156
if __name__ == "__main__":

examples/pulse_cloud_submission_e2e.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ def example_mode_a_explicit_pulse_with_comparison():
185185
else:
186186
print(f" ✅ 编译成功,无警告")
187187

188-
tqasm_code = result["circuit"]
188+
# compiled_source 是 TQASM 字符串
189+
tqasm_code = result["compiled_source"]
189190

190191
print(f"\n TQASM 代码长度: {len(tqasm_code)} 字符")
191192

@@ -344,7 +345,8 @@ def example_mode_b_smart_inference():
344345
print(f" 2. 参数警告: 缺少 device_params → 自动补足默认值")
345346
print(f" 默认: qubit_freq=[5.0e9], anharmonicity=[-330e6]")
346347

347-
tqasm_code = result["circuit"]
348+
# compiled_source 是 TQASM 字符串
349+
tqasm_code = result["compiled_source"]
348350

349351
print(f"\n ✅ 智能推断成功!")
350352
print(f" TQASM 代码长度: {len(tqasm_code)} 字符")

examples/pulse_gate_calibration.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ def example_2_virtual_z_gate():
126126
})
127127

128128
result = compile(circuit_pulse, output="pulse_ir", options={"mode": "pulse_only"})
129-
pulse_circuit = result["circuit"]
129+
# compiled_source 是 pulse IR 对象
130+
pulse_circuit = result["compiled_source"]
130131

131132
# 分析脉冲序列
132133
print(f"\n脉冲序列分析:")
@@ -147,7 +148,8 @@ def example_2_virtual_z_gate():
147148

148149
# 导出 TQASM 查看 Virtual-Z 实现
149150
tqasm_result = compile(circuit_pulse, output="tqasm", options={"mode": "pulse_only"})
150-
tqasm_code = tqasm_result["circuit"]
151+
# compiled_source 是 TQASM 字符串
152+
tqasm_code = tqasm_result["compiled_source"]
151153

152154
print(f"\n TQASM 中的 Virtual-Z 实现:")
153155
print(f" (在 defcal 中表现为 shift_phase 指令)")
@@ -303,7 +305,8 @@ def example_5_gate_calibration_export():
303305

304306
# 导出为 TQASM (包含优化后的 defcal)
305307
result = compile(circuit_pulse, output="tqasm", options={"mode": "pulse_only"})
306-
tqasm_code = result["circuit"]
308+
# compiled_source 是 TQASM 字符串
309+
tqasm_code = result["compiled_source"]
307310

308311
print(f"\n导出的 TQASM 校准文件:")
309312
print("=" * 70)

tests_core_module/test_pulse_compiler.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,15 @@ def test_compile_single_x_gate(self):
3838
c.x(0)
3939

4040
compiler = PulseCompiler()
41-
pulse_circuit = compiler.compile(
41+
result = compiler.compile(
4242
c,
4343
device_params={
4444
"qubit_freq": [5.0e9],
4545
"anharmonicity": [-330e6]
4646
},
4747
mode="pulse_only"
4848
)
49+
pulse_circuit = result["circuit"]
4950

5051
# Check that circuit has pulse operations
5152
assert pulse_circuit is not None
@@ -90,7 +91,8 @@ def test_hybrid_mode_preserves_gates(self):
9091
c.measure_z(1)
9192

9293
compiler = PulseCompiler()
93-
pulse_circuit = compiler.compile(c, mode="hybrid")
94+
result = compiler.compile(c, mode="hybrid")
95+
pulse_circuit = result["circuit"]
9496

9597
# Check that measurement gates are preserved
9698
measure_ops = [op for op in pulse_circuit.ops
@@ -189,14 +191,15 @@ def test_full_pipeline_with_multiple_gates(self):
189191
c.measure_z(1)
190192

191193
compiler = PulseCompiler(optimization_level=2)
192-
pulse_circuit = compiler.compile(
194+
result = compiler.compile(
193195
c,
194196
device_params={
195197
"qubit_freq": [5.0e9, 5.1e9],
196198
"anharmonicity": [-330e6, -320e6]
197199
},
198200
mode="hybrid"
199201
)
202+
pulse_circuit = result["circuit"]
200203

201204
# Verify compilation succeeded
202205
assert pulse_circuit is not None
@@ -219,7 +222,8 @@ def test_pulse_compilation_with_device_params(self):
219222
}
220223

221224
compiler = PulseCompiler()
222-
pulse_circuit = compiler.compile(c, device_params=device_params)
225+
result = compiler.compile(c, device_params=device_params)
226+
pulse_circuit = result["circuit"]
223227

224228
# Verify device params are stored in metadata
225229
assert pulse_circuit.metadata["pulse_device_params"] == device_params

0 commit comments

Comments
 (0)