Advanced Operator Functions#
This example explores operator-valued functions such as exp(A), cos(A),
and sqrtm(A) when applied to local operators. It explains the grammar
restrictions (single operator argument, optional integer power) and shows how
backends treat these constructs.
What you’ll learn#
Allowed operator functions and their constraints.
How operator functions are represented in the IR (
OperatorFunctionRef).
Source#
1# flake8: noqa
2"""
3Advanced operator-function usage and validation.
4
5This example covers:
6- Allowed operator-valued functions (exp, cos, sin, etc.).
7- Scalar factors on operator functions.
8- Mixing operator functions with time-dependent envelopes.
9- How to handle invalid operator functions and surface clear errors.
10
11Run individual functions from a REPL; nothing executes on import.
12"""
13
14from __future__ import annotations
15
16import sys
17from pathlib import Path
18from typing import Iterable, Tuple
19
20import sympy as sp
21
22ROOT = Path(__file__).resolve().parents[1]
23if str(ROOT) not in sys.path:
24 sys.path.insert(0, str(ROOT))
25
26from latex_parser.dsl import HilbertConfig, QubitSpec
27from latex_parser.dsl_constants import ALLOWED_OPERATOR_FUNCTIONS
28from latex_parser.ir import HamiltonianIR, latex_to_ir
29
30
31def _describe_ir(ir: HamiltonianIR) -> None:
32 print("has_time_dep:", ir.has_time_dep)
33 for idx, term in enumerate(ir.terms):
34 print(f"Term {idx}: scalar={term.scalar_expr}")
35 print(" ops:", term.ops)
36
37
38def list_allowed_functions() -> None:
39 """
40 Print the currently allowed operator-valued functions.
41 """
42 print("Allowed operator functions:", sorted(ALLOWED_OPERATOR_FUNCTIONS))
43
44
45def simple_operator_function() -> None:
46 """
47 Compile exp(sigma_z) acting on a qubit.
48 """
49 cfg = HilbertConfig(qubits=[QubitSpec(label="q", index=1)], bosons=[], customs=[])
50 H = r"\exp(\sigma_{z,1})"
51 ir = latex_to_ir(H, cfg, t_name="t")
52 _describe_ir(ir)
53
54
55def operator_function_with_scalar() -> None:
56 """
57 Compile a scalar times an operator function, e.g. g * exp(sigma_z).
58 """
59 cfg = HilbertConfig(qubits=[QubitSpec(label="q", index=1)], bosons=[], customs=[])
60 H = r"g \exp(\sigma_{z,1})"
61 ir = latex_to_ir(H, cfg, t_name="t")
62 _describe_ir(ir)
63
64
65def operator_function_with_power() -> None:
66 """
67 Operator function applied to a powered operator (sigma_x^2).
68 """
69 cfg = HilbertConfig(qubits=[QubitSpec(label="q", index=1)], bosons=[], customs=[])
70 H = r"\cos(\sigma_{x,1}^{2})"
71 ir = latex_to_ir(H, cfg, t_name="t")
72 _describe_ir(ir)
73
74
75def operator_function_plus_time_envelope() -> None:
76 """
77 Mix a time-dependent scalar with an operator function argument.
78 """
79 cfg = HilbertConfig(qubits=[QubitSpec(label="q", index=1)], bosons=[], customs=[])
80 H = r"A \cos(\omega t) \exp(\sigma_{z,1})"
81 ir = latex_to_ir(H, cfg, t_name="t")
82 _describe_ir(ir)
83
84
85def invalid_operator_function_sum() -> None:
86 """
87 Demonstrate rejection of operator-function arguments that are sums.
88 """
89 cfg = HilbertConfig(qubits=[QubitSpec(label="q", index=1)], bosons=[], customs=[])
90 bad = [
91 r"\exp(\sigma_{x,1} + \sigma_{z,1})",
92 r"\tanh(\sigma_{z,1})",
93 ]
94 for expr in bad:
95 try:
96 latex_to_ir(expr, cfg, t_name="t")
97 except Exception as exc: # noqa: BLE001 - user-facing demo
98 print(expr, "->", exc)
99
100
101def batch_operator_functions(exprs: Iterable[str]) -> None:
102 """
103 Compile a list of operator-function expressions and report properties.
104 """
105 cfg = HilbertConfig(qubits=[QubitSpec(label="q", index=1)], bosons=[], customs=[])
106 for expr in exprs:
107 try:
108 ir = latex_to_ir(expr, cfg, t_name="t")
109 except Exception as exc: # noqa: BLE001 - user-facing demo
110 print(expr, "-> error:", exc)
111 continue
112 print(expr, "-> has_time_dep:", ir.has_time_dep)
113 for term in ir.terms:
114 print(" scalar:", term.scalar_expr)
115 print(" ops:", term.ops)
116
117
118def operator_function_simplify() -> None:
119 """
120 Apply SymPy simplify to scalar factors surrounding operator functions.
121 """
122 cfg = HilbertConfig(qubits=[QubitSpec(label="q", index=1)], bosons=[], customs=[])
123 H = r"2*g \exp(\sigma_{z,1}) + g*g \exp(\sigma_{x,1})"
124 ir = latex_to_ir(H, cfg, t_name="t")
125 simplified: list[Tuple[sp.Expr, list]] = []
126 for term in ir.terms:
127 simplified.append((sp.simplify(term.scalar_expr), term.ops))
128 print("Simplified scalars:")
129 for s, ops in simplified:
130 print(" ", s, "| ops:", ops)
131
132
133def operator_function_with_aliases() -> None:
134 """
135 Confirm parameter aliases still work when operator functions present.
136 """
137 cfg = HilbertConfig(qubits=[QubitSpec(label="q", index=1)], bosons=[], customs=[])
138 H = r"\omega_{0} \exp(\sigma_{z,1})"
139 ir = latex_to_ir(H, cfg, t_name="t")
140 required = {sym.name for sym in ir.terms[0].scalar_expr.free_symbols}
141 print("Required scalar symbols:", required)
142
143
144def combine_operator_functions_with_products() -> None:
145 """
146 Compose operator functions with products of standard operators.
147 """
148 cfg = HilbertConfig(qubits=[QubitSpec(label="q", index=1)], bosons=[], customs=[])
149 H = r"\exp(\sigma_{z,1}) \sigma_{x,1} + \exp(\sigma_{x,1}) \sigma_{z,1}"
150 ir = latex_to_ir(H, cfg, t_name="t")
151 _describe_ir(ir)
152
153
154def register_and_use_custom_operator_function() -> None:
155 """
156 Demonstrate how to register a new operator function at runtime.
157 """
158 from latex_parser.dsl_constants import register_operator_function
159
160 cfg = HilbertConfig(qubits=[QubitSpec(label="q", index=1)], bosons=[], customs=[])
161 register_operator_function("sinh")
162 H = r"\sinh(\sigma_{x,1})"
163 ir = latex_to_ir(H, cfg, t_name="t")
164 _describe_ir(ir)
165
166
167def stress_test_operator_functions() -> None:
168 """
169 Build a small suite of varied operator-function expressions to ensure
170 they remain within the allowed grammar.
171 """
172 exprs = [
173 r"\cos(\sigma_{x,1}) + \cos(\sigma_{z,1})",
174 r"\exp(\sigma_{x,1}) \exp(\sigma_{z,1})",
175 r"A \exp(\sigma_{x,1}) + B \cos(\sigma_{y,1})",
176 r"\exp(\sigma_{x,1}^{3})",
177 r"\cos(\sigma_{z,1}) \cos(\omega t)",
178 ]
179 batch_operator_functions(exprs)
180
181
182def operator_function_error_messages() -> None:
183 """
184 Surface friendly error messages for common mistakes.
185 """
186 cfg = HilbertConfig(qubits=[QubitSpec(label="q", index=1)], bosons=[], customs=[])
187 mistakes = [
188 r"\exp(\sigma_{x,1} + \sigma_{z,1})", # sum in argument
189 r"\exp(\sigma_{x,1}^{-1})", # negative power
190 r"\log(\sigma_{x,1})", # unsupported function
191 ]
192 for expr in mistakes:
193 try:
194 latex_to_ir(expr, cfg, t_name="t")
195 except Exception as exc: # noqa: BLE001 - user-facing demo
196 print("[expected] ", expr, "->", exc)
197
198
199def operator_functions_with_params() -> None:
200 """
201 Track scalar parameters that accompany operator functions.
202 """
203 cfg = HilbertConfig(qubits=[QubitSpec(label="q", index=1)], bosons=[], customs=[])
204 H = r"g \exp(\sigma_{z,1}) + \kappa \cos(\sigma_{x,1})"
205 ir = latex_to_ir(H, cfg, t_name="t")
206 required = set()
207 for term in ir.terms:
208 required |= {s.name for s in term.scalar_expr.free_symbols}
209 print("Scalar symbols alongside operator functions:", sorted(required))
210
211
212def main() -> None:
213 list_allowed_functions()
214 simple_operator_function()
215 operator_function_with_scalar()
216 operator_function_with_power()
217 operator_function_plus_time_envelope()
218 invalid_operator_function_sum()
219 batch_operator_functions(
220 [
221 r"\cos(\sigma_{x,1})",
222 r"\exp(\sigma_{z,1})",
223 r"\sin(\sigma_{y,1}) \cos(\omega t)",
224 ]
225 )
226 operator_function_simplify()
227 operator_function_with_aliases()
228 combine_operator_functions_with_products()
229 register_and_use_custom_operator_function()
230 stress_test_operator_functions()
231 operator_function_error_messages()
232 operator_functions_with_params()
233
234
235if __name__ == "__main__":
236 main()
Run#
python examples/example_operator_functions_advanced.py
Notes#
Not all backends support the same operator functions; check backend docs.
Use IR inspection to verify arguments and scalar factors for operator functions.