(for Sage-Combinat folks: this e-mail is mostly about our beloved
cycles in the coercion graph; see below)
On Sat, Nov 27, 2010 at 01:15:11AM -0800, Simon King wrote:
> Sometimes I am not sure where to post my questions - I think there
> are too many Sage lists.
Yes. In a perfect world, there would be a single sage list, and
threads would be tagged by keywords so that people interested in just
a few topics would ask to follow only the matching threads.
> Anyway. On sage-nt, I asked about coercions of number fields. In a not-
> yet-published version of my patch for #8800, I arranged coercion of
> "number fields with prescribed embeddings" so that there may both be a
> coercion from L1 to L2 and from L2 to L1, where L1 and L2 are both
> embedded into a common ambient field, K.
>
> David Roe commented: "I think we should avoid coercion maps going in
> both directions when possible."
I can't comment on the use case at hand. But in Sage-Combinat we do
have a lot of use cases where we really want to have coercion maps in
both directions; more generally, we have large strongly connected
components in the coercion graph. That happens when we have several
implementations of the same algebra, typically depending on which
basis the elements are expanded on; see:
sage: S = Sets()
sage: S.WithRealizations?
There is a single caveat: namely that the current coercion
implementation does not handle those well (see #8878). It's been on my
todo list for a long time, and I spent a hard week of work last spring
implementing this; the patch is in the Sage-Combinat queue, but
guarded out since it is not yet fully ready for general use: coercion
is used throughout the Sage library and is a pretty sensitive point;
there are still a couple issues that need to be fixed. It's my plan to
work on this early next year when my teaching load will be down. I
could use a hand discussing a couple fine technical points and fixing
the remaining issues.
Cheers,
Nicolas
--
Nicolas M. Thi�ry "Isil" <nth...@users.sf.net>
http://Nicolas.Thiery.name/
Do you really want to have coercion maps in both directions, or rather
just conversion maps?
> There is a single caveat: namely that the current coercion
> implementation does not handle those well (see #8878).
The examples there are conversion than coercion.
--Mike
coercion, so that mixed arithmetic works smoothly.
> >>There is a single caveat: namely that the current coercion
> >>implementation does not handle those well (see #8878).
> >
> >The examples there are conversion than coercion.
Ok, I should add a test there with a coercion :-)
> I remember that we ran into trouble with the coercion maps at Sage Days 20.5
> for symmetric functions subspaces/quotients. But as far as I remember in that
> setting only conversions were needed in principle.
>
> But perhaps Nicolas could confirm?
Yes, and it was an instance of #8878. I don't remember if we ran into
problem with coercion or conversion, but in any cases we want both.
SymmetricFunctions.
That use case was also at the root of the design of the coercion model
I wrote for MuPAD (back in 2003).
It is actually used intensively by quite a few people around. But
precisely because it is such a central tool for us, there are a lot of
features (Hopf structure) that we want to have. Hopefully soon ...
> And, as I mentioned in a different thread a couple of
> months ago, I don't understand how one really works with these
> "algebras with basis". But anyway.
> Do you think of an example like this one?
>
> sage: Sym = SymmetricFunctions(QQ)
> sage: p = Sym.powersum()
> sage: e = Sym.elementary()
> sage: p.one()+e.one()
> 2*p[]
> sage: e.one()+p.one()
> 2*e[]
Precisely.
> So, we have two copies of "the same" algebra with two different bases.
> That is certainly a setting where coercions in both directions should
> exist (after all, coercion is here just a basis change), and, as one
> sees above, indeed the left summand determines the parent of the sum.
Yup.
> The question is whether two number fields with different embeddings
> are to be treated like an algebra with different bases.
The key point is: are the two algebraic structures canonically isomorphic?
"canonically isomorphic" means in particular that the coercion graph
shall be a commutative diagram. I don't have a good view on your
specific problem, but it sounds like this is not the case
(L1 -> L2 -> C does not do the same as L1 -> C).
I should just emphasize that coercions (applied automatically) must
be canonical. There were some coercion problems in Magma precisely
with number fields K, L, with K a subfield of L, and K', isomorphic
to K, which created non-commuting coercion diagrams by "recognizing"
K' as "equal" to K (same defining polynomial), then using K' -> K
and K -> L for the coercion.
In general, if two non-equal fields have not been constructed with
a coercion between then then no choice should be made. I don't
see how one can choose any coercion between a cyclotomic field with
embedding and another number field which does not come equipped
with an embedding in a common field.
Thus for Simon's question 1, I agree (with Sage) that there should
be no coercion. For question 2, I wouldn't want or expect coercion
to move outside of the given parents (and certainly not outside of
the domain of number fields). For question 3, I would only return
something which is categorically defined -- the pushout of (K,K->F)
and (L,L->F) should be again a minimal field M with embedding M->F
whose image contains the images of K and L, right? Returning
(F, id:F->F) would be mathematically wrong. Most likely the
determination of such a field would be expensive and not something
that one would to be invoked by automatic coercion.
Cheers,
David
On Sun, 28 Nov 2010 00:40:58 -0800 (PST)
Simon King <simon...@uni-jena.de> wrote:
> 3. CONCLUSION
>
> Perhaps I can now reformulate my "real" questions:
> 1. If there are computationally canonical isomorphisms (structure
> preserving) between K and K', should they always be used as
> bidirectional coercions between K and K'? Or do you agree with David
> Roe that having coercions in both directions should be a rare
> exception?
I really think having bidirectional coercions would be very confusing
for users in the long term. I can imagine long, frustrating debugging
sessions where people are bitten by the fact that a + b doesn't have
the same parent as b + a in Sage.
IMHO, this discussion also goes against several principles from the Zen
of Python.
sage: import this
The Zen of Python, by Tim Peters
...
Explicit is better than implicit.
Simple is better than complex.
...
Readability counts.
...
In the face of ambiguity, refuse the temptation to guess.
...
If the implementation is hard to explain, it's a bad idea.
...
Especially in Nicolas Thiery's examples with symmetric functions, using
an explicit conversion is definitely the best way to go. How hard is it
to use the conversion in the following example?
sage: Sym = SymmetricFunctions(QQ)
sage: P = Sym.powersum()
sage: E = Sym.elementary()
sage: P.one()+ P(E.one())
2*p[]
sage: E.one()+ E(P.one())
2*e[]
This way the user (or Sage) doesn't have to guess what the result will be. It's explicit, clear and easy to read.
Cheers,
Burcin
On 11/28/2010 06:06 AM, Burcin Erocal wrote:
> Especially in Nicolas Thiery's examples with symmetric functions, using
> an explicit conversion is definitely the best way to go. How hard is it
> to use the conversion in the following example?
>
> sage: Sym = SymmetricFunctions(QQ)
> sage: P = Sym.powersum()
> sage: E = Sym.elementary()
> sage: P.one()+ P(E.one())
> 2*p[]
> sage: E.one()+ E(P.one())
> 2*e[]
>
> This way the user (or Sage) doesn't have to guess what the result will be. It's explicit, clear and easy to read.
I apologize for drifting away from the main thread, but I do want to
address this point. The problem is that I often work with ~8 bases of
this space simultaneously, and perhaps close to 20 bases are defined
within sage. I am also frequently adding a new basis and playing with
it. The coercion graph is connected, but not every edge is implemented
explicitly. When I implement a new basis, I certainly don't want to
have to explicitly define 20 conversions; I only want to define one
change of basis matrix, so that my basis is connected by some path to
all the others. (This is often all I know explicitly, anyway).
Since every conversion has to be made explicit (as opposed to coercions,
which will traverse the whole graph), the user would have to know the
path of change of basis matrices which have been implemented. So one
would have to write something like:
sage: S, J, s, P = # various bases of Sym
sage: S( s( P( J[2,1] ) ) )
instead of
sage: S, J = # bases
sage: S( J[2,1] )
The former seems practically unusable to me to anyone who is not an
expert with the implementation details.
Perhaps, in an ideal world, we would have another system (distinct from
conversion and coercion) that would handle this case of vector spaces or
algebras with multiple bases. But until someone implements such a
thing, we have to choose between conversion and coercion as they
currently exist, and the coercion system is the one which does what we need.
Cheers,
Jason
On Sun, 28 Nov 2010 08:36:05 -0800 (PST)
Simon King <simon...@uni-jena.de> wrote:
> On 28 Nov., 14:35, Jason Bandlow <jband...@gmail.com> wrote:
> > Since every conversion has to be made explicit (as opposed to
> > coercions, which will traverse the whole graph), the user would
> > have to know the path of change of basis matrices which have been
> > implemented. So one would have to write something like:
> >
> > sage: S, J, s, P = # various bases of Sym
> > sage: S( s( P( J[2,1] ) ) )
>
> Or one can use register_as_coercion() in order to customise coercion.
> In your situation, you could register some base changes, and could
> then rely on automatic coercion. Burcin would perhaps not use
> register_as_coercion(), as he seems to prefer explicit conversion.
I prefer explicit conversion _in this case_. My point was about
allowing bidirectional coercions, and violating the condition that
parent(a + b) is parent(b + a).
I agree that in Jason's example expecting the user to write
sage: S( s( P( J[2,1] ) ) )
is absurd.
Your suggestion is a good short term solution to Jason's problem. In
the long term, we should take the code for graph traversal out of the
coercion system and make it an independent class which we can query for
maps/morphisms in the transitive closure of a given set of
maps/morphisms. Of course this will open a whole new can of worms, like
what is the most efficient path between two parents, etc.
> From the answers in this thread, it seems to me that people have
> different expectations on the necessary level of explicity.
>
> My impression is that Nicolas and Jason would like that Sage tries to
> make sense of any arithmetic expression that the user presents: Hence,
> Sage should infer a suitable common parent whenever it seems possible,
> of course as long as choices (that certainly can't be avoided, see
> QQ['x'] versus Frac(ZZ['x'])) are consistent.
>
> Burcin seems to propose the other extremal position: Arithmetic should
> not take place between different parents at all, unless explicitly
> requested by the user (via explicit conversion or probably via
> register_as_coercion()).
No, this is not what I meant. I don't see anything wrong with the
result of an addition with an element of QQ and ZZ['x'] returning an
element from QQ['x']. I think the coercion model is one of the features
(along with the category framework) that make Sage a great platform to
implement mathematical algorithms. My objection was to adding
bidirectional coercions only.
Cheers,
Burcin
John
I would be concerned if in general the determination of an isomorphism
would invoke an expensive computation (before either succeeding or
failing) outside of the user's control.
It might be fast for quadratic fields, for cyclotomic fields (defined
by cyclotomic polynomials). Note that more extensive isomorphism
testing (polynomial factorization) is invoked as well:
sage: P.<x> = PolynomialRing(QQ)
sage: f = x^7 + x + 1
sage: r = [ r[0] for r in f.roots(CC) ]
sage: L1.<r1> = NumberField(f, embedding = r[1])
sage: L2.<r2> = NumberField(f(x+1), embedding = r[1]-1)
sage: L1(r2)
r1 - 1
sage: L2(r1)
r2 + 1
sage: g = f(1/x).numerator()
sage: L3.<r3> = NumberField(g, embedding = 1/r[1])
sage: L3(r1)
-r3^6 - r3^5
sage: L1(r3)
-r1^6 - 1
But if the risks and advantages are well-documented as a feature of
embedded fields, this should not affect number fields without embedding,
hence is harmless if the user doesn't specifically request an embedding.
Assuming there is no impact on unembedded number fields and such are
the default, then I have no objection to leaving this feature.
Does this work for p-adic embeddings as well?
Cheers,
David
On 29 Nov., 18:26, "David R. Kohel" <ko...@iml.univ-mrs.fr> wrote:
> I would be concerned if in general the determination of an isomorphism
> would invoke an expensive computation (before either succeeding or
> failing) outside of the user's control.
This is the reason why currently we get "ERROR: An unexpected error
occurred while tokenizing input" in the example above: By oversight,
the ambient field is constructed but not passed as an argument to
EmbeddedNumberFieldMorphism, so that it assumes embedding in CDF,
which takes too long.
> Assuming there is no impact on unembedded number fields and such are
> the default, then I have no objection to leaving this feature.
Yes, EmbeddedNumberFieldMorphism is only invoked (and can only be
invoked) if there is an embedding.
> Does this work for p-adic embeddings as well?
How would one construt a p-adic example? Then I can try (and perhaps
make it another doctest).
Cheers,
Simon
sage: Q5 = Qp(5)
sage: iQ5 = Q5(-1).sqrt(); iQ5
2 + 5 + 2*5^2 + 5^3 + 3*5^4 + 4*5^5 + 2*5^6 + 3*5^7 + 3*5^9 + 2*5^10 +
2*5^11 + 4*5^13 + 5^14 + 3*5^15 + 2*5^16 + 4*5^17 + 4*5^19 + O(5^20)
sage: K.<i> = NumberField(x^2+1, embedding=iQ5)
sage: K
Number Field in i with defining polynomial x^2 + 1
sage: Q5(i)
2 + 5 + 2*5^2 + 5^3 + 3*5^4 + 4*5^5 + 2*5^6 + 3*5^7 + 3*5^9 + 2*5^10 +
2*5^11 + 4*5^13 + 5^14 + 3*5^15 + 2*5^16 + 4*5^17 + 4*5^19 + O(5^20)
John
>
> Cheers,
> Simon
>
On Tue, Nov 30, 2010 at 01:28:03AM -0800, Simon King wrote:
> Hi Robert,
>
> On 30 Nov., 05:26, Robert Bradshaw <rober...@math.washington.edu>
> wrote:
> > > Part 2: Only one number field is embedded
> > > I think David misunderstood: I did not state that there should be a
> > > coercion from a non-embedded to an embedded field. The opposite
> > > coercion (by forgetful functor) should be fine, though. I suppose that
> > > David and I agree here.
> >
> > Yep, it's fine if the forgetful functor is applied. Actually, I might
> > add that I'd probably only want this if the defining polynomials
> > agree, mapping generator to generator, otherwise an arbitrary choice
> > would have to be made.
>
> Sure, that was the idea.
This David was me, right?
I still see a potential problem. The forgetful functor would map from
(K,K->F) to K. If K is a "new" object, then there is no problem, since
no choice of isomorphism with an existing object has been made.
But given (K,K->F) and L (containing isomorphic image of K), there is still
an arbitrary choice of embedding K -> L to be made. If now L1 and L2 are
two such fields then can we be sure that (as unembedded number fields) there
can never be any coercion relation between L1 and L2 (which could give rise
to non-commuting coercion diagrams)? If an embedding can only be installed
at creation, then maybe this is impossible.
If Sage doesn't know a relation, a user might intend some relation between
L1 and L2, then automatic coercion could violate the intended relation.
CC.<i> = ComplexField()
L1.<i_1> = NumberField(x^2+1) # intended embedding=+i
L2.<i_2> = NumberField(x^2+1) # intended embedding=-i
H12 = Hom(L1,L2)
h12 = H12(-i_2)
K0.<i_0> = CyclotomicField(4) # embedding=+i
A user might prefer to work with explicit homomorphisms, and get burned by
automatic coercion from some embedded field. Arguably this will involve
a user error in mixing embedded an non-embedded fields, but this could be
very subtle to debug.
Currently no such forgetful coercion exists, right?
However, I find this problematic (in Sage 4.3.1):
sage: CC(i_0)
6.12323399573677e-17 + 1.00000000000000*I
sage: CC(i_1)
1.00000000000000*I
sage: CC(i_2)
1.00000000000000*I
since i_1 and i_2 are not supposed to be embedded.
Cheers,
David