Skip to content
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

cleaning and enhancement to PolyDict #34000

Closed
videlec opened this issue Jun 16, 2022 · 41 comments · Fixed by #35174
Closed

cleaning and enhancement to PolyDict #34000

videlec opened this issue Jun 16, 2022 · 41 comments · Fixed by #35174

Comments

@videlec
Copy link
Contributor

videlec commented Jun 16, 2022

We provide some cleaning and speed up to the PolyDict class by always enforcing keys to be ETuple (some parts of the code did assume that was the case). As a consequence we deprecate the usage of the constructor arguments force_int_exponents and force_etuples.

We also simplify the design by getting rid of PolyDict.__zero (and hence deprecating the argument zero of the PolyDict constructor).

Along the way, we fix

sage: R = ZZ['x']['y,z']
sage: y, z = R.gens()
sage: y.integral(y)
1/2*y^2
sage: parent(y.integral(y))
Multivariate Polynomial Ring in y, z over Univariate Polynomial Ring in x over Integer Ring

and

sage: from sage.rings.polynomial.polydict import ETuple
sage: e = ETuple([0, 1, 0])
sage: e.eadd_p(0, 0).nonzero_positions()
[0, 1]

CC: @xcaruso @mezzarobba @saraedum

Component: algebra

Author: Vincent Delecroix

Issue created by migration from https://trac.sagemath.org/ticket/34000

@videlec videlec added this to the sage-9.7 milestone Jun 16, 2022
@videlec

This comment has been minimized.

@videlec
Copy link
Contributor Author

videlec commented Jun 16, 2022

Branch: u/vdelecroix/34000

@videlec
Copy link
Contributor Author

videlec commented Jun 16, 2022

Commit: e48d741

@videlec
Copy link
Contributor Author

videlec commented Jun 16, 2022

New commits:

7deaa2434000: cleaning and enhancement to polydict
e48d74134000: remove PolyDict.__pow__

@mezzarobba
Copy link
Member

comment:3

Two things that I did not understand while skimming through the code:

  • in MPolynomial_polydict.integral(), why do you have two different code paths for determining the result's parent?
  • what do the RuntimeErrors now raised by PolyDict on various occasions correspond to?

@videlec
Copy link
Contributor Author

videlec commented Jun 18, 2022

comment:4

Replying to @mezzarobba:

Two things that I did not understand while skimming through the code:

Thanks for having a look.

  • in MPolynomial_polydict.integral(), why do you have two different code paths for determining the result's parent?

I shamefully copied the code from univariate polynomials, see polynomial_element.pyx#L3980-L3985

  • what do the RuntimeErrors now raised by PolyDict on various occasions correspond to?

One of them is ensuring that keys are ETuple. All others are here because I also made uniform that no coefficient is zero. At least, it did not break any test.

@mezzarobba
Copy link
Member

comment:5

Replying to @videlec:

  • what do the RuntimeErrors now raised by PolyDict on various occasions correspond to?

One of them is ensuring that keys are ETuple. All others are here because I also made uniform that no coefficient is zero. At least, it did not break any test.

Sorry, my question was not clear. I was mostly wondering why you were raising RuntimeErrors rather than ValueErrors/TypeErrors/... (if the purpose was argument checking) or using assertions (if you wanted to guard against things that should never happen).

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 18, 2022

Branch pushed to git repo; I updated commit sha1. New commits:

6eac6b034000: cleaner optimization in derivative/integral
065d42e34000: clarify RuntimeError
48413be34000: two little optimizations

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 18, 2022

Changed commit from e48d741 to 48413be

@videlec
Copy link
Contributor Author

videlec commented Jun 18, 2022

comment:7

Replying to @mezzarobba:

Replying to @videlec:

  • what do the RuntimeErrors now raised by PolyDict on various occasions correspond to?

One of them is ensuring that keys are ETuple. All others are here because I also made uniform that no coefficient is zero. At least, it did not break any test.

Sorry, my question was not clear. I was mostly wondering why you were raising RuntimeErrors rather than ValueErrors/TypeErrors/... (if the purpose was argument checking) or using assertions (if you wanted to guard against things that should never happen).

It is really a RuntimeError : it is assumed that keys are ETuple and coefficients are nonzero.

@videlec
Copy link
Contributor Author

videlec commented Jun 18, 2022

comment:8

I hope I clarified the code related to your comments in ​6eac6b0 and 065d42e.

@videlec
Copy link
Contributor Author

videlec commented Jun 18, 2022

comment:9

Let me change RuntimeError for assertions.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 18, 2022

Branch pushed to git repo; I updated commit sha1. New commits:

f6c689334000: replace RuntimeError with assertion

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 18, 2022

Changed commit from 48413be to f6c6893

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 19, 2022

Changed commit from f6c6893 to 3341a98

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 19, 2022

Branch pushed to git repo; I updated commit sha1. New commits:

3341a9834000: fix Polydict.homogenize and ETuple.eadd_p

@videlec

This comment has been minimized.

@videlec
Copy link
Contributor Author

videlec commented Jun 19, 2022

comment:12

In the last commit I fixed a bug in eadd_p and optimized homogenize in order to fix a bug that show up in doctests from sage.schemes.elliptic_curve.constructor.


New commits:

3341a9834000: fix Polydict.homogenize and ETuple.eadd_p

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 19, 2022

Changed commit from 3341a98 to 0b0e48c

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 19, 2022

Branch pushed to git repo; I updated commit sha1. New commits:

0b0e48c34000: fix zero coefficient in PolyDict.homogenize

@videlec
Copy link
Contributor Author

videlec commented Jun 19, 2022

comment:14
sage -t --long src/sage/rings/tate_algebra_element.pyx  # 5 doctests failed
sage -t --long src/sage/rings/tate_algebra_ideal.pyx  # 3 doctests failed
sage -t --long src/sage/rings/polynomial/multi_polynomial.pyx  # 1 doctest failed

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 19, 2022

Branch pushed to git repo; I updated commit sha1. New commits:

fae4a2534000: make a copy of input in PolyDict.__init__

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 19, 2022

Changed commit from 0b0e48c to fae4a25

@videlec
Copy link
Contributor Author

videlec commented Jun 19, 2022

comment:16

@Xavier Caruso: now that I made systematic zero coefficient removal in polydict.pyx I have trouble with Tate algebras. Namely, it seems that you always want to keep zeros there even though there is no natural way we can make difference between exact and inexact zero in the base ring

sage: R = Zp(2, print_mode='digits', prec=10)
sage: R(0, 5).is_zero()
True
sage: R(0, 5) == R(0)
True
sage: not (R(0, 5) != R(0))
True

This affects code such as

sage: R = Zp(2, print_mode='digits', prec=10)
sage: A.<x,y> = TateAlgebra(R)
sage: f = 1 + 64*x
sage: f -= R(1, 5)
sage: f
...00000 + ...0000000001000000*x

which now returns ...0000000001000000*x.

On the other hand, I believe that the code in Tate algebra is buggy for the following reason. The conversion R -> A does not commute with binary operations

sage: R = Zp(2, print_mode='digits', prec=10)
sage: A.<x,y> = TateAlgebra(R)
sage: A(R(1)) - A(R(1,5))
...00000
sage: A(R(1) - R(1,5))
0

The following is also broken

sage: A({(1,1): R(0,5)})
0

(it should have been R(0,5)*x*y which prints as ...00000*x*y)

The main question is : how do we test whether an element is exactly zero in R ? r.precision_absolute() == infinity and r.is_zero()? I could introduce an attribute zero_test in PolyDict to make this check consistently.

@videlec
Copy link
Contributor Author

videlec commented Jun 19, 2022

comment:17

For the same reason as in comment:16 multivariate polynomials over p-adics are similarly broken in the current sage

sage: R = Zp(2)
sage: Rxy.<x,y> = R[]
sage: Rxy(R(0,5))
0
sage: x - x
0

@videlec
Copy link
Contributor Author

videlec commented Jun 19, 2022

comment:18

Replying to @videlec:

For the same reason as in comment:16 multivariate polynomials over p-adics are similarly broken in the current sage

sage: R = Zp(2)
sage: Rxy.<x,y> = R[]
sage: Rxy(R(0,5))
0
sage: x - x
0

hmm as well as multivariate polynomial rings over power series

sage: R.<x> = PowerSeriesRing(QQ)
sage: A.<y,z> = R[]
sage: O(x^3) * y
0

@xcaruso
Copy link
Contributor

xcaruso commented Jun 19, 2022

comment:19

Replying to @videlec:

The main question is : how do we test whether an element is exactly zero in R ? r.precision_absolute() == infinity and r.is_zero()? I could introduce an attribute zero_test in PolyDict to make this check consistently.

I think you can use the method _is_exact_zero for padics.

I'll have a look at the bug in coercion from base ring to Tate algebra you noticed.

@videlec
Copy link
Contributor Author

videlec commented Jun 19, 2022

comment:20

Replying to @xcaruso:

Replying to @videlec:

The main question is : how do we test whether an element is exactly zero in R ? r.precision_absolute() == infinity and r.is_zero()? I could introduce an attribute zero_test in PolyDict to make this check consistently.

I think you can use the method _is_exact_zero for padics.

Thanks. Though very specific to p-adics. And it does not exist for power series.

I'll have a look at the bug in coercion from base ring to Tate algebra you noticed.

It is not a bug in the coercion system. It is the way elements of the Tate algebra are constructed. The PolyDict class does a cleaning of zero coefficients in its input.

@videlec
Copy link
Contributor Author

videlec commented Jun 19, 2022

comment:21

As far as this ticket is concerned there is an easy way out : leave simplification of zero coefficients in PolyDict to the user (via the PolyDict.remove_zeros method). This will solve the construction issues with Tate algebra.

I opened ticket #34024 to fix polynomials.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 19, 2022

Branch pushed to git repo; I updated commit sha1. New commits:

680f8e034000: do not simplify zero coefficients in PolyDict

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jun 19, 2022

Changed commit from fae4a25 to 680f8e0

@videlec
Copy link
Contributor Author

videlec commented Jun 19, 2022

comment:23

@Xavier Caruso Even with comment:21 implemented I got the following failure

sage -t --random-seed=31078045756822634162710736872151007113 tate_algebra_ideal.pyx
**********************************************************************
File "tate_algebra_ideal.pyx", line 857, in sage.rings.tate_algebra_ideal.groebner_basis_pote
Failed example:
    I.groebner_basis(algorithm="PoTe", prec=100)  # indirect doctest
Expected:
    [...0000000001*x^3 + ...2222222222*y + ...000000000*x^2*y^2 + O(3^99 * <x, y>),
     ...0000000001*x^2*y + ...01210121020 + O(3^100 * <x, y>),
     ...0000000001*y^2 + ...01210121020*x + ...000000000*x^2*y^3 + ...0000000000*x^3*y + O(3^99 * <x, y>)]
Got:
    [...0000000001*x^3 + ...2222222222*y + ...000000000*x^2*y^2 + O(3^99 * <x, y>),
     ...0000000001*x^2*y + ...01210121020 + O(3^100 * <x, y>),
     ...0000000001*y^2 + ...01210121020*x + ...0000000000*x^3*y + O(3^99 * <x, y>)]
**********************************************************************
File "tate_algebra_ideal.pyx", line 1104, in sage.rings.tate_algebra_ideal.groebner_basis_vapote
Failed example:
    I.groebner_basis(algorithm="VaPoTe", prec=100)  # indirect doctest
Expected:
    [...0000000001*x^3 + ...2222222222*y + ...000000000*x^2*y^2 + O(3^99 * <x, y>),
     ...0000000001*x^2*y + ...01210121020 + O(3^100 * <x, y>),
     ...0000000001*y^2 + ...01210121020*x + ...000000000*x^2*y^3 + ...0000000000*x^3*y + O(3^99 * <x, y>)]
Got:
    [...0000000001*x^3 + ...2222222222*y + ...000000000*x^2*y^2 + O(3^99 * <x, y>),
     ...0000000001*x^2*y + ...01210121020 + O(3^100 * <x, y>),
     ...0000000001*y^2 + ...01210121020*x + ...0000000000*x^3*y + O(3^99 * <x, y>)]
**********************************************************************
2 items had failures:
   1 of   9 in sage.rings.tate_algebra_ideal.groebner_basis_pote
   1 of  10 in sage.rings.tate_algebra_ideal.groebner_basis_vapote
    [126 tests, 2 failures, 3.46 s]

Also, it did not magically fix comment:16 since Tate algebras use multivariate polynomials over p-adic rings...

@xcaruso
Copy link
Contributor

xcaruso commented Jun 20, 2022

comment:24

Replying to @videlec:

@Xavier Caruso Even with comment:21 implemented I got the following failure

Hmm. Difficult to say what is the correct answer.
I'll try to investigate this more but maybe, the easiest fix is to change the doctest.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Aug 12, 2022

Branch pushed to git repo; I updated commit sha1. This was a forced push. Last 10 new commits:

54bacfb34000: clarify RuntimeError
1f08c9734000: two little optimizations
e597bd734000: replace RuntimeError with assertion
b6eb9e534000: fix Polydict.homogenize and ETuple.eadd_p
5966dc334000: fix zero coefficient in PolyDict.homogenize
0c026ec34000: make a copy of input in PolyDict.__init__
5e0aa5c34000: do not simplify zero coefficients in PolyDict
49e78f934000: fix doctest in multi_polynomial.pyx
a19ca7c34000: change tate algebras doctests
52c5a2534000: doc details

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Aug 12, 2022

Changed commit from 680f8e0 to 52c5a25

@videlec
Copy link
Contributor Author

videlec commented Aug 12, 2022

comment:26

rebased on 9.7.beta8 and failing doctests modified

@videlec
Copy link
Contributor Author

videlec commented Aug 13, 2022

comment:27

green bot

@tscrim
Copy link
Collaborator

tscrim commented Aug 16, 2022

comment:28

I think some timings are needed here before a positive review to see what sort of speed regressions we incur because we no longer have the option to turn off certain features and checks.

Why is addition the only operation that gets a special in-place operation? I think it would be good to make this universal.

It is generally not a good ideal to check if type(e) is not ETuple:. I understand this is faster than isinstance(e, ETuple), but it is less future-proof if someone subclasses ETuple.

Naively coverage seems to have decreased; e.g., __len__ no longer has documentation. It is a bit of a misdirect that the coverage has increased as it is just total percentage.

@mkoeppe
Copy link
Member

mkoeppe commented Feb 13, 2023

Removed branch from issue description; replaced by PR #35020

@vneiger
Copy link
Contributor

vneiger commented Mar 10, 2023

Just for reference, I want to point out that PR #35174 also seems to fix another bug with eadd_p (in addition, but likely related, to the one mentioned in the initial description of this issue). With the current version 10.0.beta3, the following makes SageMath crash with memory issues such as invalid pointer, invalid next size, ... : ETuple([0,1,1]).eadd_p(1,0) .

The problem seems independent of the nonzero values (the 1's) and seems to persist in lengths 4 and more. E.g. ETuple([0,2,4,3]).eadd_p(5,0) crashes as well, but ETuple([0,2]).eadd_p(5,0) will not crash.

With PR #35174 , and I suppose thanks to this commit , this issues appears to have been solved.

@videlec
Copy link
Contributor Author

videlec commented Mar 18, 2023

Indeed, the nonzero_values is merely here to check consistency of the data. The crash does not systematically happen as the accessed memory might be in the allowed zone.

vbraun pushed a commit that referenced this issue Mar 26, 2023
    
<!-- ^^^^^
Please provide a concise, informative and self-explanatory title.
Don't put issue numbers in there, do this in the PR body below.
For example, instead of "Fixes #1234" use "Introduce new method to
calculate 1+1"
-->
### 📚 Description

Fixes #34000 (and more complete version of the proposition at #35020).

A discussion about the general problem of inexact zeros has been opened
at #35319

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->
<!-- If your change requires a documentation PR, please link it
appropriately -->
<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->

- [x] I have made sure that the title is self-explanatory and the
description concisely explains the PR.
- [x] I have linked an issue or discussion.
- [x] I have created tests covering the changes.
- [x] I have updated the documentation accordingly.
    
URL: #35174
Reported by: Vincent Delecroix
Reviewer(s): Frédéric Chapoton, Travis Scrimshaw, Vincent Delecroix
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants