source: sage/rings/polynomial/polynomial_singular_interface.py @ 5849:9a8ffd2b3568

Revision 5849:9a8ffd2b3568, 17.2 KB checked in by William Stein <wstein@…>, 6 years ago (diff)

Fixes needed so Nick's patch works.

Line 
1"""
2Polynomial Interfaces to Singular
3
4AUTHORS:
5     -- Martin Albrecht <malb@informatik.uni-bremen.de> (2006-04-21)
6
7TESTS:
8    sage: R = MPolynomialRing(GF(2**8,'a'),10,'x', order='revlex')
9    sage: R == loads(dumps(R))
10    True
11    sage: P.<a,b> = PolynomialRing(GF(7), 2)
12    sage: f = (a^3 + 2*b^2*a)^7; f
13    a^21 + 2*a^7*b^14
14
15"""
16
17#################################################################
18#
19#   SAGE: System for Algebra and Geometry Experimentation   
20#
21#       Copyright (C) 2006 William Stein <wstein@gmail.com>
22#
23#  Distributed under the terms of the GNU General Public License (GPL)
24#
25#    This code is distributed in the hope that it will be useful,
26#    but WITHOUT ANY WARRANTY; without even the implied warranty of
27#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28#    General Public License for more details.
29#
30#  The full text of the GPL is available at:
31#
32#                  http://www.gnu.org/licenses/
33#
34######################################################################
35
36import sage.rings.finite_field
37import sage.rings.number_field as number_field
38
39from sage.interfaces.all import singular as singular_default, is_SingularElement
40from sage.rings.complex_field import is_ComplexField
41from sage.rings.real_mpfr import is_RealField
42from sage.rings.complex_double import is_ComplexDoubleField
43from sage.rings.real_double import is_RealDoubleField
44from sage.rings.integer_ring import ZZ
45import sage.rings.arith
46import sage.rings.ring
47
48
49class PolynomialRing_singular_repr:
50    """
51    Implements methods to convert polynomial rings to Singular.
52
53    This class is a base class for all univariate and multivariate
54    polynomial rings which support conversion from and to Singular
55    rings.
56    """
57    def _singular_(self, singular=singular_default, force=False):
58        """
59        Returns a singular ring for this polynomial ring over a field.
60        Currently QQ, GF(p), and GF(p^n), CC, and RR are supported.
61
62        INPUT:
63            singular -- Singular instance
64            force -- polynomials over ZZ may be coerced to Singular by
65                     treating them as polynomials over RR. This is
66                     inexact but works for some cases where the
67                     coeffients are not considered (default: False).
68
69        OUTPUT:
70            singular ring matching this ring
71
72        EXAMPLES:
73            sage: r = MPolynomialRing(GF(2**8,'a'),10,'x', order='revlex')
74            sage: r._singular_()
75            //   characteristic : 2
76            //   1 parameter    : a
77            //   minpoly        : (a^8+a^4+a^3+a^2+1)
78            //   number of vars : 10
79            //        block   1 : ordering rp
80            //                  : names    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9
81            //        block   2 : ordering C
82            sage: r = MPolynomialRing(GF(127),2,'x', order='revlex')
83            sage: r._singular_()
84            //   characteristic : 127
85            //   number of vars : 2
86            //        block   1 : ordering rp
87            //                  : names    x0 x1
88            //        block   2 : ordering C
89            sage: r = MPolynomialRing(QQ,2,'x', order='revlex')
90            sage: r._singular_()
91            //   characteristic : 0
92            //   number of vars : 2
93            //        block   1 : ordering rp
94            //                  : names    x0 x1
95            //        block   2 : ordering C
96            sage: r = PolynomialRing(QQ,'x')
97            sage: r._singular_()
98            //   characteristic : 0
99            //   number of vars : 1
100            //        block   1 : ordering lp
101            //                  : names    x
102            //        block   2 : ordering C
103            sage: r = PolynomialRing(GF(127),'x')
104            sage: r._singular_()
105            //   characteristic : 127
106            //   number of vars : 1
107            //        block   1 : ordering lp
108            //                  : names    x
109            //        block   2 : ordering C
110            sage: r = PolynomialRing(GF(2**8,'a'),'y')
111            sage: r._singular_()
112            //   characteristic : 2
113            //   1 parameter    : a
114            //   minpoly        : (a^8+a^4+a^3+a^2+1)
115            //   number of vars : 1
116            //        block   1 : ordering lp
117            //                  : names    y
118            //        block   2 : ordering C
119            sage: R.<x,y> = PolynomialRing(CC,'x',2)
120            sage: R._singular_()
121            //   characteristic : 0 (complex:15 digits, additional 0 digits)
122            //   1 parameter    : I
123            //   minpoly        : (I^2+1)
124            //   number of vars : 2
125            //        block   1 : ordering dp
126            //                  : names    x y
127            //        block   2 : ordering C
128            sage: R.<x,y> = PolynomialRing(RealField(100),'x',2)
129            sage: R._singular_()
130            //   characteristic : 0 (real:29 digits, additional 0 digits)
131            //   number of vars : 2
132            //        block   1 : ordering dp
133            //                  : names    x y
134            //        block   2 : ordering C
135
136            sage: w = var('w')
137            sage: R.<x,y> = PolynomialRing(NumberField(w^2+1,'s'))
138            sage: R._singular_()
139            //   characteristic : 0
140            //   1 parameter    : s
141            //   minpoly        : (s^2+1)
142            //   number of vars : 2
143            //        block   1 : ordering dp
144            //                  : names    x y
145            //        block   2 : ordering C
146
147        WARNING:
148           If the base ring is a finite extension field or a number field
149           the ring will not only be returned but also be set as the current
150           ring in Singular.
151
152        NOTE:
153            Singular represents precision of floating point numbers base 10
154            while SAGE represents floating point precision base 2.
155        """
156        try:
157            R = self.__singular
158            if not (R.parent() is singular):
159                raise ValueError
160            R._check_valid()
161            if self.base_ring() is ZZ or self.base_ring().is_prime_field():
162                return R
163            if sage.rings.ring.is_FiniteField(self.base_ring()) or\
164                    number_field.number_field.is_NumberField(self.base_ring()):
165                R.set_ring() #sorry for that, but needed for minpoly
166                if  singular.eval('minpoly') != self.__minpoly:
167                    singular.eval("minpoly=%s"%(self.__minpoly))
168            return R
169        except (AttributeError, ValueError):
170            return self._singular_init_(singular, force)
171           
172    def _singular_init_(self, singular=singular_default, force=False):
173        """
174        Return a newly created Singular ring matching this ring.
175        """
176        if not self._can_convert_to_singular() and not force:
177            raise TypeError, "no conversion of this ring to a Singular ring defined"
178       
179        if self.ngens()==1:
180            _vars = str(self.gen())
181            if "*" in _vars: # 1.000...000*x
182                _vars = _vars.split("*")[1]
183            order = 'lp'
184        else:
185            _vars = str(self.gens())
186            order = self.term_order().singular_str()
187           
188        if is_RealField(self.base_ring()):
189            # singular converts to bits from base_10 in mpr_complex.cc by:
190            #  size_t bits = 1 + (size_t) ((float)digits * 3.5);
191            precision = self.base_ring().precision()
192            digits = sage.rings.arith.integer_ceil((2*precision - 2)/7.0)
193            self.__singular = singular.ring("(real,%d,0)"%digits, _vars, order=order, check=False)
194
195        elif is_ComplexField(self.base_ring()):
196            # singular converts to bits from base_10 in mpr_complex.cc by:
197            #  size_t bits = 1 + (size_t) ((float)digits * 3.5);
198            precision = self.base_ring().precision()
199            digits = sage.rings.arith.integer_ceil((2*precision - 2)/7.0)
200            self.__singular = singular.ring("(complex,%d,0,I)"%digits, _vars,  order=order, check=False)
201
202        elif is_RealDoubleField(self.base_ring()):
203            # singular converts to bits from base_10 in mpr_complex.cc by:
204            #  size_t bits = 1 + (size_t) ((float)digits * 3.5);
205            self.__singular = singular.ring("(real,15,0)", _vars, order=order, check=False)
206
207        elif is_ComplexDoubleField(self.base_ring()):
208            # singular converts to bits from base_10 in mpr_complex.cc by:
209            #  size_t bits = 1 + (size_t) ((float)digits * 3.5);
210            self.__singular = singular.ring("(complex,15,0,I)", _vars,  order=order, check=False)
211
212        elif self.base_ring().is_prime_field() or (self.base_ring() is ZZ and force):
213            self.__singular = singular.ring(self.characteristic(), _vars, order=order, check=False)
214       
215        elif sage.rings.ring.is_FiniteField(self.base_ring()):
216            # not the prime field!
217            gen = str(self.base_ring().gen())
218            r = singular.ring( "(%s,%s)"%(self.characteristic(),gen), _vars, order=order, check=False)
219            self.__minpoly = "("+(str(self.base_ring().modulus()).replace("x",gen)).replace(" ","")+")"
220            singular.eval("minpoly=%s"%(self.__minpoly) )
221
222            self.__singular = r
223        elif number_field.number_field.is_NumberField(self.base_ring()):
224            # not the rationals!
225            gen = str(self.base_ring().gen())
226            poly=self.base_ring().polynomial()
227            poly_gen=str(poly.parent().gen())
228            poly_str=str(poly).replace(poly_gen,gen)
229            r = singular.ring( "(%s,%s)"%(self.characteristic(),gen), _vars, order=order, check=False)
230            self.__minpoly = "("+(poly_str).replace(" ","")+")"
231            singular.eval("minpoly=%s"%(self.__minpoly) )
232
233            self.__singular = r
234                       
235       
236        else:   
237            raise TypeError, "no conversion to a Singular ring defined"
238
239        return self.__singular
240
241    def _can_convert_to_singular(self):
242        """
243        Returns True if this ring's base field or ring can be
244        represented in Singular.  If this is True then this polynomial
245        ring can be represented in Singular.
246
247        The following base rings are supported: $GF(p)$, $GF(p^n)$,
248        rationals, number fields, and real and complex fields.
249        """
250        base_ring = self.base_ring()
251        return ( sage.rings.ring.is_FiniteField(base_ring)
252                 or base_ring.is_prime_field()
253                 or is_RealField(base_ring)
254                 or is_ComplexField(base_ring)
255                 or is_RealDoubleField(base_ring)
256                 or is_ComplexDoubleField(base_ring)
257                 or number_field.number_field.is_NumberField(base_ring)
258                 or base_ring is ZZ )
259
260
261class Polynomial_singular_repr:
262    """
263    Implements coercion of polynomials to Singular polynomials.
264
265    This class is a base class for all (univariate and multivariate)
266    polynomial classes which support conversion from and to
267    Singular polynomials.
268    """
269    def _singular_(self, singular=singular_default, have_ring=False, force=False):
270        """
271        Return Singular polynomial matching this polynomial.
272
273        INPUT:
274            singular -- Singular instance to use
275
276            have_ring -- if True we will not attempt to set this
277                         element's ring as the current Singular
278                         ring. This is useful to speed up a batch of
279                         f._singular_() calls. However, it's dangerous
280                         as it might lead to wrong results if another
281                         ring is singluar.current_ring().  (default:
282                         False)
283
284            force -- polynomials over ZZ may be coerced to Singular by
285                     treating them as polynomials over QQ. This is
286                     inexact but works for some cases where the
287                     coeffients are not considered (default: False).
288
289
290        EXAMPLES:
291            sage: P.<a,b> = PolynomialRing(GF(7), 2)
292            sage: f = (a^3 + 2*b^2*a)^7; f
293            a^21 + 2*a^7*b^14
294            sage: h = f._singular_(); h
295            a^21+2*a^7*b^14
296            sage: P(h)
297            a^21 + 2*a^7*b^14
298            sage: P(h^20) == f^20
299            True
300
301            sage: R.<x> = PolynomialRing(GF(7))
302            sage: f = (x^3 + 2*x^2*x)^7
303            sage: f
304            3*x^21
305            sage: h = f._singular_(); h
306            3*x^21
307            sage: R(h)
308            3*x^21
309            sage: R(h^20) == f^20
310            True
311        """
312        if not have_ring:
313            self.parent()._singular_(singular,force=force).set_ring() #this is expensive
314
315        try:
316            self.__singular._check_valid()
317            if self.__singular.parent() is singular:
318                return self.__singular
319        except (AttributeError,ValueError):
320            pass
321        return self._singular_init_(singular,have_ring=have_ring)
322
323    def _singular_init_(self, singular=singular_default, have_ring=False, force=False):
324        """
325        Return corresponding Singular polynomial but enforce that a new
326        instance is created in the Singular interpreter.
327
328        Use self._singular_() instead.
329        """
330        if not have_ring:
331            self.parent()._singular_(singular,force=force).set_ring() #this is expensive
332
333        self.__singular = singular(str(self))
334
335        return self.__singular
336
337    def lcm(self, right, have_ring=False):
338        """
339        Returns the least common multiple of this element and the right element.
340
341        INPUT:
342            right -- multivariate polynomial
343            have_ring -- see self._singular_() (default:False)
344
345        OUTPUT:
346            multivariate polynomial representing the least common
347            multiple of self and right
348
349        ALGORITHM: Singular
350
351        EXAMPLES:
352            sage: r.<x,y> = MPolynomialRing(GF(2**8,'a'),2)
353            sage: a = r.base_ring().0
354            sage: f = (a^2+a)*x^2*y + (a^4+a^3+a)*y + a^5
355            sage: f.lcm(x^4)
356            (a^2 + a)*x^6*y + (a^4 + a^3 + a)*x^4*y + (a^5)*x^4
357           
358            sage: w = var('w')
359            sage: r.<x,y> = MPolynomialRing(NumberField(w^4+1,'a'),2)
360            sage: a = r.base_ring().0
361            sage: f = (a^2+a)*x^2*y + (a^4+a^3+a)*y + a^5
362            sage: f.lcm(x^4)
363            (a^2 + a)*x^6*y + (a^3 + a - 1)*x^4*y + (-a)*x^4
364        """
365        lcm = self._singular_(have_ring=have_ring).lcm(right._singular_(have_ring=have_ring))
366        return lcm.sage_poly(self.parent())
367
368    def diff(self, variable, have_ring=False):
369        """
370        Differentiates self with respect to the provided variable. This
371        is completely symbolic so it is also defined over e.g. finite
372        fields.
373       
374        INPUT:
375            variable -- the derivative is taken with respect to variable
376            have_ring -- see self._singular_() (default:False)
377
378        EXAMPLES:
379            sage: R.<x,y> = PolynomialRing(RR,2)
380            sage: f = 3*x^3*y^2 + 5*y^2 + 3*x + 2
381            sage: f.diff(x)
382            9.00000000000000*x^2*y^2 + 3.00000000000000
383            sage: f.diff(y)
384            6.00000000000000*x^3*y + 10.0000000000000*y
385 
386            The derivate is also defined over finite fields:
387
388            sage: R.<x,y> = PolynomialRing(GF(2**8, 'a'),2)
389            sage: f = x^3*y^2 + y^2 + x + 2
390            sage: f.diff(x)
391            x^2*y^2 + 1
392
393            The new coefficients are coerced to the base ring:
394           
395            sage: f.diff(y)
396            0
397
398            sage: w = var('w')
399            sage: R.<x,y> = PolynomialRing(NumberField(w^3-2, 'a'),2)
400            sage: a=R.base_ring().0
401            sage: f = x^3*y^2 + y^2 + a*x + 2
402            sage: f.diff(x)
403            3*x^2*y^2 + a
404       
405        ALGORITHM: Singular
406       
407        """
408        df = self._singular_(have_ring=have_ring).diff(variable._singular_(have_ring=have_ring))
409        return df.sage_poly(self.parent())
410
411
412    def resultant(self, other, variable=None):
413        """
414        computes the resultant of self and the first argument with
415        respect to the variable given as the second argument.
416
417        If a second argument is not provide the first variable of
418        self.parent() is chosen.
419
420        INPUT:
421            other -- polynomial in self.parent()
422            variable -- optional variable (of type polynomial) in self.parent() (default: None)
423
424        EXAMPLE:
425            sage: P.<x,y> = PolynomialRing(QQ,2)
426            sage: a = x+y
427            sage: b = x^3-y^3
428            sage: c = a.resultant(b); c
429            -2*y^3
430            sage: d = a.resultant(b,y); d
431            2*x^3
432
433        TESTS:
434            sage: from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict_domain
435            sage: P.<x,y> = MPolynomialRing_polydict_domain(QQ,2,order='degrevlex')
436            sage: a = x+y
437            sage: b = x^3-y^3
438            sage: c = a.resultant(b); c
439            -2*y^3
440            sage: d = a.resultant(b,y); d
441            2*x^3
442           
443        """
444        if variable is None:
445            variable = self.parent().gen(0)
446        rt = self._singular_().resultant(other._singular_(), variable._singular_())
447        r = rt.sage_poly(self.parent())
448        if self.parent().ngens() <= 1 and r.degree() <= 0:
449            return self.parent().base_ring()(r[0])
450        else:
451            return r
Note: See TracBrowser for help on using the repository browser.