Skip to content

Commit 550144e

Browse files
authored
Merge branch 'main' into openqasm-circuitbinding
2 parents e7871d7 + 3fb2d0e commit 550144e

8 files changed

Lines changed: 529 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Changelog
22

3+
## v1.119.1 (2026-06-10)
4+
5+
### Bug Fixes and Other Changes
6+
7+
* support division in FreeParameterExpression string constructor
8+
9+
## v1.119.0 (2026-06-09)
10+
11+
### Features
12+
13+
* support math functions in FreeParameterExpression
14+
315
## v1.118.0 (2026-06-04)
416

517
### Deprecations and Removals

src/braket/_sdk/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@
1515
Version number (major.minor.patch[-label])
1616
"""
1717

18-
__version__ = "1.118.1.dev0"
18+
__version__ = "1.119.2.dev0"

src/braket/parametric/__init__.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,24 @@
1414
"""You can define a circuit with gates that depend on free parameters and specify
1515
the values of these parameters when submitting the circuit as a quantum task.
1616
This module provides FreeParameter for defining symbolic parameters,
17-
FreeParameterExpression for mathematical expressions, and Parameterizable
18-
interface for parameter binding.
17+
FreeParameterExpression for mathematical expressions, math helper functions,
18+
and Parameterizable interface for parameter binding.
1919
"""
2020

2121
from braket.parametric.free_parameter import FreeParameter # noqa: F401
2222
from braket.parametric.free_parameter_expression import FreeParameterExpression # noqa: F401
23+
from braket.parametric.functions import (
24+
arccos, # noqa: F401
25+
arcsin, # noqa: F401
26+
arctan, # noqa: F401
27+
ceiling, # noqa: F401
28+
cos, # noqa: F401
29+
exp, # noqa: F401
30+
floor, # noqa: F401
31+
log, # noqa: F401
32+
mod, # noqa: F401
33+
sin, # noqa: F401
34+
sqrt, # noqa: F401
35+
tan, # noqa: F401
36+
)
2337
from braket.parametric.parameterizable import Parameterizable # noqa: F401

src/braket/parametric/free_parameter_expression.py

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,39 @@
1717
import operator
1818
from functools import reduce
1919
from numbers import Number
20-
from typing import Any
20+
from typing import Any, ClassVar
2121

2222
import sympy
2323
from oqpy.base import OQPyExpression
2424
from oqpy.classical_types import FloatVar
25+
from sympy.printing.str import StrPrinter
26+
27+
28+
class _OpenQASMExpressionPrinter(StrPrinter):
29+
_FN_MAP: ClassVar[dict[type, str]] = {
30+
sympy.sin: "sin",
31+
sympy.cos: "cos",
32+
sympy.tan: "tan",
33+
sympy.asin: "arcsin",
34+
sympy.acos: "arccos",
35+
sympy.atan: "arctan",
36+
sympy.exp: "exp",
37+
sympy.log: "log",
38+
sympy.Mod: "mod",
39+
sympy.ceiling: "ceiling",
40+
sympy.floor: "floor",
41+
}
42+
43+
def _print_Function(self, expr: sympy.Function) -> str:
44+
function_name = self._FN_MAP.get(expr.func)
45+
if function_name is None:
46+
raise ValueError(f"No OpenQASM 3 equivalent for {expr.func.__name__}")
47+
args = ", ".join(self._print(arg) for arg in expr.args)
48+
return f"{function_name}({args})"
49+
50+
51+
def _openqasm_doprint(expression: Number | sympy.Expr) -> str:
52+
return _OpenQASMExpressionPrinter().doprint(expression)
2553

2654

2755
class FreeParameterExpression:
@@ -31,6 +59,8 @@ class FreeParameterExpression:
3159
FreeParametersExpressions can hold FreeParameters that can later be
3260
swapped out for a number. Circuits or PulseSequences with FreeParameters
3361
present will NOT run. Values must be substituted prior to execution.
62+
String representations of supported SymPy functions use OpenQASM-compatible
63+
names.
3464
"""
3565

3666
def __init__(self, expression: FreeParameterExpression | Number | sympy.Expr | str):
@@ -54,6 +84,7 @@ def __init__(self, expression: FreeParameterExpression | Number | sympy.Expr | s
5484
ast.Add: self.__add__,
5585
ast.Sub: self.__sub__,
5686
ast.Mult: self.__mul__,
87+
ast.Div: self.__truediv__,
5788
ast.Pow: self.__pow__,
5889
ast.USub: self.__neg__,
5990
}
@@ -177,9 +208,17 @@ def __repr__(self) -> str:
177208
"""The representation of the :class:'FreeParameterExpression'.
178209
179210
Returns:
180-
str: The expression of the class:'FreeParameterExpression' to represent the class.
211+
str: The OpenQASM-compatible string for the expression.
212+
"""
213+
return str(self)
214+
215+
def __str__(self) -> str:
216+
"""The string representation of the :class:'FreeParameterExpression'.
217+
218+
Returns:
219+
str: The OpenQASM-compatible string for the expression.
181220
"""
182-
return repr(self.expression)
221+
return _openqasm_doprint(self.expression)
183222

184223
def _to_oqpy_expression(self) -> OQPyExpression:
185224
"""Transforms into an OQPyExpression.

src/braket/parametric/functions.py

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
# Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"). You
4+
# may not use this file except in compliance with the License. A copy of
5+
# the License is located at
6+
#
7+
# http://aws.amazon.com/apache2.0/
8+
#
9+
# or in the "license" file accompanying this file. This file is
10+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11+
# ANY KIND, either express or implied. See the License for the specific
12+
# language governing permissions and limitations under the License.
13+
14+
"""Math helper functions for free parameter expressions.
15+
16+
These helpers let you build symbolic OpenQASM math expressions without importing
17+
SymPy or touching the internal expression attribute.
18+
19+
Examples:
20+
>>> from braket.circuits import Circuit
21+
>>> from braket.parametric import FreeParameter, arcsin
22+
>>> alpha = FreeParameter("alpha")
23+
>>> circuit = Circuit().rx(0, arcsin(alpha))
24+
>>> source = circuit.to_ir("OPENQASM").source
25+
>>> "rx(arcsin(alpha)) q[0];" in source
26+
True
27+
"""
28+
29+
from __future__ import annotations
30+
31+
from collections.abc import Callable
32+
from numbers import Number
33+
34+
import sympy
35+
36+
from braket.parametric.free_parameter_expression import FreeParameterExpression
37+
38+
39+
def _expression(value: FreeParameterExpression | Number) -> Number | sympy.Expr:
40+
return value.expression if isinstance(value, FreeParameterExpression) else value
41+
42+
43+
def _wrap(
44+
function: Callable[..., Number | sympy.Expr],
45+
*args: FreeParameterExpression | Number,
46+
) -> FreeParameterExpression:
47+
sympy_args = [_expression(arg) for arg in args]
48+
return FreeParameterExpression(function(*sympy_args))
49+
50+
51+
def sin(x: FreeParameterExpression | Number) -> FreeParameterExpression:
52+
"""Returns the sine of a free parameter expression.
53+
54+
Args:
55+
x (FreeParameterExpression | Number): The expression.
56+
57+
Returns:
58+
FreeParameterExpression: The symbolic sine expression.
59+
"""
60+
return _wrap(sympy.sin, x)
61+
62+
63+
def cos(x: FreeParameterExpression | Number) -> FreeParameterExpression:
64+
"""Returns the cosine of a free parameter expression.
65+
66+
Args:
67+
x (FreeParameterExpression | Number): The expression.
68+
69+
Returns:
70+
FreeParameterExpression: The symbolic cosine expression.
71+
"""
72+
return _wrap(sympy.cos, x)
73+
74+
75+
def tan(x: FreeParameterExpression | Number) -> FreeParameterExpression:
76+
"""Returns the tangent of a free parameter expression.
77+
78+
Args:
79+
x (FreeParameterExpression | Number): The expression.
80+
81+
Returns:
82+
FreeParameterExpression: The symbolic tangent expression.
83+
"""
84+
return _wrap(sympy.tan, x)
85+
86+
87+
def arcsin(x: FreeParameterExpression | Number) -> FreeParameterExpression:
88+
"""Returns the arcsine (inverse sine) of a free parameter expression.
89+
90+
Args:
91+
x (FreeParameterExpression | Number): The expression.
92+
93+
Returns:
94+
FreeParameterExpression: The symbolic arcsine expression.
95+
"""
96+
return _wrap(sympy.asin, x)
97+
98+
99+
def arccos(x: FreeParameterExpression | Number) -> FreeParameterExpression:
100+
"""Returns the arccosine (inverse cosine) of a free parameter expression.
101+
102+
Args:
103+
x (FreeParameterExpression | Number): The expression.
104+
105+
Returns:
106+
FreeParameterExpression: The symbolic arccosine expression.
107+
"""
108+
return _wrap(sympy.acos, x)
109+
110+
111+
def arctan(x: FreeParameterExpression | Number) -> FreeParameterExpression:
112+
"""Returns the arctangent (inverse tangent) of a free parameter expression.
113+
114+
Args:
115+
x (FreeParameterExpression | Number): The expression.
116+
117+
Returns:
118+
FreeParameterExpression: The symbolic arctangent expression.
119+
"""
120+
return _wrap(sympy.atan, x)
121+
122+
123+
def exp(x: FreeParameterExpression | Number) -> FreeParameterExpression:
124+
"""Returns the exponential of a free parameter expression.
125+
126+
Args:
127+
x (FreeParameterExpression | Number): The expression.
128+
129+
Returns:
130+
FreeParameterExpression: The symbolic exponential expression.
131+
"""
132+
return _wrap(sympy.exp, x)
133+
134+
135+
def log(x: FreeParameterExpression | Number) -> FreeParameterExpression:
136+
"""Returns the natural logarithm of a free parameter expression.
137+
138+
Args:
139+
x (FreeParameterExpression | Number): The expression.
140+
141+
Returns:
142+
FreeParameterExpression: The symbolic natural logarithm expression.
143+
"""
144+
return _wrap(sympy.log, x)
145+
146+
147+
def sqrt(x: FreeParameterExpression | Number) -> FreeParameterExpression:
148+
"""Returns the square root of a free parameter expression.
149+
150+
Args:
151+
x (FreeParameterExpression | Number): The expression.
152+
153+
Returns:
154+
FreeParameterExpression: The symbolic square root expression.
155+
"""
156+
return _wrap(sympy.sqrt, x)
157+
158+
159+
def mod(
160+
x: FreeParameterExpression | Number,
161+
m: FreeParameterExpression | Number,
162+
) -> FreeParameterExpression:
163+
"""Returns the remainder of a free parameter expression divided by ``m``.
164+
165+
Args:
166+
x (FreeParameterExpression | Number): The dividend expression.
167+
m (FreeParameterExpression | Number): The divisor expression.
168+
169+
Returns:
170+
FreeParameterExpression: The symbolic modulo expression.
171+
"""
172+
return _wrap(sympy.Mod, x, m)
173+
174+
175+
def ceiling(x: FreeParameterExpression | Number) -> FreeParameterExpression:
176+
"""Returns the ceiling of a free parameter expression.
177+
178+
Args:
179+
x (FreeParameterExpression | Number): The expression.
180+
181+
Returns:
182+
FreeParameterExpression: The symbolic ceiling expression.
183+
"""
184+
return _wrap(sympy.ceiling, x)
185+
186+
187+
def floor(x: FreeParameterExpression | Number) -> FreeParameterExpression:
188+
"""Returns the floor of a free parameter expression.
189+
190+
Args:
191+
x (FreeParameterExpression | Number): The expression.
192+
193+
Returns:
194+
FreeParameterExpression: The symbolic floor expression.
195+
"""
196+
return _wrap(sympy.floor, x)

test/unit_tests/braket/devices/test_local_simulator.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,26 @@
2020
from unittest.mock import Mock, patch
2121

2222
import pytest
23+
import sympy
2324
from pydantic.v1 import create_model # This is temporary for defining properties below
2425

2526
import braket.ir as ir
2627
from braket.ahs.analog_hamiltonian_simulation import AnalogHamiltonianSimulation
2728
from braket.ahs.atom_arrangement import AtomArrangement
2829
from braket.ahs.hamiltonian import Hamiltonian
2930
from braket.annealing import Problem, ProblemType
30-
from braket.circuits import Circuit, FreeParameter, Gate, Noise
31+
from braket.circuits import Circuit, FreeParameter, FreeParameterExpression, Gate, Noise
3132
from braket.circuits.noise_model import GateCriteria, NoiseModel, NoiseModelInstruction
3233
from braket.circuits.serialization import IRType, SerializableProgram
34+
from braket.default_simulator import StateVectorSimulator
3335
from braket.device_schema import DeviceActionType, DeviceCapabilities
3436
from braket.device_schema.openqasm_device_action_properties import (
3537
OpenQASMDeviceActionProperties,
3638
)
3739
from braket.devices import LocalSimulator, local_simulator
3840
from braket.ir.openqasm import Program
3941
from braket.ir.openqasm.program_set_v1 import ProgramSet as OpenQASMProgramSet
42+
from braket.parametric import cos, sin
4043
from braket.program_sets import ProgramSet
4144
from braket.program_sets.circuit_binding import CircuitBinding
4245
from braket.simulator import BraketSimulator
@@ -689,6 +692,30 @@ def test_run_program_model_inputs():
689692
assert task.result() == GateModelQuantumTaskResult.from_object(GATE_MODEL_RESULT)
690693

691694

695+
def test_local_simulator_runs_sympy_inverse_trig_free_parameter_expression():
696+
alpha = FreeParameter("alpha")
697+
expr = FreeParameterExpression(sympy.asin(alpha.expression))
698+
circuit = Circuit().rx(0, expr).measure(0)
699+
700+
assert "arcsin(alpha)" in circuit.to_ir("OPENQASM").source
701+
702+
device = LocalSimulator(StateVectorSimulator())
703+
result = device.run(circuit, inputs={"alpha": 0.5}, shots=10).result()
704+
705+
assert sum(result.measurement_counts.values()) == 10
706+
707+
708+
def test_local_simulator_runs_parametric_math_helper_expression():
709+
alpha = FreeParameter("alpha")
710+
expr = sin(alpha / 2) ** 2 + cos(alpha / 2) ** 2
711+
circuit = Circuit().rx(0, expr).measure(0)
712+
713+
device = LocalSimulator(StateVectorSimulator())
714+
result = device.run(circuit, inputs={"alpha": math.pi}, shots=10).result()
715+
716+
assert sum(result.measurement_counts.values()) == 10
717+
718+
692719
def test_run_jaqcd_only_raises():
693720
dummy = DummyJaqcdSimulator()
694721
sim = LocalSimulator(dummy)

0 commit comments

Comments
 (0)