Skip to content

Commit fb8d1c5

Browse files
committed
fix(Mpolynomial_libsingular): support division over transcendental extension
Currently, dividing a Singular backed multivariate polynomial by a fractional field element(of the same type) is unsupported and triggers a conversion error on the Singular end indicating the denominator is nonconstant. This commit extracts the commit from Singular trunk which adds support for the use case[^1] to a patch to be applied on top of release 4.4.1. We force an in-source build of Singular if the system Singular package does not contain the patch. [^1]: Singular/Singular@0a4bc0e
1 parent d617df4 commit fb8d1c5

File tree

4 files changed

+313
-1
lines changed

4 files changed

+313
-1
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
4.4.1
1+
4.4.1.p0
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
From f319ccff8d39114cd1404cb7631f4399678c7269 Mon Sep 17 00:00:00 2001
2+
From: Hans Schoenemann <[email protected]>
3+
Date: Fri, 2 May 2025 11:35:37 +0200
4+
Subject: [PATCH] fix #1269
5+
6+
---
7+
kernel/ideals.cc | 83 ++++++++++++++++----------------
8+
kernel/polys.cc | 120 ++++++++++++++++++++++++++++-------------------
9+
2 files changed, 116 insertions(+), 87 deletions(-)
10+
11+
diff --git a/kernel/ideals.cc b/kernel/ideals.cc
12+
index 148f4878b..cfc523c8a 100644
13+
--- a/kernel/ideals.cc
14+
+++ b/kernel/ideals.cc
15+
@@ -3487,54 +3487,57 @@ ideal idSaturate_intern(ideal I, ideal J, int &k, BOOLEAN isIdeal, BOOLEAN isSB)
16+
// return id_Sat_principal(I,J,currRing);
17+
//}
18+
//---------------------------------------------------
19+
- BOOLEAN only_vars=TRUE; // enabled for I:x_i
20+
- if (idElem(J)==1)
21+
+ if (!rField_is_Ring(currRing))
22+
{
23+
- for(int j=IDELEMS(J)-1;j>=0;j--)
24+
+ BOOLEAN only_vars=TRUE; // enabled for I:x_i
25+
+ if (idElem(J)==1)
26+
{
27+
- poly p=J->m[j];
28+
- if (p!=NULL)
29+
+ for(int j=IDELEMS(J)-1;j>=0;j--)
30+
{
31+
- if (pVar(p)==0)
32+
+ poly p=J->m[j];
33+
+ if (p!=NULL)
34+
{
35+
- only_vars=FALSE;
36+
- break;
37+
+ if (pVar(p)==0)
38+
+ {
39+
+ only_vars=FALSE;
40+
+ break;
41+
+ }
42+
}
43+
}
44+
}
45+
- }
46+
- if (only_vars && isIdeal && rOrd_is_Totaldegree_Ordering(currRing)
47+
- && (idElem(J)==1))
48+
- {
49+
- ideal Iquot,Istd;
50+
- intvec *w=NULL;
51+
- Istd=id_Satstd(I,J,currRing);
52+
- si_opt_2|=Sy_bit(V_PURE_GB);
53+
- k=0;
54+
- loop
55+
+ if (only_vars && isIdeal && rOrd_is_Totaldegree_Ordering(currRing)
56+
+ && (idElem(J)==1))
57+
{
58+
- k++;
59+
- Iquot=idQuot(Istd,J,TRUE,isIdeal);
60+
- ideal tmp=kNF(Istd,currRing->qideal,Iquot,5);
61+
- int elem=idElem(tmp);
62+
- id_Delete(&tmp,currRing);
63+
- id_Delete(&Istd,currRing);
64+
- Istd=Iquot;
65+
- w=NULL;
66+
- Istd=kStd2(Iquot,currRing->qideal,testHomog,&w,(bigintmat*)NULL);
67+
- if (w!=NULL) delete w;
68+
- id_Delete(&Iquot,currRing);
69+
- if (elem==0) break;
70+
- }
71+
- k--;
72+
- idSkipZeroes(Istd);
73+
- //PrintS("\nSatstd:\n");
74+
- //iiWriteMatrix((matrix)I,"I",1,currRing,0); PrintLn();
75+
- //iiWriteMatrix((matrix)J,"J",1,currRing,0); PrintLn();
76+
- //iiWriteMatrix((matrix)Istd,"res",1,currRing,0);PrintLn();
77+
- //id_Delete(&Istd,currRing);
78+
- SI_RESTORE_OPT2(save_opt);
79+
- return Istd;
80+
+ ideal Iquot,Istd;
81+
+ intvec *w=NULL;
82+
+ Istd=id_Satstd(I,J,currRing);
83+
+ si_opt_2|=Sy_bit(V_PURE_GB);
84+
+ k=0;
85+
+ loop
86+
+ {
87+
+ k++;
88+
+ Iquot=idQuot(Istd,J,TRUE,isIdeal);
89+
+ ideal tmp=kNF(Istd,currRing->qideal,Iquot,5);
90+
+ int elem=idElem(tmp);
91+
+ id_Delete(&tmp,currRing);
92+
+ id_Delete(&Istd,currRing);
93+
+ Istd=Iquot;
94+
+ w=NULL;
95+
+ Istd=kStd2(Iquot,currRing->qideal,testHomog,&w,(bigintmat*)NULL);
96+
+ if (w!=NULL) delete w;
97+
+ id_Delete(&Iquot,currRing);
98+
+ if (elem==0) break;
99+
+ }
100+
+ k--;
101+
+ idSkipZeroes(Istd);
102+
+ //PrintS("\nSatstd:\n");
103+
+ //iiWriteMatrix((matrix)I,"I",1,currRing,0); PrintLn();
104+
+ //iiWriteMatrix((matrix)J,"J",1,currRing,0); PrintLn();
105+
+ //iiWriteMatrix((matrix)Istd,"res",1,currRing,0);PrintLn();
106+
+ //id_Delete(&Istd,currRing);
107+
+ SI_RESTORE_OPT2(save_opt);
108+
+ return Istd;
109+
+ }
110+
}
111+
//--------------------------------------------------
112+
ideal Iquot,Istd;
113+
diff --git a/kernel/polys.cc b/kernel/polys.cc
114+
index 841a02cfa..9417bf7c9 100644
115+
--- a/kernel/polys.cc
116+
+++ b/kernel/polys.cc
117+
@@ -48,26 +48,27 @@ poly p_Divide(poly p, poly q, const ring r)
118+
{ /* This means that q != 0 consists of at least two terms*/
119+
if(p_GetComp(p,r)==0)
120+
{
121+
- if((rFieldType(r)==n_transExt)
122+
- &&(convSingTrP(p,r))
123+
- &&(convSingTrP(q,r))
124+
- &&(!rIsNCRing(r)))
125+
+ if (!rIsNCRing(r))
126+
{
127+
- poly res=singclap_pdivide(p, q, r);
128+
- p_Delete(&p,r);
129+
- p_Delete(&q,r);
130+
- return res;
131+
- }
132+
- else if ((r->cf->convSingNFactoryN!=ndConvSingNFactoryN)
133+
- &&(!rField_is_Ring(r))
134+
- &&(!rIsNCRing(r)))
135+
- {
136+
- poly res=singclap_pdivide(p, q, r);
137+
- p_Delete(&p,r);
138+
- p_Delete(&q,r);
139+
- return res;
140+
+ if((rFieldType(r)==n_transExt)
141+
+ &&(convSingTrP(p,r))
142+
+ &&(convSingTrP(q,r)))
143+
+ {
144+
+ poly res=singclap_pdivide(p, q, r);
145+
+ p_Delete(&p,r);
146+
+ p_Delete(&q,r);
147+
+ return res;
148+
+ }
149+
+ if ((rFieldType(r)==n_Q)
150+
+ ||(rFieldType(r)==n_Zp))
151+
+ {
152+
+ poly res=singclap_pdivide(p, q, r);
153+
+ p_Delete(&p,r);
154+
+ p_Delete(&q,r);
155+
+ return res;
156+
+ }
157+
}
158+
- else
159+
+ // generic division for poly
160+
{
161+
ideal vi=idInit(1,1); vi->m[0]=q;
162+
ideal ui=idInit(1,1); ui->m[0]=p;
163+
@@ -80,9 +81,9 @@ poly p_Divide(poly p, poly q, const ring r)
164+
ideal m = idLift(vi,ui,&R, FALSE,TRUE,TRUE,&U);
165+
SI_RESTORE_OPT1(save_opt);
166+
if (r!=save_ring) rChangeCurrRing(save_ring);
167+
- p=m->m[0]; m->m[0]=NULL;
168+
- id_Delete(&m,r);
169+
- p_SetCompP(p,0,r);
170+
+ matrix T = id_Module2formatedMatrix(m,1,1,r);
171+
+ p=MATELEM(T,1,1); MATELEM(T,1,1)=NULL;
172+
+ id_Delete((ideal *)&T,r);
173+
id_Delete((ideal *)&U,r);
174+
id_Delete(&R,r);
175+
//vi->m[0]=NULL; ui->m[0]=NULL;
176+
@@ -121,8 +122,7 @@ poly p_Divide(poly p, poly q, const ring r)
177+
{
178+
h=singclap_pdivide(I->m[i],q,r);
179+
}
180+
- else if ((r->cf->convSingNFactoryN!=ndConvSingNFactoryN)
181+
- &&(!rField_is_Ring(r))
182+
+ else if (((rFieldType(r)==n_Q)||(rFieldType(r)==n_Zp))
183+
&&(!rIsNCRing(r)))
184+
h=singclap_pdivide(I->m[i],q,r);
185+
else
186+
@@ -189,22 +189,23 @@ poly pp_Divide(poly p, poly q, const ring r)
187+
{ /* This means that q != 0 consists of at least two terms*/
188+
if(p_GetComp(p,r)==0)
189+
{
190+
- if((rFieldType(r)==n_transExt)
191+
- &&(convSingTrP(p,r))
192+
- &&(convSingTrP(q,r))
193+
- &&(!rIsNCRing(r)))
194+
- {
195+
- poly res=singclap_pdivide(p, q, r);
196+
- return res;
197+
- }
198+
- else if ((r->cf->convSingNFactoryN!=ndConvSingNFactoryN)
199+
- &&(!rField_is_Ring(r))
200+
- &&(!rIsNCRing(r)))
201+
+ if (!rIsNCRing(r))
202+
{
203+
- poly res=singclap_pdivide(p, q, r);
204+
- return res;
205+
+ if((rFieldType(r)==n_transExt)
206+
+ &&(convSingTrP(p,r))
207+
+ &&(convSingTrP(q,r)))
208+
+ {
209+
+ poly res=singclap_pdivide(p, q, r);
210+
+ return res;
211+
+ }
212+
+ if ((rFieldType(r)==n_Q)
213+
+ ||(rFieldType(r)==n_Zp))
214+
+ {
215+
+ poly res=singclap_pdivide(p, q, r);
216+
+ return res;
217+
+ }
218+
}
219+
- else
220+
+ // generic division for poly
221+
{
222+
ideal vi=idInit(1,1); vi->m[0]=p_Copy(q,r);
223+
ideal ui=idInit(1,1); ui->m[0]=p_Copy(p,r);
224+
@@ -253,17 +254,43 @@ poly pp_Divide(poly p, poly q, const ring r)
225+
{
226+
if (I->m[i]!=NULL)
227+
{
228+
- if((rFieldType(r)==n_transExt)
229+
- &&(convSingTrP(I->m[i],r))
230+
- &&(convSingTrP(q,r))
231+
- &&(!rIsNCRing(r)))
232+
+ if(!rIsNCRing(r))
233+
{
234+
- h=singclap_pdivide(I->m[i],q,r);
235+
+ if((rFieldType(r)==n_transExt)
236+
+ &&(convSingTrP(I->m[i],r))
237+
+ &&(convSingTrP(q,r)))
238+
+ {
239+
+ h=singclap_pdivide(I->m[i],q,r);
240+
+ }
241+
+ else if ((rFieldType(r)==n_Q)
242+
+ ||(rFieldType(r)==n_Zp))
243+
+ h=singclap_pdivide(I->m[i],q,r);
244+
+ else
245+
+ {
246+
+ ideal vi=idInit(1,1); vi->m[0]=q;
247+
+ ideal ui=idInit(1,1); ui->m[0]=I->m[i];
248+
+ ideal R; matrix U;
249+
+ ring save_ring=currRing;
250+
+ if (r!=currRing) rChangeCurrRing(r);
251+
+ BITSET save_opt;
252+
+ SI_SAVE_OPT1(save_opt);
253+
+ si_opt_1 &= ~(Sy_bit(OPT_PROT));
254+
+ ideal m = idLift(vi,ui,&R, FALSE,TRUE,TRUE,&U);
255+
+ SI_RESTORE_OPT1(save_opt);
256+
+ if (r!=save_ring) rChangeCurrRing(save_ring);
257+
+ if (idIs0(R))
258+
+ {
259+
+ matrix T = id_Module2formatedMatrix(m,1,1,r);
260+
+ p=MATELEM(T,1,1); MATELEM(T,1,1)=NULL;
261+
+ id_Delete((ideal *)&T,r);
262+
+ }
263+
+ id_Delete((ideal*)&U,r);
264+
+ id_Delete(&R,r);
265+
+ vi->m[0]=NULL; ui->m[0]=NULL;
266+
+ id_Delete(&vi,r);
267+
+ id_Delete(&ui,r);
268+
+ }
269+
}
270+
- else if ((r->cf->convSingNFactoryN!=ndConvSingNFactoryN)
271+
- &&(!rField_is_Ring(r))
272+
- &&(!rIsNCRing(r)))
273+
- h=singclap_pdivide(I->m[i],q,r);
274+
else
275+
{
276+
ideal vi=idInit(1,1); vi->m[0]=q;
277+
@@ -283,7 +310,6 @@ poly pp_Divide(poly p, poly q, const ring r)
278+
p=MATELEM(T,1,1); MATELEM(T,1,1)=NULL;
279+
id_Delete((ideal *)&T,r);
280+
}
281+
- else p=NULL;
282+
id_Delete((ideal*)&U,r);
283+
id_Delete(&R,r);
284+
vi->m[0]=NULL; ui->m[0]=NULL;
285+
--
286+
2.39.5
287+

build/pkgs/singular/spkg-configure.m4

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ SAGE_SPKG_CONFIGURE([singular], [
2323
AC_MSG_RESULT(no)
2424
sage_spkg_install_singular=yes
2525
])
26+
AC_MSG_CHECKING([that polynomial division over transcendental extensions is working])
27+
AS_IF([test x`printf "ring r = (0,x),(u,v),dp; \n ((1/x)*(u-1))/(u-1);" | Singular 2>&1 | grep "error occurred"` = x], [
28+
AC_MSG_RESULT(yes)
29+
], [
30+
AC_MSG_RESULT(no)
31+
sage_spkg_install_singular=yes
32+
])
2633
], [
2734
AC_MSG_RESULT([no])
2835
sage_spkg_install_singular=yes

src/sage/rings/polynomial/multi_polynomial_libsingular.pyx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2341,6 +2341,15 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base):
23412341
sage: h = f/g
23422342
sage: h*g == f
23432343
True
2344+
2345+
Ensure that :issue:`39801` is fixed::
2346+
2347+
sage: R.<x> = PolynomialRing(QQ)
2348+
sage: S.<u,v> = PolynomialRing(R)
2349+
sage: d = u - 1
2350+
sage: f = 1 / x * d
2351+
sage: f / d
2352+
1/x
23442353
"""
23452354
cdef poly *p
23462355
cdef MPolynomial_libsingular right = <MPolynomial_libsingular>right_ringelement
@@ -4197,6 +4206,15 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base):
41974206
Traceback (most recent call last):
41984207
...
41994208
NotImplementedError: Division of multivariate polynomials over non fields by non-monomials not implemented.
4209+
4210+
Ensure that :issue:`39801` is fixed::
4211+
4212+
sage: R.<a> = PolynomialRing(QQ)
4213+
sage: S.<x,y> = PolynomialRing(R)
4214+
sage: f = 1/a * (x^2 + y^2)
4215+
sage: g = x^2 + y^2
4216+
sage: f // g
4217+
1/a
42004218
"""
42014219
cdef MPolynomialRing_libsingular parent = self._parent
42024220
cdef MPolynomial_libsingular _right = <MPolynomial_libsingular>right

0 commit comments

Comments
 (0)