Advanced Operator Functions

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.