Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/libs/singular/polynomial.pyx
4057 views
1
"""
2
Wrapper for Singular's Polynomial Arithmetic
3
4
AUTHOR:
5
6
- Martin Albrecht (2009-07): refactoring
7
"""
8
#*****************************************************************************
9
# Copyright (C) 2009 Martin Albrecht <[email protected]>
10
#
11
# Distributed under the terms of the GNU General Public License (GPL)
12
# http://www.gnu.org/licenses/
13
#*****************************************************************************
14
include "../../ext/interrupt.pxi"
15
16
cdef extern from "":
17
int unlikely(int)
18
19
import re
20
plusminus_pattern = re.compile("([^\(^])([\+\-])")
21
22
from sage.libs.singular.decl cimport number, ideal
23
from sage.libs.singular.decl cimport currRing, rChangeCurrRing
24
from sage.libs.singular.decl cimport p_Copy, p_Add_q, p_Neg, pp_Mult_nn, p_GetCoeff, p_IsConstant, p_Cmp, pNext
25
from sage.libs.singular.decl cimport p_GetMaxExp, pp_Mult_qq, pPower, p_String, p_GetExp, pLDeg
26
from sage.libs.singular.decl cimport n_Delete, idInit, fast_map, id_Delete
27
from sage.libs.singular.decl cimport omAlloc0, omStrDup, omFree
28
from sage.libs.singular.decl cimport p_GetComp, p_SetComp
29
30
31
from sage.libs.singular.singular cimport sa2si, si2sa, overflow_check
32
33
from sage.misc.latex import latex
34
35
cdef int singular_polynomial_check(poly *p, ring *r) except -1:
36
"""
37
Run consistency checks on ``p``.
38
"""
39
while p:
40
if p_GetCoeff(p, r) == NULL:
41
raise ZeroDivisionError("NULL pointer as coefficient.")
42
p = p.next
43
return 0
44
45
cdef int singular_polynomial_add(poly **ret, poly *p, poly *q, ring *r):
46
"""
47
``ret[0] = p+q`` where ``p`` and ``p`` in ``r``.
48
49
INPUT:
50
51
- ``ret`` - a pointer to a Singular polynomial to store the result in
52
- ``p`` - a Singular polynomial
53
- ``q`` - a Singular polynomial
54
- ``r`` - a Singular ring
55
56
EXAMPLE::
57
58
sage: P.<x,y,z> = QQ[]
59
sage: x + y # indirect doctest
60
x + y
61
62
sage: x + P(0)
63
x
64
"""
65
if(r != currRing): rChangeCurrRing(r)
66
p = p_Copy(p, r)
67
q = p_Copy(q, r)
68
ret[0] = p_Add_q(p, q, r)
69
return 0;
70
71
cdef int singular_polynomial_sub(poly **ret, poly *p, poly *q, ring *r):
72
"""
73
``ret[0] = p-q`` where ``p`` and ``p`` in ``r``.
74
75
INPUT:
76
77
- ``ret`` - a pointer to a Singular polynomial to store the result in
78
- ``p`` - a Singular polynomial
79
- ``q`` - a Singular polynomial
80
- ``r`` - a Singular ring
81
82
EXAMPLE::
83
84
sage: P.<x,y,z> = QQ[]
85
sage: x - y # indirect doctest
86
x - y
87
88
sage: x + P(0)
89
x
90
"""
91
if(r != currRing): rChangeCurrRing(r)
92
p = p_Copy(p, r)
93
q = p_Copy(q, r)
94
ret[0] = p_Add_q(p, p_Neg(q, r), r)
95
return 0;
96
97
cdef int singular_polynomial_rmul(poly **ret, poly *p, RingElement n, ring *r):
98
"""
99
``ret[0] = n*p`` where ``n`` is a coefficient and ``p`` in ``r``.
100
101
INPUT:
102
103
- ``ret`` - a pointer to a Singular polynomial to store the result in
104
- ``p`` - a Singular polynomial
105
- ``n`` - a Sage coefficient
106
- ``r`` - a Singular ring
107
108
EXAMPLE::
109
110
sage: P.<x,y,z> = QQ[]
111
sage: 2*x # indirect doctest
112
2*x
113
114
sage: P(0)*x
115
0
116
"""
117
if(r != currRing): rChangeCurrRing(r)
118
cdef number *_n = sa2si(n,r)
119
ret[0] = pp_Mult_nn(p, _n, r)
120
n_Delete(&_n, r)
121
return 0
122
123
cdef int singular_polynomial_call(poly **ret, poly *p, ring *r, list args, poly *(*get_element)(object)):
124
"""
125
``ret[0] = p(*args)`` where each entry in arg is a polynomial and ``p`` in ``r``.
126
127
INPUT:
128
129
- ``ret`` - a pointer to a Singular polynomial to store the result in
130
- ``p`` - a Singular polynomial
131
- ``r`` - a Singular ring
132
- ``args`` - a list/tuple of elements which can be converted to
133
Singular polynomials using the ``(get_element)`` function
134
provided.
135
- ``(*get_element)`` - a function to turn a Sage element into a
136
Singular element.
137
138
EXAMPLE::
139
140
sage: P.<x,y,z> = QQ[]
141
sage: x(0,0,0) # indirect doctest
142
0
143
144
sage: (3*x*z)(x,x,x)
145
3*x^2
146
"""
147
cdef long l = len(args)
148
cdef ideal *to_id = idInit(l,1)
149
for i from 0 <= i < l:
150
to_id.m[i]= p_Copy( get_element(args[i]), r)
151
152
cdef ideal *from_id=idInit(1,1)
153
from_id.m[0] = p
154
155
rChangeCurrRing(r)
156
cdef ideal *res_id = fast_map(from_id, r, to_id, r)
157
ret[0] = res_id.m[0]
158
159
from_id.m[0] = NULL
160
res_id.m[0] = NULL
161
162
id_Delete(&to_id, r)
163
id_Delete(&from_id, r)
164
id_Delete(&res_id, r)
165
166
return 0
167
168
cdef int singular_polynomial_cmp(poly *p, poly *q, ring *r):
169
"""
170
Compare two Singular elements ``p`` and ``q`` in ``r``.
171
172
INPUT:
173
174
- ``p`` - a Singular polynomial
175
- ``q`` - a Singular polynomial
176
- ``r`` - a Singular ring
177
178
EXAMPLES::
179
180
sage: P.<x,y,z> = PolynomialRing(QQ,order='degrevlex')
181
sage: x == x
182
True
183
184
sage: x > y
185
True
186
sage: y^2 > x
187
True
188
189
sage: (2/3*x^2 + 1/2*y + 3) > (2/3*x^2 + 1/4*y + 10)
190
True
191
"""
192
cdef number *h
193
cdef int ret = 0
194
195
if(r != currRing): rChangeCurrRing(r)
196
197
# handle special cases first (slight slowdown, as special cases
198
# are - well - special
199
if p == NULL:
200
if q == NULL:
201
# compare 0, 0
202
return 0
203
elif p_IsConstant(q,r):
204
# compare 0, const
205
return 1-2*r.cf.nGreaterZero(p_GetCoeff(q,r)) # -1: <, 1: > #
206
elif q == NULL:
207
if p_IsConstant(p,r):
208
# compare const, 0
209
return -1+2*r.cf.nGreaterZero(p_GetCoeff(p,r)) # -1: <, 1: >
210
#else
211
212
while ret==0 and p!=NULL and q!=NULL:
213
ret = p_Cmp( p, q, r)
214
215
if ret==0:
216
h = r.cf.nSub(p_GetCoeff(p, r),p_GetCoeff(q, r))
217
# compare coeffs
218
ret = -1+r.cf.nIsZero(h)+2*r.cf.nGreaterZero(h) # -1: <, 0:==, 1: >
219
n_Delete(&h, r)
220
p = pNext(p)
221
q = pNext(q)
222
223
if ret==0:
224
if p==NULL and q != NULL:
225
ret = -1
226
elif p!=NULL and q==NULL:
227
ret = 1
228
229
return ret
230
231
cdef int singular_polynomial_mul(poly** ret, poly *p, poly *q, ring *r) except -1:
232
"""
233
``ret[0] = p*q`` where ``p`` and ``p`` in ``r``.
234
235
INPUT:
236
237
- ``ret`` - a pointer to a Singular polynomial to store the result in
238
- ``p`` - a Singular polynomial
239
- ``q`` - a Singular polynomial
240
- ``r`` - a Singular ring
241
242
EXAMPLE::
243
244
sage: P.<x,y,z> = QQ[]
245
sage: x*y # indirect doctest
246
x*y
247
248
sage: x * P(0)
249
0
250
"""
251
if(r != currRing): rChangeCurrRing(r)
252
cdef unsigned long le = p_GetMaxExp(p, r)
253
cdef unsigned long lr = p_GetMaxExp(q, r)
254
cdef unsigned long esum = le + lr
255
overflow_check(esum, r)
256
ret[0] = pp_Mult_qq(p, q, r)
257
return 0;
258
259
cdef int singular_polynomial_div_coeff(poly** ret, poly *p, poly *q, ring *r) except -1:
260
"""
261
``ret[0] = p/n`` where ``p`` and ``q`` in ``r`` and ``q`` constant.
262
263
The last condition is not checked.
264
265
INPUT:
266
267
- ``ret`` - a pointer to a Singular polynomial to store the result in
268
- ``p`` - a Singular polynomial
269
- ``q`` - a constant Singular polynomial
270
- ``r`` - a Singular ring
271
272
EXAMPLE::
273
274
sage: P.<x,y,z> = QQ[]
275
sage: x/2 # indirect doctest
276
1/2*x
277
278
sage: x/0
279
Traceback (most recent call last):
280
...
281
ZeroDivisionError: rational division by zero
282
"""
283
if q == NULL:
284
raise ZeroDivisionError
285
cdef number *n = p_GetCoeff(q, r)
286
n = r.cf.nInvers(n)
287
ret[0] = pp_Mult_nn(p, n, r)
288
n_Delete(&n, r)
289
return 0
290
291
cdef int singular_polynomial_pow(poly **ret, poly *p, long exp, ring *r) except -1:
292
"""
293
``ret[0] = p**exp`` where ``p`` in ``r`` and ``exp`` > 0.
294
295
The last condition is not checked.
296
297
INPUT:
298
299
- ``ret`` - a pointer to a Singular polynomial to store the result in
300
- ``p`` - a Singular polynomial
301
- ``exp`` - integer
302
- ``r`` - a Singular ring
303
304
EXAMPLE::
305
306
sage: P.<x,y,z> = QQ[]
307
sage: f = 3*x*y + 5/2*z
308
sage: f*f == f^2 # indirect doctest
309
True
310
sage: f^2
311
9*x^2*y^2 + 15*x*y*z + 25/4*z^2
312
sage: f^0
313
1
314
sage: f^(2^60)
315
Traceback (most recent call last):
316
...
317
OverflowError: ...
318
"""
319
cdef unsigned long v = p_GetMaxExp(p, r)
320
v = v * exp
321
322
overflow_check(v, r)
323
324
if(r != currRing): rChangeCurrRing(r)
325
cdef int count = singular_polynomial_length_bounded(p,15)
326
if count >= 15 or exp > 15:
327
sig_on()
328
ret[0] = pPower( p_Copy(p,r), exp)
329
if count >= 15 or exp > 15:
330
sig_off()
331
return 0
332
333
cdef int singular_polynomial_neg(poly **ret, poly *p, ring *r):
334
"""
335
``ret[0] = -p where ``p`` in ``r``.
336
337
The last condition is not checked.
338
339
INPUT:
340
341
- ``ret`` - a pointer to a Singular polynomial to store the result in
342
- ``p`` - a Singular polynomial
343
- ``r`` - a Singular ring
344
345
EXAMPLE::
346
347
sage: P.<x,y,z> = QQ[]
348
sage: f = 3*x*y + 5/2*z
349
sage: -f # indirect doctest
350
-3*x*y - 5/2*z
351
sage: -P(0)
352
0
353
"""
354
if(r != currRing): rChangeCurrRing(r)
355
ret[0] = p_Neg(p_Copy(p,r),r)
356
return 0
357
358
cdef object singular_polynomial_str(poly *p, ring *r):
359
"""
360
Return the string representation of ``p``.
361
362
INPUT:
363
364
- ``p`` - a Singular polynomial
365
- ``r`` - a Singular ring
366
367
EXAMPLE::
368
369
sage: P.<x,y,z> = ZZ[]
370
sage: str(x) # indirect doctest
371
'x'
372
sage: str(10*x)
373
'10*x'
374
"""
375
if(r!=currRing): rChangeCurrRing(r)
376
377
s = p_String(p, r, r)
378
s = re.sub(plusminus_pattern, "\\1 \\2 ", s)
379
return s
380
381
382
cdef object singular_polynomial_latex(poly *p, ring *r, object base, object latex_gens):
383
r"""
384
Return the LaTeX string representation of ``p``.
385
386
INPUT:
387
388
- ``p`` - a Singular polynomial
389
- ``r`` - a Singular ring
390
391
EXAMPLE::
392
393
sage: P.<x,y,z> = QQ[]
394
sage: latex(x) # indirect doctest
395
x
396
sage: latex(10*x^2 + 1/2*y)
397
10 x^{2} + \frac{1}{2} y
398
399
Demonstrate that coefficients over non-atomic representated rings are
400
properly parenthesized (Trac 11186)
401
sage: x = var('x')
402
sage: K.<z> = QQ.extension(x^2 + x + 1)
403
sage: P.<v,w> = K[]
404
sage: latex((z+1)*v*w - z*w^2 + z*v + z^2*w + z + 1)
405
\left(z + 1\right) v w - z w^{2} + z v + \left(-z - 1\right) w + z + 1
406
"""
407
poly = ""
408
cdef long e,j
409
cdef int n = r.N
410
cdef int atomic_repr = base.is_atomic_repr()
411
while p:
412
413
# First determine the multinomial:
414
multi = ""
415
for j in range(1,n+1):
416
e = p_GetExp(p, j, r)
417
if e > 0:
418
multi += " "+latex_gens[j-1]
419
if e > 1:
420
multi += "^{%d}"%e
421
multi = multi.lstrip().rstrip()
422
423
# Next determine coefficient of multinomial
424
c = si2sa( p_GetCoeff(p, r), r, base)
425
if len(multi) == 0:
426
multi = latex(c)
427
elif c != 1:
428
if c == -1:
429
multi = "- %s"%(multi)
430
else:
431
sc = latex(c)
432
# Add parenthesis if the coefficient consists of terms divided by +, -
433
# (starting with - is not enough) and is not the constant term
434
if not atomic_repr and multi and (sc.find("+") != -1 or sc[1:].find("-") != -1):
435
sc = "\\left(%s\\right)"%sc
436
multi = "%s %s"%(sc,multi)
437
438
# Now add on coefficiented multinomials
439
if len(poly) > 0:
440
poly = poly + " + "
441
poly = poly + multi
442
443
p = pNext(p)
444
445
poly = poly.lstrip().rstrip()
446
poly = poly.replace("+ -","- ")
447
448
if len(poly) == 0:
449
return "0"
450
return poly
451
452
cdef object singular_polynomial_str_with_changed_varnames(poly *p, ring *r, object varnames):
453
cdef char **_names
454
cdef char **_orig_names
455
cdef char *_name
456
cdef int i
457
458
if len(varnames) != r.N:
459
raise TypeError("len(varnames) doesn't equal self.parent().ngens()")
460
461
_names = <char**>omAlloc0(sizeof(char*)*r.N)
462
for i from 0 <= i < r.N:
463
_name = varnames[i]
464
_names[i] = omStrDup(_name)
465
466
_orig_names = r.names
467
r.names = _names
468
s = singular_polynomial_str(p, r)
469
r.names = _orig_names
470
471
for i from 0 <= i < r.N:
472
omFree(_names[i])
473
omFree(_names)
474
return s
475
476
cdef long singular_polynomial_deg(poly *p, poly *x, ring *r):
477
cdef int deg, _deg, i
478
479
deg = 0
480
if p == NULL:
481
return -1
482
if(r != currRing): rChangeCurrRing(r)
483
if x == NULL:
484
return pLDeg(p,&deg,r)
485
486
for i in range(1,r.N+1):
487
if p_GetExp(x, i, r):
488
break
489
while p:
490
_deg = p_GetExp(p,i,r)
491
if _deg > deg:
492
deg = _deg
493
p = pNext(p)
494
return deg
495
496
cdef inline int singular_polynomial_length_bounded(poly *p, int bound):
497
"""
498
Return the number of monomials in ``p`` but stop counting at
499
``bound``.
500
501
This is useful to estimate whether a certain calculation will take
502
long or not.
503
504
INPUT:
505
506
- ``p`` - a Singular polynomial
507
- ``bound`` - an integer > 0
508
"""
509
cdef int count = 0
510
while p != NULL and count < bound:
511
p = pNext(p)
512
count += 1
513
return count
514
515
cdef int singular_vector_maximal_component(poly *v, ring *r) except -1:
516
"""
517
returns the maximal module component of the vector ``v``.
518
INPUT:
519
520
- ``v`` - a polynomial/vector
521
- ``r`` - a ring
522
"""
523
cdef int res=0
524
while v!=NULL:
525
res=max(p_GetComp(v, r), res)
526
v = pNext(v)
527
return res
528
529