I remember writing the QuotientRing_generic class back in 2005 when
there were no quotient rings in Sage yet (after a conversation with
Joe Wetherell and David Kohel...). The file
sage/rings/quotient_ring.py has a function "QuotientRing", and its
initial behavior was to create an object of type QuotientRing_generic.
It still does that in some cases:
sage: Q = QuotientRing(ZZ,8)
sage: type(Q)
<class 'sage.rings.quotient_ring.QuotientRing_generic'>
Simon, I agree with you. The function "QuotientRing" should be
improved so that it works like the functor, e.g,. calls the
".quo(...)" method if it exists. In fact, the code in _apply_functor
in sage/categories/pushout.py (which I had nothing to do with) and the
code in the QuotientRing function should be refactored so the actual
construction only involves calling one function that does the work.
-- William
--
William Stein
Professor of Mathematics
University of Washington
http://wstein.org
+1 Yes, definitely the generator names should be considered.
> Should we preserve the "quick and dirty" approach to test equality of
> the generator list of the ideals? Or can we afford to properly test
> equality of ideals (via Gröbner bases, if available)?
Good question. It seems like we should defer the question to
whatever ideal equality testing already does, which is surely equality
of ideals.
It definitely seems like the "right thing" is to test equality of
ideals, but it is potentially very expensive indeed.
> My opinion is: R1.quo(I1,names1)==R2.quo(I2,names2) if and only if
> R1==R2, I1.gens()==I2.gens() and names2==names2. Testing I1==I2 via
> Gröbner bases is too expensive.
I'll let you decide, unless anybody else has a strong opinion.
>
>> In fact, the code in _apply_functor
>> in sage/categories/pushout.py (which I had nothing to do with) and the
>> code in the QuotientRing function should be refactored so the actual
>> construction only involves calling one function that does the work.
>
> Sounds reasonable. Probably I can fit a new ticket on top of #9138,
> rebasing both #10667 and #11068 relative to the new ticket.
>
> Cheers,
> Simon
>
> --
> To post to this group, send an email to sage-...@googlegroups.com
> To unsubscribe from this group, send an email to sage-devel+...@googlegroups.com
> For more options, visit this group at http://groups.google.com/group/sage-devel
> URL: http://www.sagemath.org
I know you were making a pun, but just for clarification, what Volker
said is exactly right. E.g.,
sage: R.<x,y> = QQ[]
sage: I = R.ideal([x^2, 3*y^2, x^2 - y^2])
sage: J = R.ideal([x^2, y^2, y^2 - x^2])
sage: I
Ideal (x^2, 3*y^2, x^2 - y^2) of Multivariate Polynomial Ring in x, y
over Rational Field
sage: J
Ideal (x^2, y^2, -x^2 + y^2) of Multivariate Polynomial Ring in x, y
over Rational Field
sage: I == J
True
sage: I.__cmp__??
...
l = self.groebner_basis()
r = other.groebner_basis()
...
return cmp(l,r)
>
>> I think it would be more consistent to demand mathematical equality for
>> equality of the quotient rings. It is very likely that this is what the user
>> actually wants if he/she compares two quotient rings.
>
> Unfortunately, equality tests happen implicitly when using coercion:
> There is a cache indexed by parents. Thus, if you have a quotient ring
> Q=R/I and want to add an element of Q with an element of R, then
> equality is tested for Q, in order to see whether there is an
> appropriate coercion in the test.
>
> Hence, equality test ought to be as fast as possible. Ideally, parents
> are equal if and only if they are identical.
>
> Moreover, ideals must not be used as a key of a dictionary:
> sage: P.<x,y> = QQ[]
> sage: I = P*[x,y]
> sage: hash(I)
> 6308421454588240813
> sage: J = P*[x+y,-y]
> sage: hash(J)
> 5043924375983940909
> sage: I==J
> True
>
> In other words, I and J are equal, but have different hash. Actually,
> I think it is a bug that hash(I) does not result in a TypeError.
It's a bug that hash isn't canonical. One should compute a standard
form for I before hashing it. At least this is what happens with
ideals of rings of integers of number fields. (I'm not claiming that
hash is good -- it's something dumb like hashing the Pari HNF string,
but still it is well defined.)
> That's why I think one should simplify the equality test to rely on
> the generator list of the ideals, not on equality of the ideals as
> sets.
I've changed my perspective to disagree with this.
I good compromise may be the following. When creating a quotient
ring, compute a standard form for the ideal. Then when testing
equality of two quotient rings, the whole issue we're talking about
vanishes. If you're going to do any nontrivial arithmetic in the
quotient ring, you'll *need* this standard form anyways. So just
compute it up front. In a multivariate poly ring it would be computed
via something like his:
self.change_ring(R.change_ring(order="degrevlex")).groebner_basis()
(code copied from the __cmp__ method.) The point is that degrevlex
GB's are faster to compute than wrt other term orders... and for our
purposes a GB wrt any term order suffices.
William
>
> Best regards,
> Simon
>
> --
> To post to this group, send an email to sage-...@googlegroups.com
> To unsubscribe from this group, send an email to sage-devel+...@googlegroups.com
> For more options, visit this group at http://groups.google.com/group/sage-devel
> URL: http://www.sagemath.org
>
--
If "arithmetic" is addition, subtraction, multiplication, and equality
checking, then it does not matter which term order you use. The
specific term order doesn't matter in the least for basic arithmetic.
> And even degrevlex Gröbner bases
> are often enough difficult to compute.
If you don't do that, then how will you ever check equality. There is
little arithmetic one would do that never involves actually doing
something (like testing an equality) with the answer.
> Moreover, one must not forget that we want to create quotient rings
> not only for ideals in polynomial rings.
True, but it is an important case, since the ideas covers all finitely
generated quotient rings, and there are a lot of finitely generated
rings in Sage.
I'm personally more interested in rings of integers of number fields,
where one uses Hermite form and linear algebra instead of Groebner
basis.
> See #11068: Technically, we
> can do computations in the quotient ring as soon as the ideal has a
> method I.reduce(x) that returns a normal form of x with respect to I.
>
> But in addition to I.reduce(x), we may consider to request another
> method:
> * We could introduce a new method of ideals called, say,
> I.normal_form(), returning some hashable object.
> * Comparison of ideals I,J should be reduced to I.ring()==J.ring()
> and I.normal_form()==J.normal_form().
> * hash(I) should return hash(I.normal_form()).
> * By default, I.normal_form() just returns the given generators of I
> as a tuple (or polynomial sequence?). Hence, for general ideals
> (without the possibility to compute Gröbner bases), equality of ideals
> becomes equality of generator lists
> * For some types of ideals, I.normal_form() returns a "proper" normal
> form. So, for polynomial ideals, it returns an ordered reduced Gröbner
> basis. In rings of integers of number fields, it returns the pari HNF
> string.
>
> It seems better to me to have a general __cmp__ method for *all*
> ideals and implement a normal_form method, than to have different
> __cmp__ for all types of ideals.
>
> And then, uniqueness of quotient rings could easily be implemented,
> based on R.quo(I,names1)==S.quo(J,names2) <=> R==S and I==J and
> names1==names2.
This would be an acceptable solution to me.
To be precise, finitely generated *commutative* quotient rings :-)
My point is just that the ideals/quotients framework will be used in a
fairly large context. So it would be good if it did not impose too
many constraints, like forcing '==' to *always* mean mathematical
equality (though it could in the simple/not too expensive cases).
Otherwise, this will prevent modeling complex objects where some
lazyness is vital.
For a concrete example, take a quotient of a free non commutative
algebra by a graded ideal. Its Gr�bner basis will typically be
infinite, so one can't compute it in full. Yet, arithmetic can be
achieved by lazily computing it up to the appropriate degree.
In general, after three years, I still remain a big fan of MuPAD's
approach where ``=='' meant syntactical equality, and mathematical
equality was achieved with a different syntax. Especially since ``==''
is used implicitly in many situations (coercion, arithmetic,
dictionary) that ought to be super fast.
Cheers,
Nicolas
--
Nicolas M. Thi�ry "Isil" <nth...@users.sf.net>
http://Nicolas.Thiery.name/