Closed stumpc5 closed 6 years ago
Where is the error?
44 is the number of generators of P in n=4;m=11;P = PolynomialRing(QQ,n*m,"x");
, and Sage simply returns (1-t)^P.ngens()
as the denominator. Is this wrong mathematically?
The correct answer, as given in the second computation hilb(std(I))
, is
( 120*t^3 + 135*t^2 + 30*t + 1 ) / (t-1)^14
which is not what Sage outputs. (But the total degree -11
is still correct...)
well, for m=10 you only get the output above due to the fact that numerator has a factor (t-1)27 that gets cancelled.
And for m=11 the numerator is irreducible, so no cancellation happens. Does this mean that it's only due to this cancellation accident in the m=10 case you get the same output in Sage as you expect?
Numerator is computed by Singular and so it should not give any bug, I guess...
Replying to @dimpase:
well, for m=10 you only get the output above due to the fact that numerator has a factor (t-1)27 that gets cancelled.
I am not sure I follow what you mean -- in the m=10 case, the (afaik) correct Hilbert series is
( 84*t^3 + 108*t^2 + 27*t + 1 ) / (1 - t)^13
which is what I get above. But in the m=11 case, the (afaik) correct Hilbert series is
( 120*t^3 + 135*t^2 + 30*t + 1 ) / (1 - t)^14
which is not what I get above. In particular, the numerator output of singular should be divisible by (1-t)^30
, but - as you write - it is irreducible instead.
Replying to @dimpase:
Numerator is computed by Singular and so it should not give any bug, I guess...
At least luisfe on sage-devel (https://groups.google.com/d/msg/sage-devel/tyTDd5dEDGw/8FxH9hUzBwAJ) seems to confirm this to be a bug in Singular
...
Replying to @stumpc5:
Replying to @dimpase:
well, for m=10 you only get the output above due to the fact that numerator has a factor (t-1)27 that gets cancelled.
I am not sure I follow what you mean
You can read the code of I.hilbert_series
to see that it takes I.hilbert_numerator()
, which is computed by Singular (again, read the code), and divides it by (t-1)P.ngens().
-- in the m=10 case, the (afaik) correct Hilbert series is
( 84*t^3 + 108*t^2 + 27*t + 1 ) / (1 - t)^13
which is what I get above. But in the m=11 case, the (afaik) correct Hilbert series is
( 120*t^3 + 135*t^2 + 30*t + 1 ) / (1 - t)^14
which is not what I get above. In particular, the numerator output of singular should be divisible by
(1-t)^30
, but - as you write - it is irreducible instead.
So it is a bug in Singular, indeed.
Replying to @dimpase:
Replying to @stumpc5:
Replying to @dimpase:
You can read the code of
I.hilbert_series
to see that it takesI.hilbert_numerator()
, which is computed by Singular (again, read the code), and divides it by (t-1)P.ngens().
I actually did read the code, but
sage.libs.singular.function_factory.ff.hilb
,Anyway, it seems to be a bug in Singular, so I suggest to leave this ticket open until that is fixed, and then add a doctest for checking...
I would also appreciate if someone knowing how this Hilbert numerator is computed in Singular would send a bug report there (or shows me how to reproduce the bug in Singular).
Replying to @stumpc5:
Anyway, it seems to be a bug in Singular, so I suggest to leave this ticket open until that is fixed, and then add a doctest for checking...
I would also appreciate if someone knowing how this Hilbert numerator is computed in Singular would send a bug report there (or shows me how to reproduce the bug in Singular).
I think you know that in the output of hilb(std(I)) (the part you omitted and indicated by ...) is the numerator that should be divisible by the appropriate power of t-1, but it is not.
As to writing up the corresponding Singular commands to show this... I can do this for you, although I didn't touch it for 5+ years...
Upstream: Not yet reported upstream; Will do shortly.
Replying to @dimpase:
Replying to @stumpc5: I think you know that in the output of hilb(std(I)) (the part you omitted and indicated by ...) is the numerator that should be divisible by the appropriate power of t-1, but it is not.
Oh, I didn't know, thanks. If that is the not correct Singular output, how is the stuff below
// 1 t^0
// 30 t^1
// 135 t^2
// 120 t^3
// dimension (proj.) = 13
then again correct (saying that it gives the numerator divided by the maximal power of (t-1)
?
Replying to @stumpc5:
Replying to @dimpase:
Replying to @stumpc5: I think you know that in the output of hilb(std(I)) (the part you omitted and indicated by ...) is the numerator that should be divisible by the appropriate power of t-1, but it is not.
Oh, I didn't know, thanks. If that is the not correct Singular output, how is the stuff below
// 1 t^0 // 30 t^1 // 135 t^2 // 120 t^3 // dimension (proj.) = 13
then again correct (saying that it gives the numerator divided by the maximal power of
(t-1)
?
It's all a bit Greek to me now, and https://www.singular.uni-kl.de/Manual/latest/sing_310.htm#SEC349 does not help much.
Perhaps there is more than one way to compute this info, and Singular does something leading to the correct answer, even though the data it supplies to Sage is not correct.
You seem to know a reference for the correct answers to this question for all m, no? This would be handy in the bug report upstream.
Replying to @dimpase:
You seem to know a reference for the correct answers to this question for all m, no? This would be handy in the bug report upstream.
This Hilbert series is known (though maybe implicit as some h vector of a simplicial complex), but I don't have a reference at hand. I will try to get one.
The reason it seemed suspicious is that I conjecture a term order for which its initial ideal is the Stanley-Reisner ideal of a simplicial sphere I was studying for completely different reasons. And this example was spit out to contradict that conjecture. But, as often, it was the code that's buggy and and not the conjectural description. That's anyway not yet in a form to be made public.
One would try to compute the same with Macaulay2. Did you try this?
Yes, I did -- here it is the output again (with a few long outputs ...
'ed):
i31 : R = QQ[x11,x12,x13,x14,x15,x16,x17,x18,x19,x110,x111,x21,x22,x23,x24,x25,x26,x27,x28,x29,x210,x211,x31,x32,x33,x34,x35,x36,x37,x38,x39,x310,x311,x41,x42,x43,x44,x45,x46,x47,x48,x49,x410,x411]
o31 = R
o31 : PolynomialRing
i32 : M = matrix{{x11,x12,x13,x14,x15,x16,x17,x18,x19,x110,x111},{x21,x22,x23,x24,x25,x26,x27,x28,x29,x210,x211},{x31,x32,x33,x34,x35,x36,x37,x38,x39,x310,x311},{x41,x42,x43,x44,x45,x46,x47,x48,x49,x410,x411}}
o32 = | x11 x12 x13 x14 x15 x16 x17 x18 x19 x110 x111 |
| x21 x22 x23 x24 x25 x26 x27 x28 x29 x210 x211 |
| x31 x32 x33 x34 x35 x36 x37 x38 x39 x310 x311 |
| x41 x42 x43 x44 x45 x46 x47 x48 x49 x410 x411 |
4 11
o32 : Matrix R <--- R
i33 : I = minors(2,M)
o33 = ...
o33 : Ideal of R
i34 : s = hilbertSeries (R/I)
o34 = ...
o34 : Expression of class Divide
i35 : denominator s
44
o35 = (1 - T)
o35 : Expression of class Product
i36 : n = numerator s
o36 = ...
o36 : ZZ[T]
i37 : factor n
30 2 3
o37 = (- 1 + T) (1 + 30T + 135T + 120T )
o37 : Expression of class Product
by the way, here is what they mean by the 1st and by the 2nd Hilbert series. https://www.singular.uni-kl.de/DEMO_HTML/Examples/Hilbert/index.html
Indeed, this alone seems enough for a bug report. (save the Singular code :-))
Okay, I am sending a bug report to Singular now...
any progress on this?
You find the bug report from Feb at https://www.singular.uni-kl.de:8005/trac/ticket/750, but no one seems to have looked at it so far...
Changed upstream from Not yet reported upstream; Will do shortly. to Reported upstream. No feedback yet.
As rechecked at http://www.singular.uni-kl.de:8002/trac/ticket/750#comment:1, this appears to be an interface bug, and no bug directly in singular.
Looks like an overflow error
sage: QQ['z'](hilb(I, 2))*(1-z)**30-QQ['z'](hilb(I, 1))
// ** _ is no standard basis
// ** _ is no standard basis
-4294967296*z^22 + 4294967296*z^21 - 4294967296*z^20 + 4294967296*z^19 - 4294967296*z^18
sage: factor(4294967296)
2^32
On the singular ticket they observe that what is shown here as the 2nd Hilbert series is actually their 1st Hilbert series.
But the long singular answer should factorise with a factor (1-t)^30
, no ? And it does not!
So (I double checked) this is a bug in singular indeed. Someone should reopen http://www.singular.uni-kl.de:8002/trac/ticket/750
More precisely, the difference between the good result and the singular result is
(2^32) * t^18 * (t^4 - t^3 + t^2 - t + 1)
in singular 4.1.0 (which is the version used by sage and available online)
Okay, I can follow your computation. Is this problem now just a coincidence, or how should it be related to the bug I reported?
The bug I had was that the Sage Hilbert series is the singular second Hilbert series. This is given correctly by the computation 4x10, while the (as you say wrongly computed) first Hilbert series was given for the 4x11 example.
Sage only ever calls the "first Hilbert series". If the result of singular for hilb(I, 1) was correct, the rational function in sage would simplify and its numerator would be the same result as the "second Hilbert series" of singular. The problem is a bug in Singular.
Now we could "fix" this bug by calling instead hilb(I, 2) and changing the sage code, but I would not call that a good solution.
oh, I see, sorry for my ignorance.
Changed upstream from Reported upstream. No feedback yet. to Reported upstream. Developers acknowledge bug.
https://www.singular.uni-kl.de:8005/trac/ticket/750 has been re-opened
Description changed:
---
+++
@@ -1,3 +1,5 @@
+UPSTREAM: https://www.singular.uni-kl.de:8005/trac/ticket/750
+
This works correctly:
Note that in the current version 4.1.1p2.p0 of Singular, there is not a wrong result due to integer overflow, but an honest "int overflow error" is raised.
In my computations of group cohomology, I suffered from these overflow errors as well, which is why I opened #26243 and provided an implementation of Hilbert series computations that goes beyond Singular's limitations.
My implementation is not much slower than Singular in the examples in which Singular works. However, in #26243, I do not propose to use my implementation as default way to compute Hilbert series (in particular, I didn't touch the .hilbert_numerator()
method of multipolynomial ideals). However, if you consider to use it in the .hilbert_*()
methods by default in order to fix this ticket: Go ahead!
EDIT: The failing example from here became doctest for the code from #26243.
The code in #25243 has improved, it now beats Singular also speedwise.
So, I suggest to use #25243 here.
Replying to @simon-king-jena:
The code in #25243 has improved, it now beats Singular also speedwise.
So, I suggest to use #25243 here.
Typo: #26243 :P
Dependencies: #26243
Replying to @simon-king-jena:
However, in #26243, I do not propose to use my implementation as default way to compute Hilbert series (in particular, I didn't touch the
.hilbert_numerator()
method of multipolynomial ideals). However, if you consider to use it in the.hilbert_*()
methods by default in order to fix this ticket: Go ahead!
+1 to this. I may work on it this coming week if no one else volunteers, but be advised that various obligations mean I'm slow.
If I see that correctly, the following functions need to be taken care of (all in sage.rings.polynomial.multi_polynomial_ideal):
hilbert_series
: Here we can use what I called hilbert_poincare_series
in sage.rings.hilbert (name according to both the book of Greuel and Pfister, and to the article of Bigatti).hilbert_numerator
: Here we can use what I called first_hilbert_series
in sage.rings.hilbert (name according to the book of Greuel and Pfister).hilbert_polynomial
: This needs to be re-implemented.If I understand correctly, one wouldn't provide degree weights for hilbert_polynomial
, and I think it is easy enough to follow Definition 5.1.4 in the Greuel-Pfister book.
Replying to @simon-king-jena:
If I see that correctly, the following functions need to be taken care of (all in sage.rings.polynomial.multi_polynomial_ideal):
hilbert_series
: Here we can use what I calledhilbert_poincare_series
in sage.rings.hilbert (name according to both the book of Greuel and Pfister, and to the article of Bigatti).hilbert_numerator
: Here we can use what I calledfirst_hilbert_series
in sage.rings.hilbert (name according to the book of Greuel and Pfister).
Thanks. I'll aim for that.
hilbert_polynomial
: This needs to be re-implemented.
I have done that before, so I should be able to do it for this. :-)
If I understand correctly, one wouldn't provide degree weights for
hilbert_polynomial
...
Yes, the Hilbert series is non-polynomial for non-standard weights, and I understand that finding formulas for this is an area of research that no one is actually involved in, unless someone extended the work of Massimo Caboara's Master's student about 4-5 years ago.
Replying to @johnperry-math:
Replying to @simon-king-jena:
If I see that correctly, the following functions need to be taken care of (all in sage.rings.polynomial.multi_polynomial_ideal):
hilbert_series
: Here we can use what I calledhilbert_poincare_series
in sage.rings.hilbert (name according to both the book of Greuel and Pfister, and to the article of Bigatti).hilbert_numerator
: Here we can use what I calledfirst_hilbert_series
in sage.rings.hilbert (name according to the book of Greuel and Pfister).Thanks. I'll aim for that.
hilbert_polynomial
: This needs to be re-implemented.I have done that before, so I should be able to do it for this. :-)
I'm almost done and will probably submit it later today. But of course I'd be glad about a review.
Branch: u/SimonKing/Hilbert_series_bug
Commit: dcc3f17
Author: Simon King
With the new commit, the stuff from #26243 is used for all Hilbert series computations. The tests in sage/rings/polynomial pass, so, I guess it is "needs review" (I trust that the patchbot will run full tests).
For the record, here is a timing that comes out of some of my cohomology computations, in a size that Singular can manage:
sage: I
Ideal (a_1_0^2, a_1_0*b_1_1, b_2_2*a_1_0, b_2_3*a_1_0, b_2_1*b_1_1, a_1_0*b_3_4, a_1_0*b_3_5, a_1_0*b_3_6, b_2_1*b_2_2, b_1_1*b_3_5, b_4_10*a_1_0, b_2_1*b_3_4, b_2_1*b_3_6, b_2_2*b_3_5, b_4_10*b_1_1 + b_2_3*b_3_4 + b_2_3^2*b_1_1 + b_2_2*b_3_6, a_1_0*b_5_17, b_2_1*b_4_10 + b_2_1*b_2_3^2, b_3_4^2 + b_1_1^3*b_3_6 + b_2_2*b_1_1*b_3_4 + b_2_2*b_2_3*b_1_1^2 + b_2_2^3, b_3_4*b_3_5, b_3_4*b_3_6 + b_1_1*b_5_17 + b_2_3*b_1_1*b_3_6 + b_2_3*b_1_1*b_3_4 + b_2_2^2*b_2_3, b_3_5^2 + b_2_1*b_2_3^2, b_3_5*b_3_6, b_3_6^2 + b_2_3*b_1_1*b_3_6 + b_2_2*b_2_3^2 + c_4_11*b_1_1^2, b_2_1*b_5_17, b_4_10*b_3_4 + b_2_3*b_1_1^2*b_3_6 + b_2_3^2*b_3_4 + b_2_2*b_5_17 + b_2_2*b_2_3*b_3_6 + b_2_2*b_2_3^2*b_1_1, b_4_10*b_3_5 + b_2_3^2*b_3_5, b_4_10*b_3_6 + b_2_3*b_5_17 + b_2_3^2*b_3_4 + b_2_2*b_2_3*b_3_6 + b_2_2*c_4_11*b_1_1, b_4_10^2 + b_2_3^2*b_1_1*b_3_6 + b_2_3^4 + b_2_2*b_2_3*b_4_10 + b_2_2^2*c_4_11, b_3_4*b_5_17 + b_2_3*b_1_1*b_5_17 + b_2_3^2*b_1_1*b_3_6 + b_2_3^2*b_1_1*b_3_4 + b_2_2*b_1_1*b_5_17 + b_2_2^2*b_4_10 + c_4_11*b_1_1^4, b_3_5*b_5_17, b_3_6*b_5_17 + b_2_3^2*b_1_1*b_3_6 + b_2_2*b_2_3*b_4_10 + c_4_11*b_1_1*b_3_4 + b_2_3*c_4_11*b_1_1^2, b_4_10*b_5_17 + b_2_3^3*b_3_6 + b_2_3^3*b_3_4 + b_2_2*b_2_3*b_5_17 + b_2_2*b_2_3^2*b_3_6 + b_2_3*c_4_11*b_1_1^3 + b_2_2*c_4_11*b_3_4 + b_2_2*b_2_3*c_4_11*b_1_1, b_5_17^2 + b_2_3^3*b_1_1*b_3_6 + b_2_2*b_2_3*b_1_1*b_5_17 + b_2_2*b_2_3^2*b_1_1*b_3_6 + b_2_2*b_2_3^4 + b_2_2^2*b_2_3*b_4_10 + c_4_11*b_1_1^3*b_3_6 + b_2_3*c_4_11*b_1_1^4 + b_2_3^2*c_4_11*b_1_1^2 + b_2_2*c_4_11*b_1_1*b_3_4 + b_2_2*b_2_3*c_4_11*b_1_1^2 + b_2_2^3*c_4_11) of Multivariate Polynomial Ring in b_2_1, b_2_2, b_2_3, b_4_10, c_4_11, a_1_0, b_1_1, b_3_4, b_3_5, b_3_6, b_5_17 over Finite Field of size 2
sage: G = I.groebner_basis() # caching the Gröbner bases
Now, with the new commit:
sage: %timeit I.hilbert_polynomial()
The slowest run took 9.05 times longer than the fastest. This could mean that an intermediate result is being cached.
1000 loops, best of 3: 686 µs per loop
sage: I.hilbert_polynomial()
2/3*t^3 + 4*t^2 + 16/3*t + 1
Without the new commit (i.e., based on using Singular):
sage: %timeit I.hilbert_polynomial()
The slowest run took 8.71 times longer than the fastest. This could mean that an intermediate result is being cached.
100 loops, best of 3: 2.33 ms per loop
sage: I.hilbert_polynomial()
2/3*t^3 + 4*t^2 + 16/3*t + 1
Last 10 new commits:
7698bb6 | Some code optimizations in Hilbert series computation |
8ae070b | Use flint polynomial boilerplate for Hilbert series computation |
d997abe | Fix a corner case in Hilbert series computation |
5af3439 | Fix the erroneous fix of some corner cases |
138f85b | Turn some functions of polynomial.hilbert to methods of ETuple |
e900222 | Hilbert series: Remove unnecessary bound checks, simplify code branches |
f0e5c85 | Add documentation to new ETuple methods |
2d29b9b | Using slices, custom median, and formatting/P#P8 tweaks to Hilbert code. |
07ff2e1 | Reverting use of get_exp for __getitem__. |
dcc3f17 | Do not use Singular for Hilbert series computations |
Impressive speedup! Where does it come from? A better algorithm?
Replying to @dimpase:
Impressive speedup! Where does it come from? A better algorithm?
I am not totally sure. We have to distinguish: hilbert_numerator
and hilbert_series
on the one hand, and hilbert_polynomial
on the other hand.
The computation of "first Hilbert series" (also known as "Hilbert numerator") and "Hilbert-Poincaré series" (also known as "Hilbert series") relies on a new implementation introduced at #26243. The original motivation was to allow for really big computations (>70 variables, >2000 ideal generators) that would fail in Singular because of its 32-bit integer limitation. But in the end, it was also about speed: The new implementation beats Singular in medium size examples.
The algorithm for the Hilbert-Poincaré series isn't exactly new, but differs from what is done in Singular as follows. Let I
be a monomial ideal in a multivariate polynomial Ring R
and let m
be a monomial of degree d
. Then, I think all implementations for the computation of the Hilbert-Poincaré series HP(R/I)
rely on the equation HP(R/I) = HP(R/(I+m))+t^d*HP(R/(I:(m)))
. The differences lie in the choice of m. Some systems choose m as one of the generators of I and read the above equation backwards: HP(R/(I+m)) = HP(R/I) - t^d*HP(R/(I:(m)))
. Singular chooses m to be a variable that appears in at least one generator of degree >1 of I. I think CoCoA uses the gcd of two randomly chosen generators. My implementation chooses m to be the variable that appears most frequently in the generators of I, to the power of the median of all exponents of that variable in the generators of I.
I was told by John Perry that this choice is known in the literature, but I don't have a reference. Anyway, I think part of the speedup is due to good data structures and careful usage of Cython.
However, all of the above doesn't apply here. With the example of the above timing for hilbert_polynomial
, the timings for hilbert_numerator
and hilbert_series
have hardly changed. With Singular:
sage: %timeit I.hilbert_numerator()
The slowest run took 4.14 times longer than the fastest. This could mean that an intermediate result is being cached.
1000 loops, best of 3: 270 µs per loop
sage: %timeit I.hilbert_series()
The slowest run took 5.27 times longer than the fastest. This could mean that an intermediate result is being cached.
1000 loops, best of 3: 375 µs per loop
With the new implementation:
sage: %timeit I.hilbert_numerator()
1000 loops, best of 3: 280 µs per loop
sage: %timeit I.hilbert_series()
The slowest run took 5.73 times longer than the fastest. This could mean that an intermediate result is being cached.
1000 loops, best of 3: 367 µs per loop
So, in this example, the change really is in the computation of hilbert_polynomial
. Since my code is just straight forward, I really don't know why the old code was so much slower.
Branch pushed to git repo; I updated commit sha1. New commits:
6318242 | Fix a sign in Hilbert polynomial computation |
By playing with a bigger example (where I
is the ideal defined in the attachment to #26243), I found that I got the sign wrong, meaning that depending on the example I got the correct polynomial or its negative. The new commit fixes it.
With the new commit and the example from #26243, I get consistent results (i.e., the Hilbert polynomial seems to return the coefficients of the Hilbert-Poincaré series for all but finitely many degrees):
sage: P = PowerSeriesRing(QQ,'t',default_prec=50)
sage: hp = I.hilbert_series()
sage: hs = P(hp.numerator())/P(hp.denominator())
sage: hs
1 + 77*t + 436*t^2 + 1396*t^3 + 3446*t^4 + 7194*t^5 + 13376*t^6 + 22856*t^7 + 36626*t^8 + 55806*t^9 + 81644*t^10 + 115516*t^11 + 158926*t^12 + 213506*t^13 + 281016*t^14 + 363344*t^15 + 462506*t^16 + 580646*t^17 + 720036*t^18 + 883076*t^19 + 1072294*t^20 + 1290346*t^21 + 1540016*t^22 + 1824216*t^23 + 2145986*t^24 + 2508494*t^25 + 2915036*t^26 + 3369036*t^27 + 3874046*t^28 + 4433746*t^29 + 5051944*t^30 + 5732576*t^31 + 6479706*t^32 + 7297526*t^33 + 8190356*t^34 + 9162644*t^35 + 10218966*t^36 + 11364026*t^37 + 12602656*t^38 + 13939816*t^39 + 15380594*t^40 + 16930206*t^41 + 18593996*t^42 + 20377436*t^43 + 22286126*t^44 + 24325794*t^45 + 26502296*t^46 + 28821616*t^47 + 31289866*t^48 + 33913286*t^49 + O(t^50)
sage: p = I.hilbert_polynomial()
sage: p(t=1) # the only exception
86
sage: p(t=2)
436
sage: p(t=3)
1396
sage: p(t=4)
3446
sage: p(t=5)
7194
sage: p(t=20)
1072294
sage: p(t=40)
15380594
Branch pushed to git repo; I updated commit sha1. New commits:
ae4a2fc | Add consistency check for Hilbert polynomial and fix a corner case |
UPSTREAM: https://www.singular.uni-kl.de:8005/trac/ticket/750
This works correctly:
but if I increase the number of columns by one, I get
which is clearly not correct, as it can be checked with
Depends on #26243
Upstream: Reported upstream. Developers acknowledge bug.
Component: commutative algebra
Keywords: Hilbert series, polynomial ring
Author: Simon King
Branch/Commit:
a1545cc
Reviewer: Travis Scrimshaw
Issue created by migration from https://trac.sagemath.org/ticket/20145