-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
fix(polys): don't unify characteristics #25666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
✅ Hi, I am the SymPy bot. I'm here to help you write a release notes entry. Please read the guide on how to write release notes. Your release notes are in good order. Here is what the release notes will look like:
This will be added to https://github.com/sympy/sympy/wiki/Release-Notes-for-1.13. Click here to see the pull request description that was parsed.
Update The release notes on the wiki have been updated. |
@@ -396,7 +396,7 @@ def _compute_test_factor(p, gens, ZK): | |||
# predicts that such an element must exist, so nullspace should | |||
# be non-trivial. | |||
x = B.nullspace()[0, :].transpose() | |||
beta = ZK.parent(ZK.matrix * x, denom=ZK.denom) | |||
beta = ZK.parent(ZK.matrix * x.convert_to(ZZ), denom=ZK.denom) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@skieffer this change preserves existing behaviour. Let me know if something else should be done here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the question, and I'm sorry I wasn't able to respond in time. But your fix looks good. Thanks for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As the author of the only code in the whole of SymPy that depended on the previous behaviour do you have any opinions about GF(3).unify(ZZ)
and the general change in this PR that disallows it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I'll comment on the main thread, #25653.
sympy/simplify/tests/test_ratsimp.py
Outdated
a = (x**5 + 2*x**4 + 2*x**3 + 2*x**2 + x + 2/x + x**(-2)) | ||
assert ratsimpmodprime(a, [x + 1], domain=GF(2)) == 1 | ||
assert ratsimpmodprime(a, [x + 1], domain=GF(3)) == -1 | ||
# assert ratsimpmodprime(a, [x + 1], domain=GF(2)) == 1 | ||
# assert ratsimpmodprime(a, [x + 1], domain=GF(3)) == -1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These examples highlight a problem with disallowing any unification between GF(p)
and ZZ
:
In [1]: p = Poly(1, x, modulus=2)
In [2]: p
Out[2]: Poly(1, x, modulus=2)
In [3]: p * 2
...
UnificationFailed: Cannot unify GF(2) with ZZ
There are probably ways to work around this but at least it shows why being able to unify GF(p)
and ZZ
makes sense in some situations. Here the problem is that the 2
is coerced into Poly(2, x, domain=ZZ)
before the product is computed. Then the product tries to unify the two Poly
and fails if GF(2)
cannot unify with ZZ
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this example I don't think it matters which way the unification happens as long as they do unify to something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed this by special casing Poly * int/Integer
.
Benchmark results from GitHub Actions Lower numbers are good, higher numbers are bad. A ratio less than 1 Significantly changed benchmark results (PR vs master) Significantly changed benchmark results (master vs previous release) | Change | Before [8059df73] <sympy-1.12^0> | After [64a48d1a] | Ratio | Benchmark (Parameter) |
|----------|------------------------------------|---------------------|---------|----------------------------------------------------------------------|
| - | 84.5±0.9ms | 55.7±0.3ms | 0.66 | integrate.TimeIntegrationRisch02.time_doit_risch(10) |
| + | 22.2±0.07μs | 39.0±0.2μs | 1.76 | integrate.TimeIntegrationRisch03.time_doit(1) |
| - | 6.89±0.02ms | 3.75±0.01ms | 0.54 | logic.LogicSuite.time_load_file |
| - | 2.11±0.01ms | 653±2μs | 0.31 | polys.TimePREM_LinearDenseQuadraticGCD.time_op(3, 'sparse') |
| - | 10.4±0.04ms | 1.95±0ms | 0.19 | polys.TimePREM_LinearDenseQuadraticGCD.time_op(5, 'sparse') |
| - | 368±0.3μs | 81.6±0.2μs | 0.22 | polys.TimePREM_QuadraticNonMonicGCD.time_op(1, 'sparse') |
| - | 4.82±0.01ms | 362±0.5μs | 0.08 | polys.TimePREM_QuadraticNonMonicGCD.time_op(3, 'sparse') |
| - | 10.6±0.02ms | 1.09±0ms | 0.1 | polys.TimePREM_QuadraticNonMonicGCD.time_op(5, 'sparse') |
| - | 6.24±0.01ms | 3.94±0.01ms | 0.63 | polys.TimeSUBRESULTANTS_LinearDenseQuadraticGCD.time_op(2, 'sparse') |
| - | 27.2±0.07ms | 12.0±0.02ms | 0.44 | polys.TimeSUBRESULTANTS_LinearDenseQuadraticGCD.time_op(3, 'sparse') |
| - | 6.92±0.02ms | 1.17±0ms | 0.17 | polys.TimeSUBRESULTANTS_QuadraticNonMonicGCD.time_op(1, 'sparse') |
| - | 16.3±0.02ms | 9.23±0.01ms | 0.57 | polys.TimeSUBRESULTANTS_QuadraticNonMonicGCD.time_op(2, 'sparse') |
| - | 211±0.4ms | 70.4±0.09ms | 0.33 | polys.TimeSUBRESULTANTS_QuadraticNonMonicGCD.time_op(3, 'sparse') |
| - | 6.40±0.01ms | 534±1μs | 0.08 | polys.TimeSUBRESULTANTS_SparseGCDHighDegree.time_op(3, 'sparse') |
| - | 27.9±0.1ms | 851±2μs | 0.03 | polys.TimeSUBRESULTANTS_SparseGCDHighDegree.time_op(5, 'sparse') |
| - | 611±3μs | 199±0.8μs | 0.33 | polys.TimeSUBRESULTANTS_SparseNonMonicQuadratic.time_op(1, 'sparse') |
| - | 6.53±0.02ms | 202±1μs | 0.03 | polys.TimeSUBRESULTANTS_SparseNonMonicQuadratic.time_op(3, 'sparse') |
| - | 17.1±0.04ms | 207±0.8μs | 0.01 | polys.TimeSUBRESULTANTS_SparseNonMonicQuadratic.time_op(5, 'sparse') |
| - | 164±0.2μs | 90.7±0.2μs | 0.55 | solve.TimeMatrixOperations.time_rref(3, 0) |
| - | 313±0.6μs | 110±0.5μs | 0.35 | solve.TimeMatrixOperations.time_rref(4, 0) |
| - | 31.9±0.07ms | 13.7±0.2ms | 0.43 | solve.TimeSolveLinSys189x49.time_solve_lin_sys |
Full benchmark results can be found as artifacts in GitHub Actions |
This is ready for review. |
@@ -570,6 +580,17 @@ def test_Domain_get_exact(): | |||
assert QQ.frac_field(x, y).get_exact() == QQ.frac_field(x, y) | |||
|
|||
|
|||
def test_Domain_characteristic(): | |||
for F, c in [(FF(3), 3), (FF(5), 5), (FF(7), 7)]: | |||
for R in F, F[x], F.frac_field(x), F.old_poly_ring(x), F.old_frac_field(x): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
R is not used in this loop interior -- is something missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, good point. Fixed.
@@ -71,6 +71,9 @@ def wrapper(f, g): | |||
g = _sympify(g) | |||
if isinstance(g, Poly): | |||
return func(f, g) | |||
elif isinstance(g, Integer): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this is where you special cased Integer (as you referred to in how you fixed the previously commented out tests). Can g
be an int or is that always sympified before it gets here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
g
is sympified 3 lines up from here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
face plant -- thanks for pointing this out LOL
Thanks! |
References to other Issues or PRs
Partial fix for #25653 by disallowing any unification of domains with different characteristic.
Brief description of what is fixed or changed
Previously:
With the PR:
Also adds more consistent handling of
.has_CharacteristicZero
and.characteristic()
for different domains.Other comments
There was one place in the code
Release Notes
GF(p)
withZZ
or other domains would previously result inZZ
(or any other domain). This now results in a UnificationFailed error. Previously unification like e.g.GF(2).unify(GF(3))
would unify to the large characteristic but this now results in UnificationFailed.