# Ticket #807(new defect)

Opened 6 years ago

## construction of function fields

Reported by: Owned by: nbruin somebody major sage-5.10 basic arithmetic N/A

### Description

The following does not work and it seems to fail in an odd way wrt. the preparser

```P1.<t> = QQ[].fraction_field()
```

There doesn't seem to be a convenient way of constructing a rational function field with a named variable.

## Change History

### comment:1 Changed 5 years ago by cremona

This works:

```sage: P1 = PolynomialRing(QQ,'t').fraction_field()
sage: P1.gen()
t
sage: t=P1.gen()
sage: P1((t+1)/(t-3))
(t + 1)/(t - 3)
```

Note that the fraction field picks up the display name 't', but that to get the identifier t defined requires the assignment.

I guess this does not qualify for what you wanted, namely to have t assigned automatically on the line defining the field.

Looking into this I found something else peculiar:

```sage: t=polygen(QQ)
sage: t
x
sage: t.parent()
Univariate Polynomial Ring in x over Rational Field
```

I have found polygen to be useful, but now I think that using it is fraught with possible confusion. It causes the PolynomialRing? in 'x' to be created with no choice as to the display string for the variable.

### comment:2 Changed 5 years ago by was

I have found polygen to be useful, but now I think that using it is fraught with possible confusion. It causes the PolynomialRing?? in 'x' to be created with no choice as to the display string for the variable.

That's not true. Did you try reading polygen?

```sage: t = polygen(QQ,'t')
sage: t
t
sage: t.parent()
Univariate Polynomial Ring in t over Rational Field
```

### comment:3 Changed 5 years ago by was

```14:42 < cwitty-rvw3129> I'd be fine with saying 807 is invalid (since it doesn't have any sort of concrete
proposal); wstein-2605, what do you think?
14:43 < wstein-406> It's invalid.
14:43 < wstein-406> It should be an error.
14:43 < wstein-406> He has to give the poly ring variable explicitly; there is no way around htat.
14:44 < mhansen> This is what it preparses to: "P1 = QQ[].fraction_field(names=('t',)); (t,) =
P1._first_ngens(Integer(1))"
14:44 < wstein-406> However, it might be nice for this to work:
14:44 < cwitty-rvw3129> Well, he's trying to give the variable explicitly with the P1.<t> syntax.
14:44 < wstein-406> P1.<t> = QQ['t'].fraction_field()
14:44 < wstein-406> What would happen is that fraction_field would have a names option, and if the
14:44 < wstein-406> names didn't match with the gen names of R (=QQ['t']) then a copy is returned with
14:44 < wstein-406> those variable names.
14:45 < wstein-406> E.g.,
14:45 < wstein-406> P1.<t> = QQ['x'].fraction_field()
14:45 < wstein-406> should work.
14:45 < wstein-406> Too.
14:45 < wstein-406> So I do not think #807 is invalid; it just needs to be changed slightly.
```

### comment:4 Changed 18 months ago by kcrisman

• Report Upstream set to N/A

Still all true. Four years later!

```sage: P1.<t> = QQ[].fraction_field()
------------------------------------------------------------
File "<ipython console>", line 1
P1 = QQ[].fraction_field(names=('t',)); (t,) = P1._first_ngens(1)
^
SyntaxError: invalid syntax

sage: P1.<t> = QQ['x'].fraction_field()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

TypeError: fraction_field() got an unexpected keyword argument 'names'
```

### comment:5 Changed 18 months ago by cremona

Would it be possible to have QQ('a') preparse to the right thing? That would make mathematical sense. Currently, of course, QQ('a') tried to convert the strong 'a' into a rational and fails.

### comment:6 follow-up: ↓ 7 Changed 3 months ago by tscrim

I think the underlying problem is that the language syntax does not truly support doing QQ[], so when it is trying to parse QQ[].fraction_field(), it first must evaluate QQ[] as a standalone (thus the SyntaxError), in order to get the output object to find the attribute fraction_field().

I don't know where/how the syntax P.<x> = QQ[] comes from/works (in the preparser perhaps?), so perhaps we can use that, but I don't know if that is easily done, safe, or even feasible. I'll do some looking around, but I'm thinking this might not be doable considering the semantics of python... Anyone else's thoughts?

Best,
Travis

### comment:7 in reply to: ↑ 6 ; follow-up: ↓ 8 Changed 3 months ago by cremona

I think the underlying problem is that the language syntax does not truly support doing QQ[], so when it is trying to parse QQ[].fraction_field(), it first must evaluate QQ[] as a standalone (thus the SyntaxError), in order to get the output object to find the attribute fraction_field().

I don't know where/how the syntax P.<x> = QQ[] comes from/works (in the preparser perhaps?), so perhaps we can use that, but I don't know if that is easily done, safe, or even feasible. I'll do some looking around, but I'm thinking this might not be doable considering the semantics of python... Anyone else's thoughts?

```sage: preparse("P.<x> = QQ[]")
"P = QQ['x']; (x,) = P._first_ngens(1)"
```

As I understand it, the . before the < triggers a python error which is caught and then handled nicely.

Best,
Travis

### comment:8 in reply to: ↑ 7 ; follow-up: ↓ 9 Changed 3 months ago by nbruin

As I understand it, the . before the < triggers a python error which is caught and then handled nicely.

The preparser is just a preprocessor, so no python errors are involved. The string is modified before the python parser ever sees it. Anyway:

```sage: preparse("P1.<t> = QQ['x'].fraction_field()")
"P1 = QQ['x'].fraction_field(names=('t',)); (t,) = P1._first_ngens(1)"
```

and supporting it seems straightforward, but this is where things get questionable: names supplied on construction are part of the construction data, so

```sage: R=QQ['x']
sage: F1=R.fraction_field(names=('u',))
sage: F2=R.fraction_field(names=('v',))
```

should produce two fields F1,F2. Both would have coercions from R installed, since they are constructed as field-of-fractions of R. There would not be a coercion from F1 to F2. Furthermore, for

```sage: K=QQ['x,u,v'].fraction_field()
```

all of R,F1,F2 would coerce into K, but coercion from R to K would not be compatible with the coercions from F1 and F2 into K, which is bad.

For better of for worse, it was decided that the names of polynomial variables have meaning in sage. A consequence of that is that you don't get to choose the name upon applying the function_field functor.

(oh, I didn't realize I made this ticket!)

### comment:9 in reply to: ↑ 8 ; follow-ups: ↓ 10 ↓ 12 Changed 3 months ago by tscrim

The preparser is just a preprocessor, so no python errors are involved. The string is modified before the python parser ever sees it. Anyway:

```sage: preparse("P1.<t> = QQ['x'].fraction_field()")
"P1 = QQ['x'].fraction_field(names=('t',)); (t,) = P1._first_ngens(1)"
```

and supporting it seems straightforward,

That's not as scary as I expected it to be.

but this is where things get questionable: names supplied on construction are part of the construction data, so

```sage: R=QQ['x']
sage: F1=R.fraction_field(names=('u',))
sage: F2=R.fraction_field(names=('v',))
```

should produce two fields F1,F2. Both would have coercions from R installed, since they are constructed as field-of-fractions of R. There would not be a coercion from F1 to F2. Furthermore, for

```sage: K=QQ['x,u,v'].fraction_field()
```

all of R,F1,F2 would coerce into K, but coercion from R to K would not be compatible with the coercions from F1 and F2 into K, which is bad.

So you're considering adding a names argument in a meaningful way to fraction_field()? However this does not quite make sense to me and would conflict with the behavior of FractionField (which takes names as input and just ignores them; although it just redirects the call to the respective fraction_field() with no arguments). It seems like the correct fix would be to have the following:

```sage: preparse("R.<x,y> = QQ[].fraction_field()")
"R = QQ['x, y'].fraction_field(names=('x', 'y',)); (x, y,) = R._first_ngens(2)"
```

and have fraction_field() take names as an optional argument and ignore the input.

Just to note, this is the current behavior in Sage when there is no other function:

```sage: preparse("R.<x,y> = QQ[]")
"R = QQ['x, y']; (x, y,) = R._first_ngens(2)"
```

In some ways, I'd almost like the following to throw an error:

```sage: R.<x> = QQ['t']
sage: x
t
```

since the variable names don't match. But that might just be me...

For better of for worse, it was decided that the names of polynomial variables have meaning in sage. A consequence of that is that you don't get to choose the name upon applying the function_field functor.

### comment:10 in reply to: ↑ 9 ; follow-up: ↓ 11 Changed 3 months ago by cremona

In some ways, I'd almost like the following to throw an error:

```sage: R.<x> = QQ['t']
sage: x
t
```

since the variable names don't match. But that might just be me...

No, not just you. And you probably also dislike this, as I do:

```sage: y = polygen(QQ)
sage: y
x
```

This would be avoided by disallowing polygen()'s name parameter being omitted (it defaults to "x"). After all we are not allowed to construct number fields, or non-prime finite fields, without naming a generator, and this is worse since we usually think that we have named a generator...

### comment:11 in reply to: ↑ 10 ; follow-up: ↓ 13 Changed 3 months ago by tscrim

No, not just you. And you probably also dislike this, as I do:

```sage: y = polygen(QQ)
sage: y
x
```

This would be avoided by disallowing polygen()'s name parameter being omitted (it defaults to "x"). After all we are not allowed to construct number fields, or non-prime finite fields, without naming a generator, and this is worse since we usually think that we have named a generator...

Yes I do not like that as well. However, even making name a mandatory argument, it still does not prevent things such as:

```sage: y = polygen(QQ, 'a')
sage: y
a
```

From looking at the function, I'd want to deprecate it if we decide to forbid R.<x> = QQ['t'] (which could be done in the preparse).

### comment:12 in reply to: ↑ 9 Changed 3 months ago by nbruin

Replying to tscrim: Ah, I wasn't aware of the FractionField behaviour. In a way, ignoring "names" would be good. Compare:

```sage: preparse("R.<x>=QQ[t]")
'R = QQ[t]; (x,) = R._first_ngens(1)'
sage: preparse("R.<x>=PolynomialRing(QQ,'t')")
"R = PolynomialRing(QQ,'t', names=('x',)); (x,) = R._first_ngens(1)"
sage: preparse("R.<x>=PolynomialRing(QQ,names='t')")
"R = PolynomialRing(QQ,names='t', names=('x',)); (x,) = R._first_ngens(1)"
```

In the first and second cases, it is recognised that a print name supplied by the LHS is superfluous, so it gets ignored (meaning: not inserted into the RHS). In the third case, the preparser fails to recognize this (the preparser will always have problems like that).

Given that print names are always superfluous for FractionField?, ignoring the names field would be the right thing. However, I think fraction_field is not the proper place to do this and it would not solve the issue of this ticket: In

```P1.<t>=FractionField(QQ[])
```

or

```P1.<t>=QQ[].fraction_field()
```

it's not just that a names=('t',) should not be injected into the fraction_field call, it should be injected into the polynomial ring constructor. Of course, for this case the solution is

```sage: P1.<t>=FunctionField(QQ)
```

### comment:13 in reply to: ↑ 11 Changed 3 months ago by nbruin

This would be avoided by disallowing polygen()'s name parameter being omitted (it defaults to "x"). After all we are not allowed to construct number fields, or non-prime finite fields, without naming a generator, and this is worse since we usually think that we have named a generator...

Isn't the whole point of polygen that people get tired of supplying names? Otherwise you can just spell it QQ['a'].0, which is shorter anyway (or QQ['a'].gen(0) if you don't want to rely on the preparser and is still shorter than polygen(QQ,'a') and requires the same number of "shift" characters on a US keyboard)

Yes I do not like that as well. However, even making name a mandatory argument, it still does not prevent things such as:

```sage: y = polygen(QQ, 'a')
sage: y
a
```

From looking at the function, I'd want to deprecate it if we decide to forbid R.<x> = QQ['t'] (which could be done in the preparse).

Deciding if the names= implied by R.<x> is necessary is already flaky. Deciding if the implied names= is consistent with what is on the RHS is going to be very complicated within the limited view of the preparser. I don't think we want to grow a new attribute preparser_generated_names just to accommodate this.

We can document what it does:

• bind generators to the python identifiers supplied
• if the RHS requires print names for the generators and doesn't supply them, derive them from the python names.

Of course it's good style to let python names and print names bear resemblance, but ultimately users will have to know that they are not the same thing.

### comment:14 Changed 3 months ago by tscrim

Ignoring the names in fraction_field() would not solve the problem since the preparser does not set the variable names correct (which should IMO be fixed nevertheless since it is inconsistent). I'll look more into the preparser later tonight (feel free to upload a patch if you know how to fix the main issue, I can find some places to document the bindings).

Thanks,
Travis

Note: See TracTickets for help on using tickets.