The behavior of empty sums

56 views
Skip to first unread message

Peter Luschny

unread,
Jun 17, 2019, 5:18:06 AM6/17/19
to sage-support
Hi,

I think we should be confident that the sum of integers is 
again an integer, the sum of rational numbers a rational number 
and that the sum of polynomials is a polynomial.

With Sage this is not the case.

def ib(m, n): return sum(binomial(m*n-1, m*k)*OmegaPolynomial(m,k) for k in (0..n-1))

The terms "binomial(m*n-1, m*k)*OmegaPolynomial(m,k)" are of type 
<type 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'>

However "for n in (0..6): print(ib(2, n).list())" yields an
AttributeError: 'int' object has no attribute 'list'.

OK, it is not difficult to work around this. 
But would you agree to call this behavior a bug?

David Joyner

unread,
Jun 17, 2019, 5:27:52 AM6/17/19
to SAGE support
I don't know what OmegaPolynomial is. However, if you replace it by cyclotomic_polynomial, 
it seems to work as expected, doesn't it?

sage: def ib(m, n): return sum(binomial(m*n-1, m*k)*cyclotomic_polynomial(m*(k+1)) for k in (0..n-1))

sage: ib(2,2)

3*x^2 + x + 4

sage: type(ib(2,2))

<type 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'>

sage: ib(2,2).list()

[4, 1, 3]
 

--
You received this message because you are subscribed to the Google Groups "sage-support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sage-support...@googlegroups.com.
To post to this group, send email to sage-s...@googlegroups.com.
Visit this group at https://groups.google.com/group/sage-support.
To view this discussion on the web visit https://groups.google.com/d/msgid/sage-support/de96a2b1-562c-4c09-9c38-07685a5bff4c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Peter Luschny

unread,
Jun 17, 2019, 5:37:56 AM6/17/19
to sage-support
I don't know what OmegaPolynomial is. However, if you replace it by cyclotomic_polynomial, 
it seems to work as expected, doesn't it?

No, it does not. You missed the question.
 

sage: def ib(m, n): return sum(binomial(m*n-1, m*k)*cyclotomic_polynomial(m*(k+1)) for k in (0..n-1))

sage: ib(2,2)

3*x^2 + x + 4

sage: type(ib(2,2))

<type 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'>

sage: ib(2,2).list()

[4, 1, 3]

Execute 
    for n in (0..6): print(ib(2, n).list()
as indicated.
  

David Joyner

unread,
Jun 17, 2019, 7:38:42 AM6/17/19
to SAGE support
 for n in (1..6): 
   print(ib(2, n).list())

works fine for me. Again, I don't know what OmegaPoly
is but my guess is that it's not defined when n=0. For example,

 for n in (0..6): 
   print(ib(2, n).list())

doesn't work because the cyclotomic_poly isn't
defined at n=0. Are you saying, the error message it spits out,
AttributeError: 'int' object has no attribute 'list',
is misleading? 

I guess I'm being dense this morning but I don't understand 
why you think there is something wrong with the sum command.


--
You received this message because you are subscribed to the Google Groups "sage-support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sage-support...@googlegroups.com.
To post to this group, send email to sage-s...@googlegroups.com.
Visit this group at https://groups.google.com/group/sage-support.

Peter Luschny

unread,
Jun 17, 2019, 8:12:58 AM6/17/19
to sage-support
 
Are you saying, the error message it spits out,
AttributeError: 'int' object has no attribute 'list',
is misleading? 

As I see it the problem is that the sum runs over (0..n-1).
Thus for n = 0 it returns by convention the integer 0 for the
empty sum (is this correct?) which of course has no list.

But shouldn't it return the null polynomial in this case? 
And isn't the null polynomial represented by the empty list? 

Message has been deleted

luisfe

unread,
Jun 17, 2019, 8:27:40 AM6/17/19
to sage-support


On Monday, June 17, 2019 at 2:12:58 PM UTC+2, Peter Luschny wrote:

As I see it the problem is that the sum runs over (0..n-1).
Thus for n = 0 it returns by convention the integer 0 for the
empty sum (is this correct?) which of course has no list.

But shouldn't it return the null polynomial in this case? 
And isn't the null polynomial represented by the empty list? 


No, because sum has no way to know that you are expecting a polynomial. You can add a zero polynomial to make the sum over it to obtain a polynomial as a result. With David function:

sage: R=ZZ['x']
sage: zero = R(0)
sage: def ib(m, n): return sum([binomial(m*n-1, m*k)*cyclotomic_polynomial(m*(k+1)) for k in (0..n-1)], zero)
sage: type(ib(2,2))
<type 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'>
sage: ib(2,0)
0
sage: type(ib(2,0))
<type 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'>
sage:  for n in (0..6):
....:    print(ib(2, n).list())
....:  
[]
[1, 1]
[4, 1, 3]
[16, -4, 15]
[64, -34, 56, 0, 7]
[256, -134, 171, -9, 93]
[1024, -494, 539, -165, 638]

Vincent Delecroix

unread,
Jun 23, 2019, 10:21:16 AM6/23/19
to sage-s...@googlegroups.com
The SageMath function sum accepts an optional "zero" argument precisely
for this purpose

sage: sum([], 0)
0
sage: sum([], 11)
11
sage: sum([], [])
[]

Peter Luschny

unread,
Jun 25, 2019, 4:03:03 AM6/25/19
to sage-support

Am Montag, 17. Juni 2019 14:27:40 UTC+2 schrieb luisfe:
On Mon, Jun 17, 2019 at 5:18 AM Peter Luschny <peter....@gmail.com> wrote:
def ib(m, n): return sum(binomial(m*n-1, m*k)*OmegaPolynomial(m,k) for k in (0..n-1))

The terms "binomial(m*n-1, m*k)*OmegaPolynomial(m,k)" are of type 
<type 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'

But shouldn't it return the null polynomial in this case? 
And isn't the null polynomial represented by the empty list? 

No, because sum has no way to know that you are expecting a polynomial.

How that? Look at the output above. Sage *knows* that the terms of the sum 
are polynomials. So it should return the zero of that ring, which is the null polynomial.

slelievre

unread,
Jun 25, 2019, 4:31:54 AM6/25/19
to sage-support
Would you share the definition of OmegaPolynomial?
This would help figure out / explain what the issue is.

luisfe

unread,
Jun 25, 2019, 4:49:44 AM6/25/19
to sage-support


On Tuesday, June 25, 2019 at 10:03:03 AM UTC+2, Peter Luschny wrote:
How that? Look at the output above. Sage *knows* that the terms of the sum 
are polynomials. So it should return the zero of that ring, which is the null polynomial.


Not in the first case, look at what are you passing to sum as argument

sage: sage: R=ZZ['x']
sage: R=ZZ['x']
sage: def ib(m, n): return [binomial(m*n-1, m*k)*cyclotomic_polynomial(m*(k+1)) for k in (0..n-1)]

sage: for n in (0..6):
....:     print(ib(2,n))
....:    
[]
[x + 1]
[x + 1, 3*x^2 + 3]
[x + 1, 10*x^2 + 10, 5*x^2 - 5*x + 5]
[x + 1, 21*x^2 + 21, 35*x^2 - 35*x + 35, 7*x^4 + 7]
[x + 1, 36*x^2 + 36, 126*x^2 - 126*x + 126, 84*x^4 + 84, 9*x^4 - 9*x^3 + 9*x^2 - 9*x + 9]
[x + 1, 55*x^2 + 55, 330*x^2 - 330*x + 330, 462*x^4 + 462, 165*x^4 - 165*x^3 + 165*x^2 - 165*x + 165, 11*x^4 - 11*x^2 + 11]
 
When n =0, k ranges from 0 to -1 so there is no k and the list constructed in ib(n,m) is just the empty list. Not an empty list of polynomials, just an empty list.

slelievre

unread,
Jun 25, 2019, 5:29:43 AM6/25/19
to sage-support


Tue 2019-06-25 10:49:44 UTC+2, luisfe:
This is what makes it necessary to define what the sum starts from;
here, the zero in the polynomial ring (instead of the default which is
the integer zero).

So, replace

    sum(binomial(m*n-1, m*k)*OmegaPolynomial(m,k) for k in (0..n-1))

by

    sum((binomial(m*n-1, m*k)*OmegaPolynomial(m, k) for k in (0 .. n-1)), RR['x'].zero()) 

Peter Luschny

unread,
Jun 25, 2019, 6:10:29 AM6/25/19
to sage-s...@googlegroups.com
Am Di., 25. Juni 2019 um 10:49 Uhr 'luisfe' :

| When n =0, k ranges from 0 to -1 so there is no k and the list constructed in ib(n,m)
|  is just the empty list. Not an empty list of polynomials, just an empty list.

Well, then the way 'sum' is implemented is possibly improvable?

The type information for "binomial(m*n-1, m*k)*polynomial(m,k)"
is there, regardless of what the value of the integers m, n, and k is.
(The definition of 'polynomial' here does not matter as long as it is a polynomial.)

To see this try this:

def ib(m, n):
    R = ZZ['x']
    p = lambda m,n,k: binomial(m*n-1, m*k)*cyclotomic_polynomial(m*(k+1))
    print type(R(p(2,n,0)))
    return [p(m,n,k) for k in (0..n-1)]

for n in (0..3):
    r = ib(2,n)
    print(type(r), r)

The output includes in *all* cases
<type 'sage.rings.polynomial.polynomial_integer_dense_flint.Polynomial_integer_dense_flint'>

So why not use this information to return the zero of this ring if the sum 
range (a..b) has not a <= b?

Peter Luschny

unread,
Jun 25, 2019, 6:12:33 AM6/25/19
to sage-s...@googlegroups.com
Am Di., 25. Juni 2019 um 11:29 Uhr schrieb slelievre <samuel....@gmail.com>:
So, replace

    sum(binomial(m*n-1, m*k)*OmegaPolynomial(m,k) for k in (0..n-1))

by

    sum((binomial(m*n-1, m*k)*OmegaPolynomial(m, k) for k in (0 .. n-1)), RR['x'].zero()) 

Now, this is clever! Yes, this works, although I wished this would work automatically.

John H Palmieri

unread,
Jun 25, 2019, 12:51:28 PM6/25/19
to sage-support


On Tuesday, June 25, 2019 at 3:10:29 AM UTC-7, Peter Luschny wrote:
Am Di., 25. Juni 2019 um 10:49 Uhr 'luisfe' :

| When n =0, k ranges from 0 to -1 so there is no k and the list constructed in ib(n,m)
|  is just the empty list. Not an empty list of polynomials, just an empty list.

Well, then the way 'sum' is implemented is possibly improvable?

The type information for "binomial(m*n-1, m*k)*polynomial(m,k)"
is there, regardless of what the value of the integers m, n, and k is.

No, it's not there, that's the problem. Do this:

    sage: def list_polys(m, n): return [binomial(m*n-1, m*k)*cyclotomic_polynomial(m*(k+1)) for k in (0..n-1)]
    sage: list_polys(2,0)
    []

Python evaluates the argument inside sum(...) before applying the sum function to it. In this case, it gets an empty list, and so has no way of knowing whether it came from a polynomial or anything else. I'm not sure what behavior would improve this. If you wanted to try to parse the arguments and determine that the expression binomial(m*n-1, m*k)*cyclotomic_polynomial(m*(k+1)) was supposed to be a polynomial, you need to plug in actual numbers for m, n, and k: Python functions don't have defined output types, so you can't tell what "cyclomic_polynomial(m*(k+1))" will be until you plug in numbers. In this case, m=2 and n=0, but what value should you plug in for k? I can imagine situations where plugging in k=0 is right but k=-1 is wrong, and vice versa, so what would a good default be?

Sage's solution, as pointed out by slelievre, seems like the right choice.
Reply all
Reply to author
Forward
0 new messages