Opened 11 years ago

# coercion and conversion for absolute_field

Reported by: Owned by: mstreng davidloeffler major sage-6.4 number fields coercion conversion absolute_field number field structure relative absolute jdemeyer, SimonKing, daniels N/A

```sage: x = var('x')
sage: K1.<a1> = CyclotomicField(11)
sage: K2.<a2> = K1.extension(x^2 - 3)
sage: K3.<a3> = K2.extension(x^2 + 1) # Let's make a big relative number field
sage: t=a1+6*a2+a3*a1                 # with a complicated element.
sage: L = K3.absolute_field('b')
sage: L(t)
# The code at #11869 takes 12 seconds to compute roots of a
# polynomial, and then doesn't use them.
# TypeError: No compatible natural embeddings found for Number Field in b with .... and Complex Lazy Field
sage: L.structure()                   # However, the correct conversion map is available and works almost instantly
#(Isomorphism map:... , Isomorphism map: ...)
sage: L.structure()[1](t)
# big output
sage: L.gen() + t                     # It would be good if one of the structure maps is a coercion, but they aren't at the moment
# TypeError: unsupported operand parent(s) for '+': ....
sage: K3(L.gen())                     # There are similar problems in the other direction
# TypeError: Cannot coerce element into this number field
sage: L.structure()[0](L.gen())       # for which the structure maps also work.
# a3 - a2 + a1
```

So this ticket is meant to:

• make both structure maps into conversions
• maybe make one or both of the structure maps into a coercion

Speeding up #11869 is not really related and is #12270.

### comment:1 Changed 11 years ago by mstreng

• Description modified (diff)

### comment:2 Changed 11 years ago by mstreng

• Description modified (diff)

Sorry, I'm messing up the patch numbers. I mean #11869 everywhere.

### Changed 11 years ago by mstreng

shows where long calculations are done in #11869

### comment:3 Changed 11 years ago by mstreng

• Description modified (diff)

### comment:5 follow-up: ↓ 6 Changed 11 years ago by jdemeyer

I believe a solution similar to #11876 is in order: make `absolute_field` store an embedding (in this case an isomorphism) to the starting field.

### comment:6 in reply to: ↑ 5 Changed 11 years ago by mstreng

I believe a solution similar to #11876 is in order: make `absolute_field` store an embedding (in this case an isomorphism) to the starting field.

That would fix it, but I don't think it would be very fast, as it would still use `.roots()` / #11869.

Wouldn't it be better to use the category/coercion framework here? I suppose all that is needed it to store the `.structure()` homomorphisms in the appropriate place (wherever that is, cc: Simon) as conversion maps. The structure homomorphisms are computed already, and using them is very fast.

Still, inheriting embeddings as in #11876 is certainly useful, so I think it is best to do both.

### comment:7 follow-up: ↓ 10 Changed 11 years ago by mstreng

The map `absolute_field().structure()[1]` (from relative to absolute) cannot be a *coercion*, because it would lead to non-commuting diagrams of coercions. In sage-4.8.alpha4:

```sage: K.<a> = NumberField(x^2-2, embedding=-1)
sage: L.<b> = NumberField(x^2-2, embedding=1)
sage: xK = K['x'].gen()
sage: xL = L['x'].gen()
sage: M.<c> = NumberField(xK^2-3)
sage: N.<d> = NumberField(xL^2-3)
sage: O = M.absolute_field('e')
sage: P = N.absolute_field('e')
sage: b_in_a = K(0)+b
sage: map1 = O.structure()[1]
sage: map2 = P.structure()[1]
sage: b_in_a in map1.domain()
# True
sage: b in map2.domain()
# True
sage: map1(b_in_a) - map2(b)
# e^3 - 9*e, which is non-zero, so the diagrams don't commute!
```

Fast *conversions* in both directions would be very useful though. And maybe coercion from absolute to relative?

### comment:8 follow-up: ↓ 9 Changed 11 years ago by SimonKing

Sorry, I did not answer Marco's question yet.

Is it the case that the map is already known at initialisation time? Then, you could use (depending on whether you want a conversion or a coercion or an action) `sage.structure.parent.Parent.register_conversion(...)` or `...register_coercion(...)` or `...register_action(...)`. But note that it might be tricky to find the right moment for using these methods: They raise an error if the coercion framework was used before invoking the methods.

If the maps are not available at initialisation time (or if otherwise initialisation takes too much time), you could implement either `_convert_map_from_` or `_coerce_map_from_` -- see the documentation of both methods in `sage.structure.parent.Parent` for the expected return values. The advantage is that the map would only be constructed when needed.

Concerning "coercion or conversion between relative and absolute number fields", I think there has been at least one thread on sage-nt and also a trac ticket devoted to that subject.

### comment:9 in reply to: ↑ 8 Changed 11 years ago by mstreng

• Type changed from defect to enhancement

Sorry, I did not answer Marco's question yet.

No problem, it wasn't a very direct question.

Is it the case that the map is already known at initialisation time?

Don't know, I'll have to dig through the code some more.

Concerning "coercion or conversion between relative and absolute number fields", I think there has been at least one thread on sage-nt and also a trac ticket devoted to that subject.

Thanks, I don't know that ticket/thread. I have found

The first two are about coercions between number fields, but don't say anything about relative versus absolute. The third is about conversions, again no relative versus absolute.

I also did another search on trac, and could only find the tickets I created last week: #12269 (this ticket) and #12271 (same, but for relativize).

### comment:10 in reply to: ↑ 7 Changed 11 years ago by mstreng

• Description modified (diff)

`structure()[1]` cannot be a coercion, because it would lead to non-commuting diagrams of coercions.

Actually, maybe it is the coercion between O to P that shouldn't be there! All of the following maps are natural ` O <--> M <-- K <--> L --> N <--> P ` and a map between O and P sending generator to generator does not commute with the abovementioned natural maps.

Some more about O and P:

```sage: O
Number Field in e with defining polynomial x^4 - 10*x^2 + 1
sage: P
Number Field in e with defining polynomial x^4 - 10*x^2 + 1
sage: O is P
False
sage: O == P
True
sage: RR(O.structure()[1].domain().base_field().gen())
-1.41421356237309
sage: RR(P.structure()[1].domain().base_field().gen())
1.41421356237309
```

O and P are really different, I don't understand True for "==" here. Is that a bug?

```sage: K is L
False
sage: K == L
False
```

### comment:11 follow-up: ↓ 14 Changed 11 years ago by lftabera

Hi, I agree that the error here is that O and P should not be given a coercion. Note that the code above does not work if P is given another generator name. On this example I would not expect a canonical isomorphism from O to P.

### comment:12 follow-up: ↓ 13 Changed 11 years ago by lftabera

Forcing coercions exposes other errors in the coercion model:

```K = NumberField([x^2-2, x^2-3], 'a,b')
M = K.absolute_field('c')
M_to_K, K_to_M = M.structure()
M.register_coercion(K_to_M)
K.register_coercion(M_to_K)
M.coerce_map_from(QQ)
...
UnboundLocalError: local variable 'connecting' referenced before assignment
```

### comment:13 in reply to: ↑ 12 ; follow-up: ↓ 15 Changed 11 years ago by SimonKing

Forcing coercions exposes other errors in the coercion model:

Right. And here it is (in sage.structure.parent, lines 2300-2303):

```                connection = None
if EltPair(mor._domain, S, "coerce") not in _coerce_test_dict:
connecting = mor._domain.coerce_map_from(S)
if connecting is not None:
```

So, apparently someone intended to write "connecting = None", but wrote "connection = None". Can you try whether writing "connecting = None" fixes the problem?

```K = NumberField([x^2-2, x^2-3], 'a,b')
M = K.absolute_field('c')
M_to_K, K_to_M = M.structure()
M.register_coercion(K_to_M)
K.register_coercion(M_to_K)
M.coerce_map_from(QQ)
...
UnboundLocalError: local variable 'connecting' referenced before assignment
```

### comment:14 in reply to: ↑ 11 Changed 11 years ago by mstreng

Hi, I agree that the error here is that O and P should not be given a coercion. Note that the code above does not work if P is given another generator name. On this example I would not expect a canonical isomorphism from O to P.

This can be fixed by making `O == P` be False by letting `O.__cmp__(P)` compare structure maps.

### comment:15 in reply to: ↑ 13 ; follow-ups: ↓ 16 ↓ 17 Changed 11 years ago by lftabera

Forcing coercions exposes other errors in the coercion model:

Right. And here it is (in sage.structure.parent, lines 2300-2303):

```                connection = None
if EltPair(mor._domain, S, "coerce") not in _coerce_test_dict:
connecting = mor._domain.coerce_map_from(S)
if connecting is not None:
```

So, apparently someone intended to write "connecting = None", but wrote "connection = None". Can you try whether writing "connecting = None" fixes the problem?

Yes, this solves the problem. I guess that this fix should go to a new ticket.

### comment:16 in reply to: ↑ 15 Changed 11 years ago by SimonKing

Yes, this solves the problem. I guess that this fix should go to a new ticket.

OK, but I couldn't do it right now. I am in quite a mess with my good old group cohomology spkg, which wouldn't work in the latest Sage version for at least three independent reasons.

### comment:17 in reply to: ↑ 15 Changed 11 years ago by mstreng

Yes, this solves the problem. I guess that this fix should go to a new ticket.

Yes, that makes sense. It is a bugfix of 2 characters, so doesn't have to wait for all of #12269 to be fixed.

### comment:18 Changed 10 years ago by lftabera

For the typo in parent.pyx I have added a patch in #12990

### comment:20 Changed 9 years ago by jdemeyer

• Milestone changed from sage-5.11 to sage-5.12

### comment:21 Changed 9 years ago by vbraun_spam

• Milestone changed from sage-6.1 to sage-6.2

### comment:22 Changed 8 years ago by vbraun_spam

• Milestone changed from sage-6.2 to sage-6.3

### comment:23 Changed 8 years ago by vbraun_spam

• Milestone changed from sage-6.3 to sage-6.4
Note: See TracTickets for help on using tickets.