Skip to content

Conversation

@NnktYoshioka
Copy link
Contributor

@NnktYoshioka NnktYoshioka commented Aug 13, 2025

In gridsynth_gates(theta, eps) we assumed that theta and eps are mpmath objects, with its precision tuned properly by mpmath.mp.dps.
I made a change reflecting PRs #5 and #6 so that the following both works.
@shun0923 can you check if these changes are ok, upon your convenience?

from pygridsynth.gridsynth import gridsynth_gates, error
import mpmath, time

theta = 0.356
eps = 1e-80

gates1 = gridsynth_gates(theta, eps, )
print(float(error(theta, gates1)))
print()

mpmath.mp.dps = 250 # this is important when theta and eps are mpmath
theta = mpmath.mpmathify(f"{theta}")
eps = mpmath.mpmathify(f"{eps}")
gates2 = gridsynth_gates(theta, eps, )
print(float(error(theta, gates2)))

Copy link
Collaborator

@shun0923 shun0923 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When changing the dps for theta or epsilon, converting via a string:

theta = mpmath.mpmathify(f"{theta}")

can introduce unintended rounding errors if theta is already an mpf.
It might be better to convert without the intermediate string, for example:

theta = mpmath.mpmathify(theta)

For example, with:

mpmath.mp.dps = 20
epsilon = 1e-20
theta = mpmath.mpmathify("2.1")

the latter preserves the value of theta (repr(theta) remains unchanged),
while the former (current code) alters it.

@NnktYoshioka
Copy link
Contributor Author

Thanks for the quick review. Could you give me an example for the issue?
When I tried the following, it seemed fine with using the intermediate string, so I thought re-mpmathifying is fine.
But maybe you are discussing some different situation

theta = mpmath.mpmathify("2.1")

print(repr(mpmath.mpmathify(theta)))
print(repr(mpmath.mpmathify(f"{theta}")))
#mpf('2.09999999999999999999999999999992')
#mpf('2.09999999999999999999999999999992')

theta = 2.1

print(repr(mpmath.mpmathify(theta)))
print(repr(mpmath.mpmathify(f"{theta}")))
#mpf('2.10000000000000008881784197001252')
#mpf('2.09999999999999999999999999999992')

@shun0923
Copy link
Collaborator

You can see the rounding issue with the following code:

import mpmath

mpmath.mp.dps = 20
theta = mpmath.mpmathify("2.1")

mpmath.mp.dps = 65
theta1 = mpmath.mpmathify(f"{theta}")
theta2 = mpmath.mpmathify(theta)

print(repr(theta))
print(theta == theta1, repr(theta1))
print(theta == theta2, repr(theta2))
# mpf('2.1000000000000000000013552527156068805425093160010874271392822265625')
# False mpf('2.1000000000000000000013552527156068805425093160010874271392822266005')
# True mpf('2.1000000000000000000013552527156068805425093160010874271392822265625')

Here, when converting via the intermediate string (theta1), the value changes slightly at the higher precision (dps = 65).
When converting directly (theta2), the value remains exactly the same.

@shun0923
Copy link
Collaborator

Additional note for when theta is a float:

If theta is a float (e.g., theta = 0.3), the actual stored value is not exactly 0.3 due to floating-point representation errors.
When converting such a float to a string, it becomes "0.3", which removes the small error introduced earlier.
As a result, converting from the string may appear to produce a more accurate mpf.

However, the conversion without going through a string actually preserves the value that more accurately represents the actual float theta.

Therefore, if you want theta to be the exact decimal 0.3, you should avoid passing the float value 0.3 directly.
Instead, pass the string "0.3" or call:

mpmath.mp.dps = <suitable precision>
theta = mpmath.mpmathify("0.3")

In summary, extra care is needed when passing theta as a float. (It might be worth adding this as a cautionary note in the README.)

@NnktYoshioka
Copy link
Contributor Author

NnktYoshioka commented Aug 14, 2025

I see your point, thanks.
I initially thought that allowing float makes sense for enhancing usability, but now starting to get worried about the case when we want to synthesize the rotation angles related with pi.
If we do something like the following, we would not get the correct synthesis.

# outside gridsynth
theta = np.pi/8

# inside gridsynth
theta = mpmath.mpmathify(theta)

Shall we even have assert that gridsynth_gates does not take float objects then?
Or shall we just show a Warning something like "pygridsynth is synthesizing the angle XXX, please verify if this is the intended value"?

@shun0923
Copy link
Collaborator

I think it’s fine to allow floats, since there are cases where only an error at the level of float precision is required, and in such situations it can be more convenient to pass a float directly.
However, there are many things users should be careful about, so a warning should be issued.

@shun0923 shun0923 merged commit e7a7d42 into main Aug 15, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants