sagemath / sage

Main repository of SageMath
https://www.sagemath.org
Other
1.4k stars 474 forks source link

variable name '@c' is not alphanumeric #33327

Closed mezzarobba closed 2 months ago

mezzarobba commented 2 years ago

Multivariate polynomial rings over QQbar with a variable named c have problems.

Both of the following

sage: A.<a, c> = QQbar[]
sage: factor(a)

sage: A.<c> = PolynomialRing(QQbar, 1)
sage: factor(c)

cause this value error:

ValueError: variable name '@c' is not alphanumeric

No such problem with univariate polynomial rings or multivariate ones with other variable names:

sage: A.<a> = QQbar[]
sage: factor(a)
a
sage: A.<c> = QQbar[]
sage: factor(c)
c
sage: A.<a, b> = QQbar[]
sage: factor(a)
a

Multivariate polynomial rings over QQ, even using variable name c, are fine too:

sage: A.<a, c> = QQ[]
sage: factor(a)
a
sage: A.<c> = PolynomialRing(QQ, 1)
sage: factor(c)
c

Initial report by Anne Vaugon:

sage: A.<a, b, c, x, y, S> = QQbar[]
sage: p = (a - x)^2 + y^2 - b^2
sage: q = x^2 + y^2 - c^2
sage: r = a * y - 2 * S
sage: r1 = p.resultant(q, x)
sage: r2 = r.resultant(r1, y)
sage: factor(r2 - a^2 * 16 * S^2)
Traceback (most recent call last):
...
ValueError: variable name '@c' is not alphanumeric

CC: @slel

Component: interfaces

Keywords: singular

Issue created by migration from https://trac.sagemath.org/ticket/33327

DaveWitteMorris commented 2 years ago
comment:2

Here is a minimal example:

sage: A.<a,c> = QQbar[]
sage: factor(a^2)
    ...
ValueError: variable name '@c' is not alphanumeric

I reproduced the error all the way back to 9.1 (on CoCalc), which is as far as I could go, so this is not a new bug.

Interestingly, there seems to be something special about the variable name c, because there is no error if we use a different letter (or, at least, some other letters):

sage: A.<a,b> = QQbar[]
sage: factor(a^2)
a^2

So changing c to a different variable name seems to be a workaround (in 9.5 on CoCalc, at least):

sage: A.<a,b,c1,x,y,S> = QQbar[]
....: p = (a-x)**2+y**2-b**2
....: q = x**2 + y**2 - c1**2
....: r = a*y-2*S
....: r1 = p.resultant(q,x)
....: r2 = r.resultant(r1,y)
....: factor(r2-a**2*16*S**2)
(a - b - c1) * (a - b + c1) * (a + b - c1) * (a + b + c1) * a^2
DaveWitteMorris commented 2 years ago
comment:3

Correction: that "minimal" example isn't actually minimal, because replacing a^2 with a still gives the error.

sage: A.<a,c> = QQbar[]
sage: factor(a)
    ...
ValueError: variable name '@c' is not alphanumeric
slel commented 2 years ago

Description changed:

--- 
+++ 
@@ -1,111 +1,60 @@
-An issue reported by Anne Vaugon:
+Multivariate polynomial rings over `QQbar`
+with a variable named `c` have problems.
+
+Both of the following

-sage: A.<a,b,c,x,y,S> = QQbar[] -....: p = (a-x)2+y2-b2 -....: q = x2 + y2 - c2 -....: r = ay-2S -....: r1 = p.resultant(q,x) -....: r2 = r.resultant(r1,y) -....: factor(r2-a216S2) -....:

-ValueError Traceback (most recent call last) - in

-~/co/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/arith/misc.py in factor(n, proof, int_, algorithm, verbose, **kwds)

-~/co/sage/local/var/lib/sage/venv-python3.9/lib/python3.9/site-packages/sage/rings/polynomial/multi_polynomial_element.py in factor(self, proof)

slel commented 2 years ago
comment:5

An even smaller reproducer:

sage: A.<c> = PolynomialRing(QQbar, 1)
sage: factor(c)
Traceback (most recent call last):
...
ValueError: variable name '@c' is not alphanumeric
slel commented 2 years ago

Description changed:

--- 
+++ 
@@ -16,8 +16,8 @@
 ValueError: variable name '@c' is not alphanumeric

-By contrast, univariate polynomial rings and multivariate -polynomial rings with other variable names work fine: +No such problem with univariate polynomial rings +or multivariate ones with other variable names:

 sage: A.<a> = QQbar[]
@@ -30,8 +30,8 @@
 sage: factor(a)
 a

-and so do multivariate polynomial rings over QQ -even using variable name c: +Multivariate polynomial rings over QQ, +even using variable name c, are fine too:

 sage: A.<a, c> = QQ[]
nbruin commented 2 years ago
comment:7

I think it happens at interfaces/singular.py/1607 In the traceback that leads to the error, we have:

debug> p singular.eval('basering')
ipdb> p singular.eval('basering')
// coefficients: QQ(@c)
// number of vars : 1
//        block   1 : ordering dp
//                  : names    c
//        block   2 : ordering C'

so the variable does seem to have the name c, but somehow it prints as @c. So unless there is some strange encoding happening on the sage side when this ring is created, it's probably some singular escape mechanism because ... perhaps c has a special meaning in singular?

I think what happens is that @ is a singular escape mechanism for duplicate names. Note the following in singular:

> ring r = 0,(c), dp; r;
// ** redefining r (ring r = 0,(c), dp; r;)
// coefficients: QQ
// number of vars : 1
//        block   1 : ordering dp
//                  : names    c
//        block   2 : ordering C
> ring r = 0,(c,c), dp; r;
// ** name conflict var(1) and var(2): `c`, rename to `@c`in >>ring r = 0,(c,c), dp; r;<<
in STDIN:14
// ** redefining r (ring r = 0,(c,c), dp; r;)
// coefficients: QQ
// number of vars : 2
//        block   1 : ordering dp
//                  : names    c @c
//        block   2 : ordering C

Note how the repeated c has grown an @?

In the ring that seems to happen in this example, the coefficients are QQ(@c) and then we have a polynomial ring in c over it. So I suspect the real problem is in the sage code, where a function field in c is made, which then later forces singular to escape one of the variables when the ring QQ(c)[c] gets created.

So I suspect that in the factoring code over QQbar, there will be a hardcoded c somewhere.

nbruin commented 2 years ago
comment:8

Unfortunately, the problem is the absfact singular library itself:

> LIB "absfact.lib";
// ** loaded /usr/local/sage/sage-git/local/bin/../share/singular/LIB/absfact.lib (4.1.2.0,Feb_2019)
> ring R = (0), (c), lp;
> poly p = c^2+1;
> def S = absFactorize(p);

// 'absFactorize' created a ring, in which a list absolute_factors (the
// absolute factors) is stored.
// To access the list of absolute factors, type (if the name S was assigned
// to the return value):
//        setring(S); absolute_factors;

> setring(S);
> absolute_factors;
[1]:
   _[1]=1
   _[2]=c+(-@c)
[2]:
   1,1
[3]:
   _[1]=(@c)
   _[2]=(@c^2+1)
[4]:
   2
> S;
// coefficients: QQ(@c)
// number of vars : 1
//        block   1 : ordering lp
//                  : names    c
//        block   2 : ordering C

so apparently, it chooses the name "c" for the algebraic element it thinks it needs to make an extension where the polynomial fully factors. To compare:

> ring R = (0), (x,y), lp;
// ** redefining R (ring R = (0), (x,y), lp;)
> poly p = x^2+y^2;
> def S = absFactorize(p);
// ** redefining S (def S = absFactorize(p);)

// 'absFactorize' created a ring, in which a list absolute_factors (the
// absolute factors) is stored.
// To access the list of absolute factors, type (if the name S was assigned
// to the return value):
//        setring(S); absolute_factors;

> setring(S);
> absolute_factors;
[1]:
   _[1]=1
   _[2]=(a)*x-y
[2]:
   1,1
[3]:
   _[1]=(a)
   _[2]=(a2+1)
[4]:
   2

[note that here a is chosen as name!]

and

> ring R = (0), (a,b), lp;
// ** redefining R (ring R = (0), (a,b), lp;)
> poly p = a^2+b^2;
> def S= absFactorize(p);
// ** redefining S (def S= absFactorize(p);)

// 'absFactorize' created a ring, in which a list absolute_factors (the
// absolute factors) is stored.
// To access the list of absolute factors, type (if the name S was assigned
// to the return value):
//        setring(S); absolute_factors;

> setring(S);
> absolute_factors;
[1]:
   _[1]=1
   _[2]=(c)*a-b
[2]:
   1,1
[3]:
   _[1]=(c)
   _[2]=(c2+1)
[4]:
   2

[it seems to avoid the clash here by going to c]

Then, if we step up to ring = (0), (a,b,c), lp; it indeed cops out with @c as name for the algebraic element. So for now it seems @c might just be filtered for and substituted with __SAGE_CRAZY_ALGEBRAIC_ELEMENT_NAME_ or something like that.

dimpase commented 2 months ago

also reported here: https://groups.google.com/g/sage-devel/c/STactfcs5so/m/pqNuklAABAAJ

dimpase commented 2 months ago

@nbruin - singular's absFactorize() does allow a 2nd parameter, to be used as the name for the new variable:

proc absFactorize(poly p, list #)
"USAGE:  absFactorize(p [,s]);   p poly, s string
ASSUME: coefficient field is the field of rational numbers or a
        transcendental extension thereof
RETURN: ring @code{R} which is obtained from the current basering
        by adding a new parameter (if a string @code{s} is given as a
        second input, the new parameter gets this string as name). The ring
        @code{R} comes with a list @code{absolute_factors} with the
        following entries:

as you can see in absfact.lib. That's how it works in Singular:

LIB "absfact.lib";
[...]
ring r=(0,a,b),(x,y),dp;
poly p=(a+1)/b*x + y;
def S = absFactorize(p,"s");
setring(S);
absolute_factors;
// ** redefining r (ly p=(a+1)/b*x + y;
def S = absFactorize(p,"s");
setring(S);
absolute_factors;)

// 'absFactorize' created a ring, in which a list absolute_factors (the
// absolute factors) is stored.
// To access the list of absolute factors, type (if the name S was assigned
// to the return value):
//        setring(S); absolute_factors;

[1]:
   _[1]=1/(b)
   _[2]=(a+1)*x+(b)*y
[2]:
   1,1
[3]:
   _[1]=(s)
   _[2]=(s)
[4]:
   1

so the question is how to modify Sage interface to supply a good value for the new variable.

nbruin commented 2 months ago

Nice find! So as a first workaround we could simply pass in a name much less likely to collide. I've initiated a branch with a minimal change. Let's see if anything else needs to be adjusted.