coeffs() & coefficients()

247 views
Skip to first unread message

john_perry_usm

unread,
Nov 26, 2014, 3:06:31 PM11/26/14
to sage-...@googlegroups.com
Hello Sages

Last week (?) I noticed that a program I wrote was making a mistake, because f.coeffs() and f.coefficients() return very different results: the former provides a dense representation (with 0's), the second a sparse one (no 0's, correlating with f.exponents()).

I like this OK, but the help string isn't clear on this: the latter states merely, "Return the coefficients of the monomials appearing in self;" while the former states, "Returns "self.list()." " The help on self.list() states merely, "Returns a list with the coefficients of self."

So the difference is that one states "monomials appearing in self," while the other does not clarify that it gives the monomials appearing in self, which presumably means it includes monomials not appearing in self. I'm not good at these kinds of inferences, so this does not immediately convey "dense" or "sparse representation," or not to me, anyway.

I would propose the following:

f.coeffs? should state something to the effect of, "Returns all the coefficients of a dense representation of f."

f.coefficients? should state something like, "Returns all the coefficients of a sparse representation of f; that is, it returns only the non-zero coefficients, in a list correlated with f.exponents." (Notice the explicit statement of the correlation, reinforcing sparse representation.)

f.list? should be mostly identical to f.coeffs?

I'm willing to open a ticket & author a patch to this effect, if at least one other person agrees here.

john perry

Bruno Grenet

unread,
Nov 26, 2014, 3:29:18 PM11/26/14
to sage-...@googlegroups.com
Hello John,

As a very regular user of these functions, I think this is useful to have both (and luckily you don't want to remove one or the other!). For the documentation, I agree that it could and should be clearer!

For your proposition, I am quite reluctant on using "dense" and "sparse" in the documentation: There exist dense and sparse representations of polynomials in Sage, and I wonder if this would not confuse users. Some may think that f.coeffs is for densely represented polynomials and f.coefficients for sparsely represented ones.

I think one could use as inspiration for the documentation of f.coefficients() the case of multivariate polynomials. It states "Return the nonzero coefficients of this polynomials in a list." I find this formulation clear and simple enough. It is not clear to me that one should add the part one the correlation with f.exponents() that you proposed.

In the same vein, I would propose "Return all the coefficients of f in a list, including the coefficients equal to zero" for f.coeffs.

Anyway, I agree and you can open a ticket, I'll be happy to review it!

Cheers,
Bruno

P.S.: On a related note, I am procrastinating for some time now the opening of a ticket to make the interfaces of univariate polynomial rings and multivariate polynomial rings more consistent. For instance, the leading coefficient is f.leading_coefficient() in the former and f.lc() in the latter. Many other things like that are a bit frustrating...
--
You received this message because you are subscribed to the Google Groups "sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sage-devel+...@googlegroups.com.
To post to this group, send email to sage-...@googlegroups.com.
Visit this group at http://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.

Simon King

unread,
Nov 26, 2014, 3:35:51 PM11/26/14
to sage-...@googlegroups.com
Hi John,

On 2014-11-26, john_perry_usm <john....@usm.edu> wrote:
> I would propose the following:
>
> *f.coeffs?* should state something to the effect of, "Returns all the
> coefficients of a dense representation of f."
>
> *f.coefficients?* should state something like, "Returns all the
> coefficients of a sparse representation of f; that is, it returns only the
> non-zero coefficients, in a list correlated with f.exponents." (Notice the
> explicit statement of the correlation, reinforcing sparse representation.)
>
> *f.list?* should be mostly identical to f.coeffs?
>
> I'm willing to open a ticket & author a patch to this effect, if at least
> one other person agrees here.

It is about the documentation, without changing the code (so, no harm
would result to applications). As usual, explicit is better then the
need to infer the meaning of the doc. So, +1 from me.

Cheers,
Simon



john_perry_usm

unread,
Nov 26, 2014, 4:30:56 PM11/26/14
to sage-...@googlegroups.com
Thanks, everyone. I agree with Bruno's improvement on my suggestion. I will do this in the next few days, but I am first traveling, & I may need a reminder.

I also think the interfaces between univariate & multivariate polynomials should be brought more in line, but that seems like quite a bit of work. Perhaps we could somehow sketch a partial beginning with obvious improvements, & implement that?

john perry

Francis Clarke

unread,
Nov 27, 2014, 4:35:22 AM11/27/14
to sage-...@googlegroups.com


On Wednesday, November 26, 2014 8:06:31 PM UTC, john_perry_usm wrote:
I would propose the following:

f.coeffs? should state something to the effect of, "Returns all the coefficients of a dense representation of f."

f.coefficients? should state something like, "Returns all the coefficients of a sparse representation of f; that is, it returns only the non-zero coefficients, in a list correlated with f.exponents." (Notice the explicit statement of the correlation, reinforcing sparse representation.)

It seems to me that as a general principle, a method whose name is an abbreviation of the name of another method should actually be the same method.  Anything else is hugely confusing to a user.  Both the functionalities described are, of course, useful, but giving them such similar names has a times certainly confused me.

Francis Clarke

Nathann Cohen

unread,
Nov 27, 2014, 4:47:56 AM11/27/14
to Sage devel
> It seems to me that as a general principle, a method whose name is an
> abbreviation of the name of another method should actually be the same
> method. Anything else is hugely confusing to a user. Both the
> functionalities described are, of course, useful, but giving them such
> similar names has a times certainly confused me.

+1

In order to keep the two features, however, what would you think of a
solution with coeffs, coefficients_list and coefficients_dict ? It
does not look very clean, but that is the only way I see to make it
clearer while not removing the abbreviation.

This would require a deprecation for "coefficients", though.

Alternative solution: it is possible to make coeffs an alias to
coefficients, and to give them both the two features.

coeffs(dense=True) == coefficients(dense=True)
coeffs(sparse=True) == coefficients(sparse=True)

This would require to pick a default value for sparse/dense, which
also means that one of the two functions will have to display a
deprecation warning for a while.

Nathann

Bruno Grenet

unread,
Nov 27, 2014, 5:23:09 AM11/27/14
to sage-...@googlegroups.com
While I agree that the current names can be confusing, we have to be
careful not to make something even more confusing. As mentioned earlier
by John, f.coefficients() is "correlated" with f.exponents() and I think
it is a good feature to keep, and similarly I find important to keep the
consistency with multivariate polynomials (for which only the notion of
"nonzero coefficients" make sense).

The difficulty to my mind, and this may have historically lead to the
current situation, is that for the reasons I mentioned I think that
f.coefficients() should return the nonzero coefficients, and on the
other hand it is also important to have a simple way to ask for the list
of all the coefficients. That's why I find the current situation better
than having a argument "sparse/dense=True" to the function. For the
other proposal of Nathann (coeffs, coefficients_list,
coefficients_dict), I do not find it less confusing since I do not know
which one(s) return the nonzero coefficients and which one(s) return the
full list of coefficients!

Of course, proposing the statu quo may be unpopular ;-). Another
solution I can propose is to keep f.coefficients() as it is, make
f.coeffs() an alias of the former, and only keep f.list() for the list
of all the coefficients.

Cheers,
Bruno

Nathann Cohen

unread,
Nov 27, 2014, 5:29:35 AM11/27/14
to Sage devel
> Of course, proposing the statu quo may be unpopular ;-). Another solution I
> can propose is to keep f.coefficients() as it is, make f.coeffs() an alias
> of the former, and only keep f.list() for the list of all the coefficients.

If I understand what you said, you want "coefficients" to be left
unchanged for compatibility reasons with other classes, and you want
an easy way to get the *list* of coefficients too. While I do not see
why this dense/sparse=True argument would be a problem (it is only
optional, the default behaviour would not change), what about doing
that:

1) Remove .coeffs
2) Update the doc of coefficients to hint that the *list* of
coefficients can be obtained through list(P), or P.list ?

I thought that we tried in Sage to avoid short names/abbreviations
anyway, and it would also avoid the problem raised by Francis: a
function whose name abbreviates another's should be an alias, nothing
else.

Nathann

Bruno Grenet

unread,
Nov 27, 2014, 5:38:51 AM11/27/14
to sage-...@googlegroups.com, Nathann Cohen
Le 27/11/2014 11:29, Nathann Cohen a écrit :
>> Of course, proposing the statu quo may be unpopular ;-). Another solution I
>> can propose is to keep f.coefficients() as it is, make f.coeffs() an alias
>> of the former, and only keep f.list() for the list of all the coefficients.
> If I understand what you said, you want "coefficients" to be left
> unchanged for compatibility reasons with other classes, and you want
> an easy way to get the *list* of coefficients too. While I do not see
> why this dense/sparse=True argument would be a problem (it is only
> optional, the default behaviour would not change), what about doing
> that:
>
> 1) Remove .coeffs
> 2) Update the doc of coefficients to hint that the *list* of
> coefficients can be obtained through list(P), or P.list ?
You understand correctly, and I agree with your proposal (especially
writing in the documentation of .coefficients how to get the full list
of coefficients).

Bruno


Nils Bruin

unread,
Nov 27, 2014, 11:47:56 AM11/27/14
to sage-...@googlegroups.com
On Thursday, November 27, 2014 2:23:09 AM UTC-8, Bruno Grenet wrote:
While I agree that the current names can be confusing, we have to be
careful not to make something even more confusing. As mentioned earlier
by John, f.coefficients() is "correlated" with f.exponents() and I think
it is a good feature to keep,

A drawback of this correlation is that it leads people to the wrong way of accessing this information. If you need both exponents (exponent vectors for multivariate) and the corresponding coefficients, then you should get those tied together. I think f.dict() does this, but I'm not sure if it does it very efficiently. Getting the exponents and coefficients is then just a matter of f.dict().keys() and f.dict().values() [which fully deserve to be called f.exponents() and f. coefficients()]. If "dict" is an inefficient data structure to be using here, perhaps there should be a routine that returns f.dict().items() , in that case obviously *not* going through a dict.

Thierry

unread,
Nov 28, 2014, 8:15:33 AM11/28/14
to sage-...@googlegroups.com
Hi,

if it can help, here are two remarks:

First, P.coeffs does not shortcut anything compared to P.coefficients
because we have tab completion. It even slows things down: if i want
coefficients, i will write P.coe<TAB> and then it will not auto-complete
fully because coeffs adds a breaking node between P.coe and P.coefficients
(and symmetrically) so actually removing P.coeffs will speed things up.

Second, from the new user point of view, the method is called coefficients
not nonzero_coefficients so people use it the straightforward way and
since it works on most tested example, they will not go further in reading
the doc. I have observed the problem with coefficients default behaviour
some times already, see for example :
http://ask.sagemath.org/question/23920/polynomial-in-gfp2/?answer=23922#post-id-23922

The main issue here is that it somehow "fails silently". A common workflow
is to tab-complete for what you are looking for, if something with the
right name appears, try it and use it if it works, look at the
documentation only if your example did not work as expected. A test
polynomial basically looks like 1+2*x+5*x^3 tried with second coeff,
unlikely 1+2*x^4.

Note that everything is already coded as P.dict(), P.__getitem__() and
P.__iter__() so the main question is about visibility and accessibility. A
newcommer is unlikely to look at the P.dict() method while tab-completing
(even less P.__getitem__([2,3]) nor P([2,3])), while the word
"coefficients" immediately makes sense and deserves having a try.

If i had two gifts "coefficients" and "dict" to offer to a developper and
a newcommer, it is not clear i would have done the current choice,
newcomers are not subscribed to sage-devel however.

By the way, i found 'nonzero' much easier to understand than 'sparse' in
this context.

Ciao,
Thierry



On Wed, Nov 26, 2014 at 12:06:31PM -0800, john_perry_usm wrote:
> Hello Sages
>
> Last week (?) I noticed that a program I wrote was making a mistake,
> because f.coeffs() and f.coefficients() return very different results: the
> former provides a dense representation (with 0's), the second a sparse one
> (no 0's, correlating with f.exponents()).
>
> I like this OK, but the help string isn't clear on this: the latter states
> merely, "Return the coefficients of the monomials appearing in self;" while
> the former states, "Returns "self.list()." " The help on self.list() states
> merely, "Returns a list with the coefficients of self."
>
> So the difference is that one states "monomials *appearing* in self," while
> the other does not clarify that it gives the monomials appearing in self,
> which presumably means it includes monomials *not* appearing in self. I'm
> not good at these kinds of inferences, so this does not immediately convey
> "dense" or "sparse representation," or not to me, anyway.
>
> I would propose the following:
>
> *f.coeffs?* should state something to the effect of, "Returns all the
> coefficients of a dense representation of f."
>
> *f.coefficients?* should state something like, "Returns all the
> coefficients of a sparse representation of f; that is, it returns only the
> non-zero coefficients, in a list correlated with f.exponents." (Notice the
> explicit statement of the correlation, reinforcing sparse representation.)
>
> *f.list?* should be mostly identical to f.coeffs?
>
> I'm willing to open a ticket & author a patch to this effect, if at least
> one other person agrees here.
>
> john perry
>

rjf

unread,
Nov 30, 2014, 3:06:28 AM11/30/14
to sage-...@googlegroups.com
maybe this could be added.
A method called something like ExponentCoeffPairsExcludingZeros,

which would return a list of    <exponent,coeff>  pairs,  in some exponent order.
Maybe that's inconvenient in Python/sympy.
RJF


Volker Braun

unread,
Nov 30, 2014, 6:37:35 AM11/30/14
to sage-...@googlegroups.com
You want this one:

sage: R.<x,y> = QQ[]
sage: (x^2+2*y+1).dict()
{(0, 0): 1, (0, 1): 2, (2, 0): 1}

Ralf Stephan

unread,
Dec 3, 2014, 4:27:53 AM12/3/14
to sage-...@googlegroups.com
Sorry, a bit late. I also agree with removing coeffs and referring to list in the documentation of coefficients

What's more, the issue comes up with symbolic expressions too, where coeffs is an alias of coefficients, and there is no list function. This would be the perfect opportunity to unify methods over both symbolic, poly, and series rings, so, as it appears agreement was reached, I have opened a ticket for the symbolics part for

 * adding a `sparse` parameter to `Expression.coefficients()`, default `True`
 * removing/deprecating the `coeff` and `coeffs` aliases
 * implement `Expression.list()`, simply calling `coefficients(sparse=False)`


Can the coeffs alias be immediately removed? Is a deprecation of an alias needed?

Regards,

Samuel Lelievre

unread,
Dec 3, 2014, 9:56:37 AM12/3/14
to sage-...@googlegroups.com

Not so fast!

First, not all expressions are polynomial expressions!

Also, why such a hurry to remove stuff immediately?
What's the harm in deprecating first?

john_perry_usm

unread,
Dec 3, 2014, 10:10:23 AM12/3/14
to sage-...@googlegroups.com
Sorry for the delay in replying; as noted earlier, I've been traveling. I agree with Samuel; it's important to deprecate first. Some of us run scripts that will break if you simply remove the command, but a deprecation warning both allows the script to keep running and (if it's a good warning) suggests a solution that helps us move on.

Will the ticket you've opened also deal with multivariate polynomial ideals, or are you working on symbolic expressions only? Just so I know whether to open a new ticket (probably sometime next week; still traveling...)

john perry

Ralf Stephan

unread,
Dec 3, 2014, 10:19:52 AM12/3/14
to sage-...@googlegroups.com
I *did ask if I should deprecate, I just wasn't sure if we can deprecate the alias.

On Wed Dec 03 2014 at 4:10:25 PM john_perry_usm <john....@usm.edu> wrote:
Will the ticket you've opened also deal with multivariate polynomial ideals, or are you working on symbolic expressions only?
 Yes. It's almost always better to split such tickets.

Note that Laurent polys don't have list() but have valuation(), so list() would be useful to have.

Ralf Stephan

unread,
Dec 4, 2014, 4:59:11 AM12/4/14
to sage-...@googlegroups.com
This is now ready. Let's do some mutual review.

First, not all expressions are polynomial expressions!
Indeed, one reason I'm interested in this is symbolic power series:


Also, why such a hurry to remove stuff immediately? 
What's the harm in deprecating first?
I found out that it is straightforward to deprecate an alias only.

Regards,

Nguyen Van Minh Hieu

unread,
Feb 13, 2018, 8:38:04 AM2/13/18
to sage-devel
How do remove .coeffs ? Help me 
Reply all
Reply to author
Forward
0 new messages