# HG changeset patch
# User Robert Bradshaw <robertwb@math.washington.edu>
# Date 1232710683 28800
# Node ID e5ee10dabd83e0e9767e0ee30efc07f8e53f36a4
# Parent  3c91f9e16780c22d9632c30630feafa30b8e0bd6
Convert univariate polynomials to new coercion model.

diff --git a/sage/categories/morphism.pyx b/sage/categories/morphism.pyx
--- a/sage/categories/morphism.pyx
+++ b/sage/categories/morphism.pyx
@@ -104,9 +104,9 @@
         if len(args) == 0 and len(kwds) == 0:
             return x
         elif self._codomain._element_init_pass_parent:
-            return self._codomain._element_class(self._codomain, x, *args, **kwds)
+            return self._codomain._element_constructor(self._codomain, x, *args, **kwds)
         else:
-            return self._codomain._element_class(x, *args, **kwds)
+            return self._codomain._element_constructor(x, *args, **kwds)
 
     def __mul__(left, right):
         if not isinstance(right, Morphism):
diff --git a/sage/rings/number_field/number_field_ideal_rel.py b/sage/rings/number_field/number_field_ideal_rel.py
--- a/sage/rings/number_field/number_field_ideal_rel.py
+++ b/sage/rings/number_field/number_field_ideal_rel.py
@@ -69,11 +69,8 @@
         try:
             return self.__absolute_ideal
         except AttributeError:
-            rnf = self.number_field().pari_rnf()
             L = self.number_field().absolute_field('a')
-            R = L['x']
-            nf = L.pari_nf()
-            genlist = [L(R(x.polynomial())) for x in list(self.gens())]
+            genlist = [L(x.polynomial()) for x in list(self.gens())]
             self.__absolute_ideal = L.ideal(genlist)
             return self.__absolute_ideal
 
diff --git a/sage/rings/polynomial/polynomial_element.pxd b/sage/rings/polynomial/polynomial_element.pxd
--- a/sage/rings/polynomial/polynomial_element.pxd
+++ b/sage/rings/polynomial/polynomial_element.pxd
@@ -14,12 +14,15 @@
     cdef CompiledPolynomialFunction _compiled
     cpdef Polynomial truncate(self, long n)
     cdef long _hash_c(self)
+    cpdef constant_coefficient(self)
+    cpdef Polynomial _new_constant_poly(self, a)
 
     # UNSAFE, only call from an inplace operator
     # may return a new element if not possible to modify inplace
     cdef _inplace_truncate(self, long n)
 
 cdef class Polynomial_generic_dense(Polynomial):
+    cdef Polynomial_generic_dense _new_c(self, list coeffs)
     cdef list __coeffs
     cdef void __normalize(self)
 #    cdef _dict_to_list(self, x, zero)
diff --git a/sage/rings/polynomial/polynomial_element.pyx b/sage/rings/polynomial/polynomial_element.pyx
--- a/sage/rings/polynomial/polynomial_element.pyx
+++ b/sage/rings/polynomial/polynomial_element.pyx
@@ -68,6 +68,9 @@
 import polynomial_fateman
 
 from sage.rings.integer cimport Integer
+
+from sage.categories.map cimport Map
+from sage.categories.morphism cimport Morphism
 
 def is_Polynomial(f):
     """
@@ -705,10 +708,10 @@
             sage: QQ(3*x + 45)
             Traceback (most recent call last):
             ...
-            TypeError: cannot coerce nonconstant polynomial
-        """
-        if self.degree() > 0:
-            raise TypeError, "cannot coerce nonconstant polynomial"
+            TypeError: not a constant polynomial
+        """
+        if self.degree() > 0:
+            raise TypeError, "not a constant polynomial"
         return sage.rings.rational.Rational(self[0])
 
     def __invert__(self):
@@ -2454,7 +2457,7 @@
         return R.fraction_field()[self.parent().variable_name()].quotient(self, names)
 
 
-    def constant_coefficient(self):
+    cpdef constant_coefficient(self):
         """
         Return the constant coefficient of this polynomial.
 
@@ -2468,6 +2471,12 @@
             -1/3
         """
         return self[0]
+
+    cpdef Polynomial _new_constant_poly(self, a):
+        """
+        Create a new constant polynomial from a, which MUST be an element of the basering. 
+        """
+        return self._parent._element_constructor(a)
 
     def is_monic(self):
         """
@@ -4329,8 +4338,43 @@
         if check:
             self.__normalize()
             
+    cdef Polynomial_generic_dense _new_c(self, list coeffs):
+        cdef Polynomial_generic_dense f = <Polynomial_generic_dense>PY_NEW_SAME_TYPE(self)
+        f._parent = self._parent
+        f.__coeffs = coeffs
+        return f
+    
+    cpdef Polynomial _new_constant_poly(self, a):
+        """
+        Create a new constant polynomial from a, which MUST be an element of the basering. 
+        
+        EXAMPLES: 
+            sage: S.<y> = QQ[]
+            sage: R.<x> = S[]
+            sage: x._new_constant_poly(y+1)
+            y + 1
+            sage: parent(x._new_constant_poly(y+1))
+            Univariate Polynomial Ring in x over Univariate Polynomial Ring in y over Rational Field
+        """
+        if a:
+            return self._new_c([a])
+        else:
+            return self._new_c([])
             
     def __reduce__(self):
+        """
+        For pickling.
+        
+        TESTS:
+            sage: R.<x> = QQ['a,b']['x']
+            sage: f = x^3-x
+            sage: loads(dumps(f)) == f
+            True
+            
+        Make sure we're testing the right method. 
+            sage: type(f)
+            <type 'sage.rings.polynomial.polynomial_element.Polynomial_generic_dense'>
+        """
         return make_generic_polynomial, (self._parent, self.__coeffs)
 
     def __nonzero__(self):
@@ -4438,9 +4482,12 @@
         if right.parent() == self.parent():
             return Polynomial.__floordiv__(self, right)
         d = self.parent().base_ring()(right)
-        return self._parent([c // d for c in self.__coeffs], check=False)
+        cdef Polynomial_generic_dense res = self._new_c([c // d for c in self.__coeffs])
+        res.__normalize()
+        return res
         
     cpdef ModuleElement _add_(self, ModuleElement right):
+        cdef Polynomial_generic_dense res
         cdef Py_ssize_t check=0, i, min
         x = (<Polynomial_generic_dense>self).__coeffs
         y = (<Polynomial_generic_dense>right).__coeffs
@@ -4452,13 +4499,13 @@
             high = y[min:]
         else:
             min = len(x)
-        low = [x[i] + y[i] for i from 0 <= i < min]
+        cdef list low = [x[i] + y[i] for i from 0 <= i < min]
         if len(x) == len(y):
-            res = self._parent(low, check=0)
-            (<Polynomial_generic_dense>res).__normalize()
+            res = self._new_c(low)
+            res.__normalize()
             return res
         else:
-            return self._parent(low + high, check=0)
+            return self._new_c(low + high)
             
     cpdef ModuleElement _iadd_(self, ModuleElement right):
         cdef Py_ssize_t check=0, i, min
@@ -4476,6 +4523,7 @@
         return self
 
     cpdef ModuleElement _sub_(self, ModuleElement right):
+        cdef Polynomial_generic_dense res
         cdef Py_ssize_t check=0, i, min
         x = (<Polynomial_generic_dense>self).__coeffs
         y = (<Polynomial_generic_dense>right).__coeffs
@@ -4489,11 +4537,11 @@
             min = len(x)
         low = [x[i] - y[i] for i from 0 <= i < min]
         if len(x) == len(y):
-            res = self._parent(low, check=0)
-            (<Polynomial_generic_dense>res).__normalize()
+            res = self._new_c(low)
+            res.__normalize()
             return res
         else:
-            return self._parent(low + high, check=0)
+            return self._new_c(low + high)
         
     cpdef ModuleElement _isub_(self, ModuleElement right):
         cdef Py_ssize_t check=0, i, min
@@ -4516,9 +4564,9 @@
         if c._parent is not (<Element>self.__coeffs[0])._parent:
             c = (<Element>self.__coeffs[0])._parent._coerce_c(c)
         v = [c * a for a in self.__coeffs]
-        res = self._parent(v, check=0)
+        cdef Polynomial_generic_dense res = self._new_c(v)
         if not v[len(v)-1]:
-            (<Polynomial_generic_dense>res).__normalize()
+            res.__normalize()
         return res
         
     cpdef ModuleElement _lmul_(self, RingElement c):
@@ -4527,9 +4575,9 @@
         if c._parent is not (<Element>self.__coeffs[0])._parent:
             c = (<Element>self.__coeffs[0])._parent._coerce_c(c)
         v = [a * c for a in self.__coeffs]
-        res = self._parent(v, check=0)
+        cdef Polynomial_generic_dense res = self._new_c(v)
         if not v[len(v)-1]:
-            (<Polynomial_generic_dense>res).__normalize()
+            res.__normalize()
         return res
         
     cpdef ModuleElement _ilmul_(self, RingElement c):
@@ -4544,6 +4592,25 @@
             self.__normalize()
         return self
         
+    cpdef constant_coefficient(self):
+        """
+        Return the constant coefficient of this polynomial.
+
+        OUTPUT:
+            elemenet of base ring
+
+        EXAMPLES:
+            sage: R.<t> = QQ[]
+            sage: S.<x> = R[]
+            sage: f = x*t + x + t
+            sage: f.constant_coefficient()
+            t
+        """
+        if len(self.__coeffs) == 0:
+            return self.base_ring()(0)
+        else:
+            return self.__coeffs[0]
+
     def list(self, copy=True):
         """
         Return a new copy of the list of the underlying
@@ -4597,12 +4664,12 @@
         if n > 0:
             output = [self.base_ring()(0)] * n
             output.extend(self.__coeffs)
-            return self._parent(output, check=False)
+            return self._new_c(output)
         if n < 0:
             if n > len(self.__coeffs) - 1:
                 return self._parent([])
             else:
-                return self._parent(self.__coeffs[-int(n):], check=False)
+                return self._new_c(self.__coeffs[-int(n):])
     
     cpdef Polynomial truncate(self, long n):
         r"""
@@ -4628,7 +4695,7 @@
         if n < len(self.__coeffs):
             while n > 0 and not self.__coeffs[n-1]:
                 n -= 1
-        return <Polynomial>self._parent(self.__coeffs[:n], check=False)
+        return self._new_c(self.__coeffs[:n])
 
     cdef _inplace_truncate(self, long n):
         if n < len(self.__coeffs):
@@ -4640,3 +4707,104 @@
         
 def make_generic_polynomial(parent, coeffs):
     return parent(coeffs)
+
+
+cdef class ConstantPolynomialSection(Map):
+    """
+    This class is used for conversion from a polynomial ring to its basering. 
+    
+    It calls the constant_coefficient method, which can be optimized for
+    a particular polynomial type. 
+    """
+    cpdef Element _call_(self, x):
+        """
+        TESTS:
+            sage: from sage.rings.polynomial.polynomial_element import ConstantPolynomialSection
+            sage: R.<x> = QQ[]
+            sage: m = ConstantPolynomialSection(R, QQ); m
+            Generic map:
+              From: Univariate Polynomial Ring in x over Rational Field
+              To:   Rational Field
+            sage: m(x-x+1/2) # implicit
+            1/2
+            sage: m(x-x)
+            0
+            sage: m(x)
+            Traceback (most recent call last):
+            ...
+            TypeError: not a constant polynomial
+        """
+        if x.degree() <= 0:
+            return <Element>((<Polynomial>x).constant_coefficient())
+        else:
+            raise TypeError, "not a constant polynomial"
+
+cdef class PolynomialBaseringInjection(Morphism):
+    """
+    This class is used for conversion from a ring to a polynomial 
+    over that ring. 
+    
+    It calls the _new_constant_poly method on the generator, 
+    which should be optimized for a particular polynomial type. 
+    Technically, it should be a method of the polynomial ring, but 
+    few polynomial rings are cython classes. 
+    """
+    
+    cdef Polynomial _an_element
+    
+    def __init__(self, domain, codomain):
+        """
+        TESTS:
+            sage: from sage.rings.polynomial.polynomial_element import PolynomialBaseringInjection
+            sage: PolynomialBaseringInjection(QQ, QQ['x'])
+            Polynomial base injection morphism:
+              From: Rational Field
+              To:   Univariate Polynomial Ring in x over Rational Field
+            sage: PolynomialBaseringInjection(ZZ, QQ['x'])
+            Traceback (most recent call last):
+            ...
+            AssertionError: domain must be basering
+        """
+        assert domain is codomain.base_ring(), "domain must be basering"
+        Morphism.__init__(self, domain, codomain)
+        self._an_element = codomain.gen()
+        self._repr_type_str = "Polynomial base injection"
+    
+    cpdef Element _call_(self, x):
+        """
+        TESTS:
+            sage: from sage.rings.polynomial.polynomial_element import PolynomialBaseringInjection
+            sage: m = PolynomialBaseringInjection(ZZ, ZZ['x']); m
+            Polynomial base injection morphism:
+              From: Integer Ring
+              To:   Univariate Polynomial Ring in x over Integer Ring
+            sage: m(2) # implicit doctest
+            2
+            sage: parent(m(2))
+            Univariate Polynomial Ring in x over Integer Ring
+        """
+        return self._an_element._new_constant_poly(<Element>x)
+    
+    cpdef Element _call_with_args(self, x, args=(), kwds={}):
+        """
+        TESTS:
+            sage: from sage.rings.polynomial.polynomial_element import PolynomialBaseringInjection
+            sage: m = PolynomialBaseringInjection(Qp(5), Qp(5)['x'])
+            sage: m(1 + O(5^11), absprec = 5)
+            (1 + O(5^11))
+        """
+        return self._codomain._element_constructor(x, *args, **kwds)
+
+    def section(self):
+        """
+        TESTS:
+            sage: from sage.rings.polynomial.polynomial_element import PolynomialBaseringInjection
+            sage: m = PolynomialBaseringInjection(RDF, RDF['x'])
+            sage: m.section()
+            Generic map:
+              From: Univariate Polynomial Ring in x over Real Double Field
+              To:   Real Double Field
+            sage: type(m.section())
+            <type 'sage.rings.polynomial.polynomial_element.ConstantPolynomialSection'>
+        """
+        return ConstantPolynomialSection(self._codomain, self._domain)
diff --git a/sage/rings/polynomial/polynomial_ring.py b/sage/rings/polynomial/polynomial_ring.py
--- a/sage/rings/polynomial/polynomial_ring.py
+++ b/sage/rings/polynomial/polynomial_ring.py
@@ -106,6 +106,8 @@
 from sage.rings.polynomial.polynomial_singular_interface import PolynomialRing_singular_repr
 from sage.rings.fraction_field_element import FractionFieldElement
 
+from polynomial_element import PolynomialBaseringInjection
+
 import cyclotomic
 
 ZZ_sage = IntegerRing()
@@ -177,6 +179,11 @@
         self.__generator = self._polynomial_class(self, [0,1], is_gen=True)
         self.__cyclopoly_cache = {}
         self._has_singular = False
+        self._populate_coercion_lists_(
+                coerce_list = [PolynomialBaseringInjection(base_ring, self)],
+                convert_list = [list],
+                convert_method_name = '_polynomial_')
+ 
 
     def __reduce__(self):
         import sage.rings.polynomial.polynomial_ring_constructor
@@ -184,7 +191,7 @@
                 (self.base_ring(), self.variable_name(), None, self.is_sparse()))
             
         
-    def __call__(self, x=None, check=True, is_gen = False, construct=False, absprec = None):
+    def _element_constructor_(self, x=None, check=True, is_gen = False, construct=False, absprec = None):
         r"""
         Coerce \code{x} into this univariate polynomial ring, possibly non-canonically.
         
@@ -327,29 +334,51 @@
         else:
             raise TypeError, "Cannot complete %s with respect to %s" % (self, p)
             
-    def _coerce_impl(self, x):
+    def _coerce_map_from_(self, P):
         """
-        Return the canonical coercion of x to this polynomial ring, if one is
-        defined, or raise a TypeError.
-
         The rings that canonically coerce to this polynomial ring are:
             * this ring itself
             * any ring that canonically coerces to the base ring of this ring.
             * polynomial rings in the same variable over any base ring that
               canonically coerces to the base ring of this ring
+        
+        EXAMPLES: 
+            sage: R = QQ['x']
+            sage: R.has_coerce_map_from(QQ)
+            True
+            sage: R.has_coerce_map_from(ZZ)
+            True
+            sage: R.has_coerce_map_from(GF(7))
+            False
+            sage: R.has_coerce_map_from(ZZ['x'])
+            True
+            sage: R.has_coerce_map_from(ZZ['y'])
+            False
+            
+            sage: R.coerce_map_from(ZZ)
+            Composite map:
+              From: Integer Ring
+              To:   Univariate Polynomial Ring in x over Rational Field
+              Defn:   Natural morphism:
+                      From: Integer Ring
+                      To:   Rational Field
+                    then
+                      Polynomial base injection morphism:
+                      From: Rational Field
+                      To:   Univariate Polynomial Ring in x over Rational Field
         """
         # handle constants that canonically coerce into self.base_ring()
         # first, if possible
         try:
-            y = self.base_ring()._coerce_(x)
-            return self([y])
+            connecting = self.base_ring().coerce_map_from(P)
+            if connecting is not None:
+                return self.coerce_map_from(self.base_ring()) * connecting
         except TypeError:
             pass
 
         # polynomial rings in the same variable over a base that canonically
         # coerces into self.base_ring()
         try:
-            P = x.parent()
             if is_PolynomialRing(P):
                 if P.variable_name() == self.variable_name():
                     if P.base_ring() is self.base_ring() and \
@@ -365,14 +394,10 @@
                         # coercion model, at which point this code will
                         # become useful.
                         if self._implementation_names == ('NTL',):
-                            raise TypeError, "no canonical coercion from FLINT to NTL polynomials"
-                    if self.has_coerce_map_from(P.base_ring()):
-                        return self(x)
-                    else:
-                        raise TypeError, "no natural map between bases of polynomial rings"
+                            return False
+                    return self.base_ring().has_coerce_map_from(P.base_ring())
         except AttributeError:
             pass
-        raise TypeError
 
     def _magma_init_(self, magma):
         """
@@ -478,7 +503,7 @@
             # of the polynomial ring canonically coerce into codomain.
             # Since poly rings are free, any image of the gen
             # determines a homomorphism
-            codomain._coerce_(self.base_ring()(1))
+            codomain.coerce(self.base_ring()(1))
         except TypeError:
             return False
         return True
diff --git a/sage/structure/coerce.pyx b/sage/structure/coerce.pyx
--- a/sage/structure/coerce.pyx
+++ b/sage/structure/coerce.pyx
@@ -379,11 +379,11 @@
 
             sage: cm.explain(ZZ['x'], QQ, operator.add)
             Coercion on left operand via
-                Call morphism:
+                Conversion map:
                   From: Univariate Polynomial Ring in x over Integer Ring
                   To:   Univariate Polynomial Ring in x over Rational Field
             Coercion on right operand via
-                Call morphism:
+                Polynomial base injection morphism:
                   From: Rational Field
                   To:   Univariate Polynomial Ring in x over Rational Field
             Arithmetic performed after coercions.
@@ -414,7 +414,7 @@
 
             sage: cm.explain(ZZ['x'], QQ['x'], operator.div)
             Coercion on left operand via
-                Call morphism:
+                Conversion map:
                   From: Univariate Polynomial Ring in x over Integer Ring
                   To:   Univariate Polynomial Ring in x over Rational Field
             Arithmetic performed after coercions.
@@ -842,11 +842,11 @@
             
             sage: f, g = cm.coercion_maps(ZZ['x'], QQ)
             sage: print f
-            Call morphism:
+            Conversion map:
               From: Univariate Polynomial Ring in x over Integer Ring
               To:   Univariate Polynomial Ring in x over Rational Field
             sage: print g
-            Call morphism:
+            Polynomial base injection morphism:
               From: Rational Field
               To:   Univariate Polynomial Ring in x over Rational Field
               
diff --git a/sage/structure/coerce_maps.pyx b/sage/structure/coerce_maps.pyx
--- a/sage/structure/coerce_maps.pyx
+++ b/sage/structure/coerce_maps.pyx
@@ -154,6 +154,16 @@
                 raise TypeError 
             e = m._call_(e)
         return e
+
+    cpdef Element _call_with_args(self, x, args=(), kwds={}):
+        """
+        EXAMPLES: 
+            sage: from sage.structure.coerce_maps import NamedConvertMap
+            sage: f = NamedConvertMap(SR, ZZ['x'], '_polynomial_')
+            sage: f(x^2+1, check=True)
+            x^2 + 1
+        """
+        return self._codomain._element_constructor(self._call_(x), *args, **kwds)
 
 
 # Perhaps this could be a method, extracting (<PyMethodDescrObject *>(<object>Parent).coerce_map_from).d_method.ml_meth and/or PyCFunction_GET_FUNCTION(method)
diff --git a/sage/structure/parent.pyx b/sage/structure/parent.pyx
--- a/sage/structure/parent.pyx
+++ b/sage/structure/parent.pyx
@@ -671,8 +671,10 @@
                 self._convert_from_list.append(mor)
                 self._convert_from_hash[mor.domain()] = mor
             elif PY_TYPE_CHECK(mor, Parent) or PY_TYPE_CHECK(mor, type):
+                t = mor
                 mor = self._generic_convert_map(mor)
                 self._convert_from_list.append(mor)
+                self._convert_from_hash[t] = mor
                 self._convert_from_hash[mor.domain()] = mor
             else:
                 raise TypeError, "entries in the convert_list must be parents or maps"
