Opened 5 years ago

Closed 13 months ago

#16613 closed defect (fixed)

fix content of polynomials

Reported by: vdelecroix Owned by:
Priority: major Milestone: sage-8.1
Component: commutative algebra Keywords: polynomial, content
Cc: mkosters, davidloeffler Merged in:
Authors: Bruno Grenet Reviewers: Julian Rüth
Report Upstream: N/A Work issues: followup ticket mentioned in source code, update ticket summary
Branch: 017adb6 (Commits) Commit: 017adb67f3a274526c94b79d3d8683723dc14e80
Dependencies: Stopgaps:

Description (last modified by bruno)

There is an inconsistency between several implementations of methods content for polynomials which either return the gcd of the coefficients or the ideal generated by the coefficients.

To remove the inconsistency, we implement two distinct methods:

  • content returns the gcd of the coefficients;
  • content_ideal returns the ideal generated by the coefficients.

In a period of deprecation, for (most) univariate polynomial rings, content is a deprecated alias for content_ideal. In the future, content will be defined everywhere as described above.

Change History (37)

comment:1 Changed 5 years ago by vbraun_spam

  • Milestone changed from sage-6.3 to sage-6.4

comment:2 Changed 3 years ago by bruno

  • Cc mkosters davidloeffler added
  • Status changed from new to needs_info

The content of a polynomial is sometimes defined as the gcd of its coefficients, and sometimes as the ideal generated by the coefficients. In SageMath, we have inconsistencies between polynomial rings:

  • For Flint, NTL, p-adics and multivariate polynomial rings, content returns the gcd of the coefficients.
  • The generic implementation (for the class rings.polynomial.polynomial_element.Polynomial) returns an ideal. This is means that for polynomials over weird rings, and for all sparsely represented univariate polynomials, content returns an ideal.

I propose to make all the implementations return a element of the base ring rather than an ideal.

Rationale:

  • This means changing only one method.
  • This is consistent with MuPAD, Maple, Mathematica (though the name of the function is different) and Magma (also for the multivariate case)
  • This is the definition taken for instance by von zur Gathen and Gerhard in Modern Computer Algebra or Cohen in A course in Computational Number Theory.

P.S.: I cc the author and reviewer of #12218 in which the generic content was implemented.

comment:3 Changed 3 years ago by bruno

Addendum: One could also let the possibility of having the ideal, with one of the following two propositions. I am not sure this is useful.

  • Add a keyword ideal so that an ideal is returned if ideal is set to True (defaut False).
  • Create a new method content_ideal or ideal_content for today's behavior of the generic implementation.

comment:4 follow-up: Changed 3 years ago by kedlaya

I'm okay with having a method content_ideal for the generic behavior. But what is supposed to be returned by content when the content ideal is not principal? This is certainly likely to happen if the base ring is the ring of integers in a number field. Perhaps it is best if content is only implemented in those cases where it has a sensible definition at the level of elements.

comment:5 in reply to: ↑ 4 Changed 3 years ago by bruno

Replying to kedlaya:

I'm okay with having a method content_ideal for the generic behavior. But what is supposed to be returned by content when the content ideal is not principal? This is certainly likely to happen if the base ring is the ring of integers in a number field. Perhaps it is best if content is only implemented in those cases where it has a sensible definition at the level of elements.

Of course, this is a difficulty... Well, I propose then to implement content for polynomials over principal ideal domains (so that it returns a element of the domain, not an ideal), and content_ideal more generally. And of course to add a deprecation warning for content over non principal ideal domains. We may also add a warning (no deprecation) for the new behavior of content in the generic implementation.

I'll work on a proposal and let you tell me what you think about it.

comment:6 follow-up: Changed 3 years ago by bruno

I am trying to provide some code for this. I'd like opinions on two points:

  1. To avoid future inconsistencies, I plan to implement not only content and content_ideal, but also the related primitive_part and is_primitive for all polynomial rings with consistent semantics. Do you think it is appropriate to do so in this ticket, or do you think that it's better to stick with content and content_ideal only?
  1. What should it be the semantic for fields?

Remarks for the semantics for fields:

Currently, there is a method is_primitive which uses three distinct (and documented!) semantics:

  • An irreducible polynomial of degree m over Fp is primitive if its roots generate Fpm;
  • A polynomial over a ring is primitive if its coefficients generate the unit ideal;
  • Primitivity is undefined for polynomials over an infinite field, that is an exception is raised.

I guess that there should not be any opposition for content_ideal to return the unit ideal. For content, I see three possibilities (there may be more):

  • Raise an exception;
  • Return 1 (or more precisely self._parent.one());
  • Return gcd(self.coefficients()) (knowing that gcd(2/3,4/5)=2/15 with the current semantics for gcd.

And I would say that in all three cases, primitive_part should return self divided by its content, using for content the same semantic as above. Finally, the case of is_primitive is complicated because of the semantic for finite fields. One possibility could be to find another name for this semantic for finite fields but 1. I guess that "primitive" is really the word used in mathematics for this property, and 2. this may break some existing code (and given the current discussions on sage-devel, I doubt the community would favor this!).

P.S.: I really would like that we reach some consensus on the semantics before including any code in order to limit as much as possible future backward incompatible changes!

Last edited 3 years ago by bruno (previous) (diff)

comment:7 in reply to: ↑ 6 Changed 3 years ago by kedlaya

It generally is best for the development workflow if individual tickets are as limited as possible. So I would vote in favor of creating a second ticket to deal with is_primitive and primitive_part after the status of content is resolved.

Regarding primitive, both uses seem to be quite entrenched in the mathematical literature, and so I think we are obliged to maintain the dichotomy.

comment:8 Changed 3 years ago by bruno

  • Authors changed from Vincent Delecroix to Bruno Grenet
  • Branch set to u/bruno/content
  • Commit set to 78d45b9b13fcf242d0f7de248a9891f6a64298a6
  • Description modified (diff)
  • Keywords polynomial content added
  • Status changed from needs_info to needs_review

Based on answers on this ticket and on sage-devel, I've implemented the solution with two methods content and content_ideal. Right now, there is now warning nor deprecation. If necessary, I can add a warning for the generic method content as follows:

from sage.warnings import warn
warn("This method now returns the gcd of the coefficients of the input polynomial. Use content_ideal()` to get the ideal generated by the coefficients.")

comment:9 follow-up: Changed 2 years ago by saraedum

The changes look fine to me. It is my understanding that we should deprecate, i.e., content() should say content() is not going to return an ideal but an element in the future. Use content_ideal() instead.

What do you think?

comment:10 Changed 2 years ago by saraedum

  • Reviewers set to Julian Rüth
  • Status changed from needs_review to needs_info

comment:11 in reply to: ↑ 9 ; follow-up: Changed 2 years ago by bruno

Replying to saraedum:

The changes look fine to me. It is my understanding that we should deprecate, i.e., content() should say content() is not going to return an ideal but an element in the future. Use content_ideal() instead.

Do you mean that right now, content() should still return an ideal but be deprecated, and that it should only later (in one year from now) return the gcd of the coefficients? What about changing the behavior right now, but with a warning? Another idea (to combine both in some sense) is the following:

  • Make content() still return an ideal, with deprecation;
  • Add right now a flag ideal=True to the method, so that people can already use the "new behavior" in their codes, using content(ideal=False);
  • In one year: remove deprecation and make the default value of ideal to False, or even remove completely the ideal=... parameter, or make it useless.

What do you think?

comment:12 in reply to: ↑ 11 Changed 2 years ago by saraedum

Replying to bruno:

Replying to saraedum:

The changes look fine to me. It is my understanding that we should deprecate, i.e., content() should say content() is not going to return an ideal but an element in the future. Use content_ideal() instead.

Do you mean that right now, content() should still return an ideal but be deprecated, and that it should only later (in one year from now) return the gcd of the coefficients?

Yes.

What about changing the behavior right now, but with a warning?

That would certainly break existing code. It points you to the place where you have to fix it so it would be fine with me. I am not sure what our policy is here.

Another idea (to combine both in some sense) is the following:

  • Make content() still return an ideal, with deprecation;
  • Add right now a flag ideal=True to the method, so that people can already use the "new behavior" in their codes, using content(ideal=False);
  • In one year: remove deprecation and make the default value of ideal to False, or even remove completely the ideal=... parameter, or make it useless.

If we go for this we should remove that parameter completely after some time. I am also fine with this approach but I find it a bit weird to do deprecation by introducing something deprecated (the ideal parameter).

What do you think?

I think the first option (do not change content() at first but print a warning) is the cleanest option.

comment:13 Changed 2 years ago by git

  • Commit changed from 78d45b9b13fcf242d0f7de248a9891f6a64298a6 to 57077e53525ae33a8b10c77df307b89709f42c43

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

57077e516613: Deprecate content

comment:14 Changed 2 years ago by git

  • Commit changed from 57077e53525ae33a8b10c77df307b89709f42c43 to 618a016fdda4530d9cada1c1b3b340851d78a99a

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

618a01616613: doctest fix

comment:15 Changed 2 years ago by bruno

  • Status changed from needs_info to needs_review

Ok, I've deprecated content when it existed and returned an ideal, and we'll perform the complete switch later on.

comment:16 Changed 2 years ago by saraedum

  • Status changed from needs_review to needs_info

Does SEEALSO: :meth:content still make sense?

comment:17 Changed 2 years ago by git

  • Commit changed from 618a016fdda4530d9cada1c1b3b340851d78a99a to 78415d78151d2b7632c98cd41b681c4501275faa

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

cb9bbe6Merge branch 'u/bruno/content' of git://trac.sagemath.org/sage into t/16613/content
78415d7Remove unwanted SEEALSO (+ remove trailing spaces)

comment:18 Changed 2 years ago by bruno

  • Status changed from needs_info to needs_review

Removed irrelevant SEEALSO.

comment:19 Changed 2 years ago by tscrim

  • Milestone changed from sage-6.4 to sage-7.6

My 2 cents: I don't like the deprecation of content then only to replace it by something that has different functionality. I am close to considering this a bug, and as such, we do not need to deprecate. So the idea of using a temporary flag, which we then deprecate after we remove the ability to return an ideal from content, is the best way forward IMO. It's two steps, but it is the most consistent with Sage's policies.

comment:20 Changed 20 months ago by git

  • Commit changed from 78415d78151d2b7632c98cd41b681c4501275faa to 00127fdfb079b324f140cf01c354914acf98b865

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

16681f3Merge branch 'develop' into 16613_content
00127fdMerge branch 'u/bruno/content' of git://trac.sagemath.org/sage into 16613_content

comment:21 Changed 20 months ago by bruno

I've merged develop (8.0.beta11) into this ticket's branch since it did not apply.

Now I agree with Travis that the deprecation is a bit a pity. It will force users to make two changes instead of one when they need the content (as a value rather than an ideal): Now they write p.content().gen(), they need to change to p.content_ideal().gen() due to the current deprecation warning, and in some months (years?) they'll finally be able to write p.content() to avoid the useless construction of the ideal. I'm strongly in favor of having a way for users to directly use the new semantic.

As such, I would go for making content return a value without any deprecation. If the there's enough time left, this backward incompatible change may occur with the new release 8.0.

comment:22 Changed 19 months ago by chapoton

  • Status changed from needs_review to needs_work

does not apply

comment:23 Changed 19 months ago by git

  • Commit changed from 00127fdfb079b324f140cf01c354914acf98b865 to 61d122a792a764472bbbc52b8562b4a616a51d8a

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

61d122aMerge branch 'develop' into 16613_content

comment:24 Changed 19 months ago by bruno

Applies again!

comment:25 Changed 19 months ago by bruno

  • Status changed from needs_work to needs_review

comment:26 Changed 19 months ago by chapoton

failing doctests, see patchbot reports

comment:27 Changed 19 months ago by git

  • Commit changed from 61d122a792a764472bbbc52b8562b4a616a51d8a to 953e5aea98a4a0f5f6095b192607307669dfa8b1

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

953e5ae16613: Fix doctest due to bad merge

comment:28 Changed 19 months ago by bruno

Should be OK now (I'll watch the patchbot logs), I made a mistake during the merge.

comment:29 Changed 19 months ago by git

  • Commit changed from 953e5aea98a4a0f5f6095b192607307669dfa8b1 to 84fbcf39cfab762038d64105408f863e7e1efd2b

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

84fbcf319171: Doctest fix after merge

comment:30 follow-up: Changed 18 months ago by saraedum

  • Status changed from needs_review to needs_info
  • Work issues set to followup ticket mentioned in source code

The implementation looks good to me.

What is the deprecation strategy now? Do we want this to go in and have a followup ticket (to be merged in a year) to have content return an element? If so, there should be such a ticket and a comment in the code.

Or do we want to change this without deprecation? We missed the 8.0 window, so I am slightly in favor of the two step change.

comment:31 Changed 18 months ago by saraedum

  • Work issues changed from followup ticket mentioned in source code to followup ticket mentioned in source code, update ticket summary

comment:32 Changed 15 months ago by slelievre

In the docstring of content_ideal, it would be nice to include a hint such as:

When the base ring is a gcd ring, the content as a ring element is the generator of the content ideal: f.content_ideal().gen()

with an example.

comment:33 Changed 15 months ago by git

  • Commit changed from 84fbcf39cfab762038d64105408f863e7e1efd2b to 017adb67f3a274526c94b79d3d8683723dc14e80

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

6453fc4Merge branch 'u/bruno/content' of git://trac.sagemath.org/sage into t/16613/content
017adb616613: Add content_ideal().gen() example

comment:34 in reply to: ↑ 30 Changed 15 months ago by bruno

  • Description modified (diff)
  • Milestone changed from sage-7.6 to sage-8.1
  • Status changed from needs_info to needs_review

Replying to saraedum:

Or do we want to change this without deprecation? We missed the 8.0 window, so I am slightly in favor of the two step change.

I was in favor of a direct change with the argument of "the sooner the better" but the result was endless discussions and the ticket waits for 3 years! So in order for this ridiculously simple issue to be fixed at some point, let's say we implement the two phase change.

Replying to slelievre: Agree, done! Note that I put this comment only for univariate polynomial rings since in the multivariate case, a method content exists (and is linked).

Now needs review (again!).

comment:35 Changed 15 months ago by tscrim

I think we should just change the behavior (hopefully in an early beta) and put a .. NOTE:: if you do not want to go with the suggestion in comment:19.

comment:36 Changed 14 months ago by saraedum

  • Status changed from needs_review to positive_review

comment:37 Changed 13 months ago by vbraun

  • Branch changed from u/bruno/content to 017adb67f3a274526c94b79d3d8683723dc14e80
  • Resolution set to fixed
  • Status changed from positive_review to closed
Note: See TracTickets for help on using tickets.