Commits

Volker Braun  committed 6d20841

fixed doctest stuff

  • Participants
  • Parent commits 82a7d86

Comments (0)

Files changed (8)

+trac_14187_lazy_import_test.patch
+trac_14014_libgap_cyclotomic_matrix.patch
+trac_14014_deletions.patch
+trac_14014_parents_for_matrix_groups.patch
+trac_14014_parents_group_dependents.patch
+trac_14359_doctest_unicode_warning.patch
+trac_14359_doctest_ansi_escapes.patch
+trac_14357_lazy_everywhere.patch
 trac_14291.patch
 14291_reviewer.patch
 trac_14291-rev2.patch
 trac_3416_jacobians.patch
 trac_3416_fixes.patch
 trac_13826_star_imports_race.patch
-trac_14187_lazy_import_test.patch
-trac_14187_lazy_everywhere.patch
-trac_14014_libgap_cyclotomic_matrix.patch
-trac_14014_deletions.patch
-trac_14014_parents_for_matrix_groups.patch
-trac_14014_parents_group_dependents.patch
 trac_14201_ppl_doctest_fixes.patch
 trac_14015_affine_group.patch
 trac_x_matrix_groups.patch

File trac_14014_parents_for_matrix_groups.patch

 # HG changeset patch
-# Parent 1eb2904572a633f09fd88ce6cbf5b7e6b8ecf380
+# Parent 17763fc8b8e6187fa727e4893ffb61d9738504c3
 
 Update matrix groups to new parents and LibGAP.
 
 new file mode 100644
 --- /dev/null
 +++ b/sage/groups/matrix_gps/morphism.py
-@@ -0,0 +1,328 @@
+@@ -0,0 +1,342 @@
 +"""
 +Homomorphisms Between Matrix Groups
 +
 +            [1 0 0 0 0 0], [-1  0  0  0  0  0]
 +            ]
 +            sage: f(O)  # long time
-+            Matrix group over Rational Field with 6 generators: 
-+             [[[1, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]], [[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]], [[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 1]], [[0, 0, 0, 0, -1, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [-1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1]], [[0, 0, 0, 0, 0, 1], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [1, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 0, -1], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [-1, 0, 0, 0, 0, 0]]]
-+
++            Matrix group over Rational Field with 6 generators
++            sage: f(O).gens()   # long time
++            (
++            [1 0 0 0 0 0]  [1 0 0 0 0 0]  [1 0 0 0 0 0]  [ 0  0  0  0 -1  0]
++            [0 0 1 0 0 0]  [0 1 0 0 0 0]  [0 1 0 0 0 0]  [ 0  1  0  0  0  0]
++            [0 1 0 0 0 0]  [0 0 0 1 0 0]  [0 0 1 0 0 0]  [ 0  0  1  0  0  0]
++            [0 0 0 1 0 0]  [0 0 1 0 0 0]  [0 0 0 0 1 0]  [ 0  0  0  1  0  0]
++            [0 0 0 0 1 0]  [0 0 0 0 1 0]  [0 0 0 1 0 0]  [-1  0  0  0  0  0]
++            [0 0 0 0 0 1], [0 0 0 0 0 1], [0 0 0 0 0 1], [ 0  0  0  0  0  1],
++            <BLANKLINE>
++            [0 0 0 0 0 1]  [ 0  0  0  0  0 -1]
++            [0 1 0 0 0 0]  [ 0  1  0  0  0  0]
++            [0 0 1 0 0 0]  [ 0  0  1  0  0  0]
++            [0 0 0 1 0 0]  [ 0  0  0  1  0  0]
++            [0 0 0 0 1 0]  [ 0  0  0  0  1  0]
++            [1 0 0 0 0 0], [-1  0  0  0  0  0]
++            )
 +        """
 +        phi = self.gap()
 +        G = self.domain()
 diff --git a/sage/groups/matrix_gps/orthogonal.py b/sage/groups/matrix_gps/orthogonal.py
 --- a/sage/groups/matrix_gps/orthogonal.py
 +++ b/sage/groups/matrix_gps/orthogonal.py
-@@ -1,33 +1,51 @@
+@@ -1,33 +1,61 @@
  r"""
  Orthogonal Linear Groups
  
 -value of `e` must be `0` for odd `d` (and
 -can optionally be omitted in this case), respectively one of
 -`1` or `-1` for even `d`.
-+The general orthogonal group `GO(n,R)` consists of all orthogonal
-+`n\times n` matrices over the ring `R`. The special orthogonal group
-+is the subgroup of matrices of determinant one.
++The general orthogonal group `GO(n,R)` consists of all `n\times n`
++matrices over the ring `R` preserving an `n`-ary positive definite
++quadratic form. In cases where there are muliple non-isomorphic
++quadratic forms, additional data needs to be specified to
++disambiguate. The special orthogonal group is the normal subgroup of
++matrices of determinant one.
  
 -SpecialOrthogonalGroup returns a group isomorphic to the special
 -orthogonal group `SO(e,d,q)`, which is the subgroup of all
 -determinant one. (The index of `SO(e,d,q)` in
 -`GO(e,d,q)` is `2` if `q` is odd, but
 -`SO(e,d,q) = GO(e,d,q)` if `q` is even.)
++In characteristics different from 2, a quadratic form is equivalent to
++a bilinear symmetric form. Furthermore, over the real numbers a
++positive definite quadratic form is equivalent to the diagonal
++quadratic form, equivalent to the bilinear symmetric form defined by
++the identity matrix. Hence, the orthogonal group `GO(n,\RR)` is the
++group of orthogonal matrices in the usual sense.
++
 +In the case of a finite field and if the degree `n` is even, then
 +there are two inequivalent quadratic forms and a third parameter ``e``
 +must be specified to disambiguate these two possibilities. The index
  AUTHORS:
  
  - David Joyner (2006-03): initial version
-@@ -36,300 +54,310 @@
+@@ -36,300 +64,388 @@
    as_matrix_group
  
  - William Stein (2006-12-09): rewrite
 +    - ``degree`` -- integer. The degree of the affine group, that is,
 +      the dimension of the affine space the group is acting on.
      
--    INPUT:
--    
--    
++    - ``ring`` -- a ring. The base ring of the affine space.
++
++    - ``e`` -- integer, one of `+1`, `0`, `-1`.  Only relevant for
++      finite fields and if the degree is even. A parameter that
++      distinguishes inequivalent invariant forms.
++
++    OUTPUT:
++
++    The integer ``e`` with values required by GAP.
++
++    TESTS::
++
++        sage: from sage.groups.matrix_gps.orthogonal import normalize_args_e
++        sage: normalize_args_e(2, GF(3), +1)
++        1
++        sage: normalize_args_e(3, GF(3), 0)
++        0
++        sage: normalize_args_e(3, GF(3), +1)
++        0
++        sage: normalize_args_e(2, GF(3), 0)
++        Traceback (most recent call last):
++        ...
++        ValueError: must have e=-1 or e=1 for even degree
++    """
++    if is_FiniteField(ring) and degree%2 == 0:
++        if e not in (-1, +1):
++            raise ValueError('must have e=-1 or e=1 for even degree')
++    else:
++        e = 0
++    return ZZ(e)
++
++
++
++
++
++########################################################################
++# General Orthogonal Group
++########################################################################
++    
++def GO(n, R, e=0, var='a'):
++    """
++    Return the general orthogonal group.
++    
++    The general orthogonal group `GO(n,R)` consists of all `n\times n`
++    matrices over the ring `R` preserving an `n`-ary positive definite
++    quadratic form. In cases where there are muliple non-isomorphic
++    quadratic forms, additional data needs to be specified to
++    disambiguate.
++
++    In the case of a finite field and if the degree `n` is even, then
++    there are two inequivalent quadratic forms and a third parameter
++    ``e`` must be specified to disambiguate these two possibilities.
++
++    .. note::
++
++        This group is also available via ``groups.matrix.GO()``.
++
++   INPUT:
++    
++    - ``n`` -- integer. The degree.
++    
++    - ``R`` -- ring or an integer. If an integer is specified, the
++      corresponding finite field is used.
++    
++    - ``e`` -- ``+1`` or ``-1``, and ignored by default. Only relevant
++      for finite fields and if the degree is even. A parameter that
++      distinguishes inequivalent invariant forms.
++    
++    OUTPUT:
++    
++    The general orthogonal group of given degree, base ring, and
++    choice of invariant form.
++
++    EXAMPLES:
++
++        sage: GO( 3, GF(7))
++        General Orthogonal Group of degree 3 over Finite Field of size 7
++        sage: GO( 3, GF(7)).order()
++        672
++        sage: GO( 3, GF(7)).gens()
++        (
++        [3 0 0]  [0 1 0]
++        [0 5 0]  [1 6 6]
++        [0 0 1], [0 2 1]
++        )
++
++    TESTS::
++
++        sage: groups.matrix.GO(2, 3, e=-1)
++        General Orthogonal Group of degree 2 and form parameter -1 over Finite Field of size 3
++    """
++    degree, ring = normalize_args_vectorspace(n, R, var=var)
++    e = normalize_args_e(degree, ring, e)
++    if e == 0:
++        name = 'General Orthogonal Group of degree {0} over {1}'.format(degree, ring)
++        ltx  = r'\text{{GO}}_{{{0}}}({1})'.format(degree, latex(ring))
++    else:
++        name = 'General Orthogonal Group of degree' + \
++            ' {0} and form parameter {1} over {2}'.format(degree, e, ring)
++        ltx  = r'\text{{GO}}_{{{0}}}({1}, {2})'.format(degree, latex(ring), '+' if e == 1 else '-')
++    if is_FiniteField(ring):
++        cmd  = 'GO({0}, {1}, {2})'.format(e, degree, ring.characteristic())
++        return OrthogonalMatrixGroup_gap(degree, ring, False, name, ltx, cmd)
++    else:
++        return OrthogonalMatrixGroup_generic(degree, ring, False, name, ltx)
++
++
++
++########################################################################
++# Special Orthogonal Group
++########################################################################
++
++def SO(n, R, e=None, var='a'):
++    """
++    Return the special orthogonal group.
++    
++    The special orthogonal group `GO(n,R)` consists of all `n\times n`
++    matrices with determint one over the ring `R` preserving an
++    `n`-ary positive definite quadratic form. In cases where there are
++    muliple non-isomorphic quadratic forms, additional data needs to
++    be specified to disambiguate.
++
++    .. note::
++
++        This group is also available via ``groups.matrix.SO()``.
++
+     INPUT:
+     
++    - ``n`` -- integer. The degree.
+     
 -    -  ``n`` - the degree
--    
++    - ``R`` -- ring or an integer. If an integer is specified, the
++      corresponding finite field is used.
+     
 -    -  ``R`` - ring
--    
++    - ``e`` -- ``+1`` or ``-1``, and ignored by default. Only relevant
++      for finite fields and if the degree is even. A parameter that
++      distinguishes inequivalent invariant forms.
+     
 -    -  ``e`` - a parameter for orthogonal groups only
 -       depending on the invariant form
--    
++    OUTPUT:
+     
 -    
 -    .. note::
 -        This group is also available via ``groups.matrix.SO()``.
-+    - ``ring`` -- a ring. The base ring of the affine space.
- 
--    EXAMPLES::
--    
--        sage: G = SO(3,GF(5))
--        sage: G.gens()
++    The special orthogonal group of given degree, base ring, and choice of
++    invariant form.
+ 
+     EXAMPLES::
++
++        sage: G = SO(3,GF(5))
++        sage: G
++        Special Orthogonal Group of degree 3 over Finite Field of size 5
+     
+         sage: G = SO(3,GF(5))
+         sage: G.gens()
 -        [
 -        [2 0 0]
 -        [0 3 0]
 -        [4 0 0]
 -        [2 0 4]
 -        ]       
--        sage: G = SO(3,GF(5))
--        sage: G.as_matrix_group()
++        (
++        [2 0 0]  [3 2 3]  [1 4 4]
++        [0 3 0]  [0 2 0]  [4 0 0]
++        [0 0 1], [0 3 1], [2 0 4]
++        )
+         sage: G = SO(3,GF(5))
+         sage: G.as_matrix_group()
 -        Matrix group over Finite Field of size 5 with 3 generators:
 -        [[[2, 0, 0], [0, 3, 0], [0, 0, 1]], [[3, 2, 3], [0, 2, 0], [0, 3, 1]], [[1, 4, 4], [4, 0, 0], [2, 0, 4]]]
-+    - ``e`` -- integer, one of `+1`, `0`, `-1`.  Only relevant for
-+      finite fields and if the degree is even. A parameter that
-+      distinguishes inequivalent invariant forms.
-+
-+    OUTPUT:
-+
-+    The integer ``e`` with values required by GAP.
++        Matrix group over Finite Field of size 5 with 3 generators (
++        [2 0 0]  [3 2 3]  [1 4 4]
++        [0 3 0]  [0 2 0]  [4 0 0]
++        [0 0 1], [0 3 1], [2 0 4]
++        )
  
      TESTS::
  
--        sage: groups.matrix.SO(2, 3, e=1)
+         sage: groups.matrix.SO(2, 3, e=1)
 -        Special Orthogonal Group of degree 2, form parameter 1, over the Finite Field of size 3
-+        sage: from sage.groups.matrix_gps.orthogonal import normalize_args_e
-+        sage: normalize_args_e(2, GF(3), +1)
-+        1
-+        sage: normalize_args_e(3, GF(3), 0)
-+        0
-+        sage: normalize_args_e(3, GF(3), +1)
-+        0
-+        sage: normalize_args_e(2, GF(3), 0)
-+        Traceback (most recent call last):
-+        ...
-+        ValueError: must have e=-1 or e=1 for even degree
++        Special Orthogonal Group of degree 2 and form parameter 1 over Finite Field of size 3
      """
 -    if isinstance(R, (int, long, Integer)):
 -        R = FiniteField(R, var)
 -            raise ValueError, "must have e=-1 or e=1 if n is even"
 -    if is_FiniteField(R):
 -        return SpecialOrthogonalGroup_finite_field(n, R, e)
-+    if is_FiniteField(ring) and degree%2 == 0:
-+        if e not in (-1, +1):
-+            raise ValueError('must have e=-1 or e=1 for even degree')
++    degree, ring = normalize_args_vectorspace(n, R, var=var)
++    e = normalize_args_e(degree, ring, e)
++    if e == 0:
++        name = 'Special Orthogonal Group of degree {0} over {1}'.format(degree, ring)
++        ltx  = r'\text{{SO}}_{{{0}}}({1})'.format(degree, latex(ring))
      else:
 -        return SpecialOrthogonalGroup_generic(n, R, e)
-+        e = 0
-+    return ZZ(e)
++        name = 'Special Orthogonal Group of degree' + \
++            ' {0} and form parameter {1} over {2}'.format(degree, e, ring)
++        ltx  = r'\text{{SO}}_{{{0}}}({1}, {2})'.format(degree, latex(ring), '+' if e == 1 else '-')
++    if is_FiniteField(ring):
++        cmd  = 'SO({0}, {1}, {2})'.format(e, degree, ring.characteristic())
++        return OrthogonalMatrixGroup_gap(degree, ring, True, name, ltx, cmd)
++    else:
++        return OrthogonalMatrixGroup_generic(degree, ring, True, name, ltx)
  
 -class OrthogonalGroup(MatrixGroup_gap):
 -    def __init__(self, n, R, e=0, var='a'):
--        """
++
++
++########################################################################
++# Orthogonal Group class
++########################################################################
++
++class OrthogonalMatrixGroup_generic(NamedMatrixGroup_generic):
++
++    @cached_method
++    def invariant_bilinear_form(self):
+         """
 -        INPUT:
--        
--        
++        Return the symmetric bilinear form preserved by the orthogonal
++        group.
++
++        OUTPUT:
++
++        A matrix.
++
++        EXAMPLES::
++ 
++            sage: GO(2,3,+1).invariant_bilinear_form()
++            [0 1]
++            [1 0]
++            sage: GO(2,3,-1).invariant_bilinear_form()
++            [2 1]
++            [1 1]
++        """
++        from sage.matrix.constructor import identity_matrix
++        m = identity_matrix(self.base_ring(), self.degree())
++        m.set_immutable()
++        return m
++
++    @cached_method
++    def invariant_quadratic_form(self):
++        """
++        Return the quadratic form preserved by the orthogonal group.
++
++        OUTPUT:
++
++        A matrix.
++
++        EXAMPLES::
++ 
++            sage: GO(2,3,+1).invariant_quadratic_form()
++            [0 1]
++            [0 0]
++            sage: GO(2,3,-1).invariant_quadratic_form()
++            [1 1]
++            [0 2]
++        """
++        from sage.matrix.constructor import identity_matrix
++        m = identity_matrix(self.base_ring(), self.degree())
++        m.set_immutable()
++        return m
++
++    def _check_matrix(self, x, *args):
++        """a
++        Check whether the matrix ``x`` is symplectic.
++
++        See :meth:`~sage.groups.matrix_gps.matrix_group._check_matrix`
++        for details.
++
++        EXAMPLES::
++
++            sage: G = GO(4, GF(5), +1)
++            sage: G._check_matrix(G.an_element().matrix())
++        """
++        if self._special and x.determinant() != 1:
++            raise TypeError('matrix must have determinant one')
++        F = self.invariant_bilinear_form()
++        if x * F * x.transpose() != F:
++            raise TypeError('matrix must be orthogonal with respect to the invariant form')
++        # TODO: check that quadratic form is preserved in characteristic two
++
++
++class OrthogonalMatrixGroup_gap(OrthogonalMatrixGroup_generic, NamedMatrixGroup_gap):
++    
++    @cached_method
++    def invariant_bilinear_form(self):
++        """
++        Return the symmetric bilinear form preserved by the orthogonal
++        group.
++
++        OUTPUT:
+         
++        A matrix `M` such that, for every group element g, the
++        identity `g m g^T = m` holds. In characteristic different from
++        two, this uniquely determines the orthogonal group.
++
++        EXAMPLES::
+         
 -        -  ``n`` - the degree
--        
++            sage: G = GO(4, GF(7), -1)
++            sage: G.invariant_bilinear_form()
++            [0 1 0 0]
++            [1 0 0 0]
++            [0 0 2 0]
++            [0 0 0 2]
++
++            sage: G = GO(4, GF(7), +1)
++            sage: G.invariant_bilinear_form()
++            [0 1 0 0]
++            [1 0 0 0]
++            [0 0 6 0]
++            [0 0 0 2]
++
++            sage: G = GO(4, QQ)
++            sage: G.invariant_bilinear_form()
++            [1 0 0 0]
++            [0 1 0 0]
++            [0 0 1 0]
++            [0 0 0 1]
++
++            sage: G = SO(4, GF(7), -1)
++            sage: G.invariant_bilinear_form()
++            [0 1 0 0]
++            [1 0 0 0]
++            [0 0 2 0]
++            [0 0 0 2]
++        """
++        m = self.gap().InvariantBilinearForm()['matrix'].matrix()
++        m.set_immutable()
++        return m
++
++    @cached_method
++    def invariant_quadratic_form(self):
++        """
++        Return the quadratic form preserved by the orthogonal group.
++
++        OUTPUT:
+         
 -        -  ``R`` - the base ring
 -        
 -        -  ``e`` - a parameter for orthogonal groups only
 -        """
 -        MatrixGroup_gap.__init__(self, n, R, var)
 -        self.__form = e
- 
+-
 -    def invariant_form(self):
 -        """
 -        Return the invariant form of this orthogonal group.
 -        
 -        TODO: What is the point of this? What does it do? How does it
 -        work?
--        
--        EXAMPLES::
--        
++        The matrix `Q` defining "orthogonal" as follows. The matrix
++        determines a quadratic form `q` on the natural vector space
++        `V`, on which `G` acts, by `q(v) = v Q v^t`. A matrix `M' is
++        an element of the orthogonal group if `q(v) = q(v M)` for all
++        `v \in V`.
+         
+         EXAMPLES::
+         
 -            sage: G = SO( 4, GF(7), 1)
 -            sage: G.invariant_form()
 -            1
 -        """
 -        return self.__form
++            sage: G = GO(4, GF(7), -1)
++            sage: G.invariant_quadratic_form()
++            [0 1 0 0]
++            [0 0 0 0]
++            [0 0 1 0]
++            [0 0 0 1]
  
 -class SpecialOrthogonalGroup_generic(OrthogonalGroup):
 -    """
 -        EXAMPLES::
 -        
 -            sage: G = SO( 4, GF(7), 1)
--            sage: G.invariant_quadratic_form()
--            [0 1 0 0]
--            [0 0 0 0]
--            [0 0 3 0]
--            [0 0 0 1]
++            sage: G = GO(4, GF(7), +1)
+             sage: G.invariant_quadratic_form()
+             [0 1 0 0]
+             [0 0 0 0]
+             [0 0 3 0]
+             [0 0 0 1]
 -        """
 -        F = self.base_ring()
 -        I = gap(self).InvariantQuadraticForm()
 -        Q = I.attribute('matrix')
 -        return Q._matrix_(F)
--
--
+ 
++            sage: G = GO(4, QQ)
++            sage: G.invariant_quadratic_form()
++            [1 0 0 0]
++            [0 1 0 0]
++            [0 0 1 0]
++            [0 0 0 1]
+ 
 -class SpecialOrthogonalGroup_finite_field(SpecialOrthogonalGroup_generic, MatrixGroup_gap_finite_field):
 -    pass
- 
- 
- ########################################################################
- # General Orthogonal Group
- ########################################################################
-     
+-
+-
+-########################################################################
+-# General Orthogonal Group
+-########################################################################
+-    
 -def GO( n , R , e=0 ):
-+def GO(n, R, e=0, var='a'):
-     """
-     Return the general orthogonal group.
-     
-+    The general orthogonal group `GO(n,R)` consists of all orthogonal
-+    `n\times n` matrices over the ring `R`. 
-+
-+    In the case of a finite field and if the degree `n` is even, then
-+    there are two inequivalent quadratic forms and a third parameter
-+    ``e`` must be specified to disambiguate these two possibilities.
-+
-     .. note::
-+
-         This group is also available via ``groups.matrix.GO()``.
- 
-+   INPUT:
-+    
-+    - ``n`` -- integer. The degree.
-+    
-+    - ``R`` -- ring or an integer. If an integer is specified, the
-+      corresponding finite field is used.
-+    
-+    - ``e`` -- ``+1`` or ``-1``, and ignored by default. Only relevant
-+      for finite fields and if the degree is even. A parameter that
-+      distinguishes inequivalent invariant forms.
-+    
-+    OUTPUT:
-+    
-+    The general orthogonal group of given degree, base ring, and
-+    choice of invariant form.
-+
-     EXAMPLES:
+-    """
+-    Return the general orthogonal group.
 -    
-+
-+        sage: GO( 3, GF(7))
-+        General Orthogonal Group of degree 3 over Finite Field of size 7
-+        sage: GO( 3, GF(7)).order()
-+        672
-+        sage: GO( 3, GF(7)).gens()
-+        (
-+        [3 0 0]  [0 1 0]
-+        [0 5 0]  [1 6 6]
-+        [0 0 1], [0 2 1]
-+        )
-+
-     TESTS::
- 
-         sage: groups.matrix.GO(2, 3, e=-1)
+-    .. note::
+-        This group is also available via ``groups.matrix.GO()``.
+-
+-    EXAMPLES:
+-    
+-    TESTS::
+-
+-        sage: groups.matrix.GO(2, 3, e=-1)
 -        General Orthogonal Group of degree 2, form parameter -1, over the Finite Field of size 3
-+        General Orthogonal Group of degree 2 and form parameter -1 over Finite Field of size 3
-     """
+-    """
 -    if n%2!=0 and e!=0:
 -        raise ValueError, "if e = 0, then n must be even."
 -    if n%2 == 0 and e**2!=1:
 -        R = FiniteField(R)
 -    if is_FiniteField(R):
 -        return GeneralOrthogonalGroup_finite_field(n, R, e)
-+    degree, ring = normalize_args_vectorspace(n, R, var=var)
-+    e = normalize_args_e(degree, ring, e)
-+    if e == 0:
-+        name = 'General Orthogonal Group of degree {0} over {1}'.format(degree, ring)
-+        ltx  = r'\text{{GO}}_{{{0}}}({1})'.format(degree, latex(ring))
-     else:
+-    else:
 -        return GeneralOrthogonalGroup_generic(n, R, e)
-+        name = 'General Orthogonal Group of degree' + \
-+            ' {0} and form parameter {1} over {2}'.format(degree, e, ring)
-+        ltx  = r'\text{{GO}}_{{{0}}}({1}, {2})'.format(degree, latex(ring), '+' if e == 1 else '-')
-+    if is_FiniteField(ring):
-+        cmd  = 'GO({0}, {1}, {2})'.format(e, degree, ring.characteristic())
-+        return OrthogonalMatrixGroup_gap(degree, ring, False, name, ltx, cmd)
-+    else:
-+        return OrthogonalMatrixGroup_generic(degree, ring, False, name, ltx)
- 
+-
 -class GeneralOrthogonalGroup_generic(OrthogonalGroup):
-+
-+
-+########################################################################
-+# Special Orthogonal Group
-+########################################################################
-+
-+def SO(n, R, e=None, var='a'):
-     """
-+    Return the special orthogonal group.
-+    
-+    The special orthogonal group `SO(n,R)` consists of all orthogonal
-+    `n\times n` matrices over the ring `R` with determinant one.
-+
-+    .. note::
-+
-+        This group is also available via ``groups.matrix.SO()``.
-+
-+    INPUT:
-+    
-+    - ``n`` -- integer. The degree.
-+    
-+    - ``R`` -- ring or an integer. If an integer is specified, the
-+      corresponding finite field is used.
-+    
-+    - ``e`` -- ``+1`` or ``-1``, and ignored by default. Only relevant
-+      for finite fields and if the degree is even. A parameter that
-+      distinguishes inequivalent invariant forms.
-+    
-+    OUTPUT:
-+    
-+    The special orthogonal group of given degree, base ring, and choice of
-+    invariant form.
-+
-     EXAMPLES::
-+
-+        sage: G = SO(3,GF(5))
-+        sage: G
-+        Special Orthogonal Group of degree 3 over Finite Field of size 5
-     
+-    """
+-    EXAMPLES::
+-    
 -        sage: GO( 3, GF(7), 0)
 -        General Orthogonal Group of degree 3, form parameter 0, over the Finite Field of size 7
 -        sage: GO( 3, GF(7), 0).order()
 -        [1 0 0]
 -        [6 1 6]
 -        [5 0 6]
-+        sage: G = SO(3,GF(5))
-+        sage: G.gens()
-+        (
-+        [2 0 0]  [3 2 3]  [1 4 4]
-+        [0 3 0]  [0 2 0]  [4 0 0]
-+        [0 0 1], [0 3 1], [2 0 4]
-+        )
-+        sage: G = SO(3,GF(5))
-+        sage: G.as_matrix_group()
-+        Matrix group over Finite Field of size 5 with 3 generators (
-+        [2 0 0]  [3 2 3]  [1 4 4]
-+        [0 3 0]  [0 2 0]  [4 0 0]
-+        [0 0 1], [0 3 1], [2 0 4]
-+        )
-+
-+    TESTS::
-+
-+        sage: groups.matrix.SO(2, 3, e=1)
-+        Special Orthogonal Group of degree 2 and form parameter 1 over Finite Field of size 3
-     """
+-    """
 -    def _gap_init_(self):
-+    degree, ring = normalize_args_vectorspace(n, R, var=var)
-+    e = normalize_args_e(degree, ring, e)
-+    if e == 0:
-+        name = 'Special Orthogonal Group of degree {0} over {1}'.format(degree, ring)
-+        ltx  = r'\text{{SO}}_{{{0}}}({1})'.format(degree, latex(ring))
-+    else:
-+        name = 'Special Orthogonal Group of degree' + \
-+            ' {0} and form parameter {1} over {2}'.format(degree, e, ring)
-+        ltx  = r'\text{{SO}}_{{{0}}}({1}, {2})'.format(degree, latex(ring), '+' if e == 1 else '-')
-+    if is_FiniteField(ring):
-+        cmd  = 'SO({0}, {1}, {2})'.format(e, degree, ring.characteristic())
-+        return OrthogonalMatrixGroup_gap(degree, ring, True, name, ltx, cmd)
-+    else:
-+        return OrthogonalMatrixGroup_generic(degree, ring, True, name, ltx)
-+
-+
-+
-+########################################################################
-+# Orthogonal Group class
-+########################################################################
-+
-+class OrthogonalMatrixGroup_generic(NamedMatrixGroup_generic):
-+
-+    @cached_method
-+    def invariant_form(self):
-         """
-+        Return the quadratic form preserved by the orthogonal group.
-+
-+        OUTPUT:
-+
-+        A matrix.
-+
-         EXAMPLES::
-+ 
-+            sage: GO(2,3,+1).invariant_form()
-+            [0 1]
-+            [1 0]
-+            sage: GO(2,3,-1).invariant_form()
-+            [2 1]
-+            [1 1]
-+        """
-+        from sage.matrix.constructor import identity_matrix
-+        m = identity_matrix(self.base_ring(), self.degree())
-+        m.set_immutable()
-+        return m
-+
-+    def _check_matrix(self, x, *args):
-+        """a
-+        Check whether the matrix ``x`` is symplectic.
-+
-+        See :meth:`~sage.groups.matrix_gps.matrix_group._check_matrix`
-+        for details.
-+
-+        EXAMPLES::
-+
-+            sage: G = GO(4, GF(5), +1)
-+            sage: G._check_matrix(G.an_element().matrix())
-+        """
-+        if self._special and x.determinant() != 1:
-+            raise TypeError('matrix must have determinant one')
-+        F = self.invariant_form()
-+        if x * F * x.transpose() != F:
-+            raise TypeError('matrix must be orthogonal with respect to the invariant form')
-+
-+
-+class OrthogonalMatrixGroup_gap(OrthogonalMatrixGroup_generic, NamedMatrixGroup_gap):
-+    
-+    @cached_method
-+    def invariant_form(self):
-+        """
-+        The invariant quadratic form.
-+
-+        OUTPUT:
-         
+-        """
+-        EXAMPLES::
+-        
 -            sage: GO( 3, GF(7), 0)._gap_init_()
 -            'GO(0, 3, 7)'
 -        """
 -    def _repr_(self):
 -        """
 -        String representation of self.
-+        The matrix `Q` defining "orthogonal" as follows. The matrix
-+        determines a quadratic form `q` on the natural vector space
-+        `V` on which `G` acts by `q(v) = v Q v^t`. A matrix `M' is
-+        orthogonal if `q(v) = q(v M)` for all `v \in V`.
-         
-         EXAMPLES::
-         
+-        
+-        EXAMPLES::
+-        
 -            sage: GO(3,7)
 -            General Orthogonal Group of degree 3, form parameter 0, over the Finite Field of size 7
-+            sage: G = GO(4, GF(7), -1)
-+            sage: G.invariant_form()
-+            [0 1 0 0]
-+            [1 0 0 0]
-+            [0 0 2 0]
-+            [0 0 0 2]
-+
-+            sage: G = GO(4, GF(7), +1)
-+            sage: G.invariant_form()
-+            [0 1 0 0]
-+            [1 0 0 0]
-+            [0 0 6 0]
-+            [0 0 0 2]
-+
-+            sage: G = GO(4, QQ)
-+            sage: G.invariant_form()
-+            [1 0 0 0]
-+            [0 1 0 0]
-+            [0 0 1 0]
-+            [0 0 0 1]
-+
-+            sage: G = SO(4, GF(7), -1)
-+            sage: G.invariant_form()
-+            [0 1 0 0]
-+            [1 0 0 0]
-+            [0 0 2 0]
-+            [0 0 0 2]
-         """
+-        """
 -        return "General Orthogonal Group of degree %s, form parameter %s, over the %s"%( self.degree(), self.invariant_form(), self.base_ring())
-+        m = self.gap().InvariantBilinearForm()['matrix'].matrix()
-+        m.set_immutable()
-+        return m
- 
+-
 -    def _latex_(self):
 -        """
 -        EXAMPLES::
 -            \text{GO}_{3}(5, 0)
 -        """
 -        return "\\text{GO}_{%s}(%s, %s)"%( self.degree(), self.base_ring().order(),self.invariant_form() )
-+
-     
+-    
 -    def invariant_quadratic_form(self):
 -        """
 -        This wraps GAP's command "InvariantQuadraticForm". From the GAP
 -        EXAMPLES::
 -        
 -            sage: G = GO( 4, GF(7), 1)
--            sage: G.invariant_quadratic_form()
--            [0 1 0 0]
--            [0 0 0 0]
++            sage: G = SO(4, GF(7), -1)
+             sage: G.invariant_quadratic_form()
+             [0 1 0 0]
+             [0 0 0 0]
 -            [0 0 3 0]
--            [0 0 0 1]
--        """
++            [0 0 1 0]
+             [0 0 0 1]
+         """
 -        F = self.base_ring()
 -        G = self._gap_init_()
 -        cmd = "r := InvariantQuadraticForm("+G+")"
 -        cmd = "r.matrix"
 -        Q = gap(cmd)
 -        return Q._matrix_(F)
--
++        m = self.gap().InvariantQuadraticForm()['matrix'].matrix()
++        m.set_immutable()
++        return m
+ 
 -class GeneralOrthogonalGroup_finite_field(GeneralOrthogonalGroup_generic, MatrixGroup_gap_finite_field):
 -    pass
--    
++
+     
 diff --git a/sage/groups/matrix_gps/pickling_overrides.py b/sage/groups/matrix_gps/pickling_overrides.py
 new file mode 100644
 --- /dev/null

File trac_14014_parents_group_dependents.patch

 # HG changeset patch
-# Parent fe1342218bf2706c11e625b42134e27a6bec6017
+# Parent f15bc2bb8c0ea2a83128192774f207b10c697ed5
 
 Source files outside of sage.groups that need to be changed to match
 the new matrix groups.
              """
              return self.parent().conjugacy_class(self)
  
+diff --git a/sage/categories/groups.py b/sage/categories/groups.py
+--- a/sage/categories/groups.py
++++ b/sage/categories/groups.py
+@@ -51,7 +51,7 @@
+             General Linear Group of degree 4 over Rational Field
+         """
+         from sage.rings.rational_field import QQ
+-        from sage.groups.matrix_gps.general_linear import GL
++        from sage.groups.matrix_gps.linear import GL
+         return GL(4,QQ)
+ 
+     class ParentMethods:
 diff --git a/sage/combinat/root_system/pieri_factors.py b/sage/combinat/root_system/pieri_factors.py
 --- a/sage/combinat/root_system/pieri_factors.py
 +++ b/sage/combinat/root_system/pieri_factors.py
              sage: refdict = W.reflections(); refdict
              Finite family {s1: (1, -1), s2*s1*s2: (1, 1), s1*s2*s1: (1, 0), s2: (0, 1)}
              sage: [refdict[r]+r.action(refdict[r]) for r in refdict.keys()]
-@@ -283,7 +293,9 @@
+@@ -283,35 +293,14 @@
          ret = {}
          try:
              for alp in self.domain().positive_roots():
                  ret[r] = alp
              return Family(ret)
          except StandardError:
-@@ -297,18 +309,12 @@
-         
-             sage: G = WeylGroup(['A',3])
-             sage: G.gens()
+             raise NotImplementedError, "reflections are only implemented for finite Weyl groups"
+ 
+-    def gens(self):
+-        """
+-        Returns the generators of self, i.e. the simple reflections.
+-        
+-        EXAMPLES::
+-        
+-            sage: G = WeylGroup(['A',3])
+-            sage: G.gens()
 -            [[0 1 0 0]
 -             [1 0 0 0]
 -             [0 0 1 0]
 -             [0 1 0 0]
 -             [0 0 0 1]
 -             [0 0 1 0]]
-+            [
-+            [0 1 0 0]  [1 0 0 0]  [1 0 0 0]
-+            [1 0 0 0]  [0 0 1 0]  [0 1 0 0]
-+            [0 0 1 0]  [0 1 0 0]  [0 0 0 1]
-+            [0 0 0 1], [0 0 0 1], [0 0 1 0]
-+            ]
+-        """
+-        return list(self.simple_reflections())
+-
+     def __repr__(self):
          """
-         return list(self.simple_reflections())
- 
-@@ -327,70 +333,6 @@
+         EXAMPLES::
+@@ -327,70 +316,6 @@
                                                                                                        type=False))
  
  
      def list(self):
          """
          Returns a list of the elements of self.
-@@ -399,9 +341,10 @@
+@@ -399,9 +324,10 @@
  
              sage: G = WeylGroup(['A',1])
              sage: G.list()
  
              sage: G = WeylGroup(['A',3,1])
              sage: G.list()
-@@ -438,13 +381,15 @@
+@@ -438,13 +364,15 @@
  
      def character_table(self):
          """
              CT1
              <BLANKLINE>
                   2  3  2  2  .  3
-@@ -458,7 +403,9 @@
+@@ -458,7 +386,9 @@
              X.4     3 -1  1  . -1
              X.5     1  1  1  1  1
          """
  
      @cached_method
      def one(self):
-@@ -746,7 +693,7 @@
+@@ -746,7 +676,7 @@
          assert(not self.weyl_group(self._prefix).is_finite())
          assert(self.is_finite())
  
      """
      Class for a Weyl Group elements
      """
-@@ -758,9 +705,8 @@
+@@ -758,9 +688,8 @@
              sage: s1 = G.simple_reflection(1)
              sage: TestSuite(s1).run()
          """
          self._parent = parent
  
      def __hash__(self):
-@@ -779,12 +725,12 @@
+@@ -779,12 +708,12 @@
          """
          return self._parent.domain()
  
              sage: s0*s1
              s0*s1
              sage: W = WeylGroup(['A',2,1])
-@@ -795,7 +741,7 @@
+@@ -795,7 +724,7 @@
              [ 0  0  1]
          """
          if self._parent._prefix is None:
          else:
              redword = self.reduced_word()
              if len(redword) == 0:
-@@ -824,7 +770,7 @@
+@@ -824,7 +753,7 @@
              \end{array}\right)
          """
          if self._parent._prefix is None:
          else:
              redword = self.reduced_word()
              if len(redword) == 0:
-@@ -832,23 +778,6 @@
+@@ -832,23 +761,6 @@
              else:
                  return "".join(["%s_{%d}"%(self._parent._prefix, i) for i in redword])
  
      def __eq__(self, other):
          """
          EXAMPLES::
-@@ -886,54 +815,6 @@
+@@ -886,54 +798,6 @@
              return cmp(self._parent.cartan_type(), other._parent.cartan_type())
          return cmp(self.matrix(), other.matrix())
  
      def action(self, v):
          """
          Returns the action of self on the vector v.
+diff --git a/sage/groups/libgap_mixin.py b/sage/groups/libgap_mixin.py
+--- a/sage/groups/libgap_mixin.py
++++ b/sage/groups/libgap_mixin.py
+@@ -443,6 +443,7 @@
+         """
+         return self(self.gap().Random())
+ 
++    @cached_method
+     def list(self):
+         """
+         List all elements of this group.
+@@ -514,7 +515,7 @@
+         if not self.is_finite():
+             raise ValueError('group must be finite')
+         elements = self.gap().Elements()
+-        return tuple(self(x) for x in elements)
++        return tuple(self(x, check=False) for x in elements)
+ 
+     def is_isomorphic(self, H):
+         """
+diff --git a/sage/libs/gap/libgap.pyx b/sage/libs/gap/libgap.pyx
+--- a/sage/libs/gap/libgap.pyx
++++ b/sage/libs/gap/libgap.pyx
+@@ -454,7 +454,7 @@
+     def __init__(self):
+         r"""
+         The Python constructor.
+-        
++
+         EXAMPLES::
+ 
+             sage: type(libgap)
 diff --git a/sage/matrix/matrix2.pyx b/sage/matrix/matrix2.pyx
 --- a/sage/matrix/matrix2.pyx
 +++ b/sage/matrix/matrix2.pyx
      def __call__(self,*args,**kwds):
          """
          The purpose of this call method is to kill ``self`` and to
+diff --git a/sage/misc/dev_tools.py b/sage/misc/dev_tools.py
+--- a/sage/misc/dev_tools.py
++++ b/sage/misc/dev_tools.py
+@@ -139,8 +139,8 @@
+     In principle, the function should also work on object which are instances.
+     In case of ambiguity, one or two warning lines are printed::
+ 
+-        sage: import_statements(NN)
+-        from sage.rings.semirings.non_negative_integer_semiring import NN
++        sage: import_statements(RDF)
++        from sage.rings.real_double import RDF
+ 
+         sage: import_statements(ZZ)
+           ** Warning **: several names for that object: ZZ, Z
 diff --git a/sage/modular/arithgroup/arithgroup_perm.py b/sage/modular/arithgroup/arithgroup_perm.py
 --- a/sage/modular/arithgroup/arithgroup_perm.py
 +++ b/sage/modular/arithgroup/arithgroup_perm.py

File trac_14187_lazy_everywhere.patch

-# HG changeset patch
-# User Volker Braun <vbraun@stp.dias.ie>
-# Date 1363031056 14400
-# Node ID 8cefe2e05ac231bb402c982ff1349356d129bcb7
-# Parent  f1fdd943f9441ea88c517fa21424181b17d034b1
-Replace all lazy references to a lazy import when resolving it.
-
-diff --git a/sage/libs/gap/libgap.pyx b/sage/libs/gap/libgap.pyx
---- a/sage/libs/gap/libgap.pyx
-+++ b/sage/libs/gap/libgap.pyx
-@@ -388,8 +388,6 @@
-         EXAMPLES::
- 
-             sage: type(libgap)
--            <type 'sage.misc.lazy_import.LazyImport'>
--            sage: type(libgap._get_object())
-             <class 'sage.libs.gap.libgap.Gap'>
-         """
-         initialize()
-diff --git a/sage/misc/dev_tools.py b/sage/misc/dev_tools.py
---- a/sage/misc/dev_tools.py
-+++ b/sage/misc/dev_tools.py
-@@ -139,8 +139,8 @@
-     In principle, the function should also work on object which are instances.
-     In case of ambiguity, one or two warning lines are printed::
- 
--        sage: import_statements(NN)
--        from sage.rings.semirings.non_negative_integer_semiring import NN
-+        sage: import_statements(RDF)
-+        from sage.rings.real_double import RDF
- 
-         sage: import_statements(ZZ)
-           ** Warning **: several names for that object: ZZ, Z
-diff --git a/sage/misc/lazy_import.pyx b/sage/misc/lazy_import.pyx
---- a/sage/misc/lazy_import.pyx
-+++ b/sage/misc/lazy_import.pyx
-@@ -156,12 +156,6 @@
-         """
-         Return the wrapped object, importing it if necessary.
- 
--        INPUT:
--
--        - ``owner`` -- ``None`` or the class (or subclass thereof)
--          which contains this :class:`LazyImport` object in its
--          ``__dict__``.
--
-         OUTPUT:
- 
-         - the wrapped object
-@@ -172,38 +166,55 @@
-             sage: my_integer_ring = LazyImport('sage.rings.all', 'ZZ')
-             sage: my_integer_ring._object is None
-             True
-+           
-+        Create reference to the lazy import that cannot be replaced
-+        since tuples are immutable::
-+
-+            sage: my_integer_ref = (my_integer_ring,)
-+
-+        Now resolve the lazy import::
-+
-+            sage: type(my_integer_ring)
-+            <type 'sage.misc.lazy_import.LazyImport'>
-             sage: my_integer_ring._get_object()
-             Integer Ring
--            sage: my_integer_ring._object is None
-+            sage: type(my_integer_ring)
-+            <type 'sage.rings.integer_ring.IntegerRing_class'>
-+
-+            sage: hasattr(my_integer_ring, '_object') 
-             False
-+            sage: type(my_integer_ref[0])
-+            <type 'sage.misc.lazy_import.LazyImport'>
-+            sage: my_integer_ref[0]._object is my_integer_ring
-+            True
- 
-         .. note::
-+ 
-+            For a :class:`LazyImport` object that appears in a class
-+            namespace, we need to do something special. Indeed, the
-+            class namespace dictionary at the time of the class
-+            definition is not the one that actually gets used. Thus,
-+            when this function is called, :meth:`__get__`, ``owner``
-+            should be set to the ``owner`` class passed into
-+            ``__get__``::
- 
--           For a :class:`LazyImport` object that appears in a class
--           namespace, we need to do something special. Indeed, the
--           class namespace dictionary at the time of the class
--           definition is not the one that actually gets used. Thus,
--           when this function is called, :meth:`__get__`, ``owner``
--           should be set to the ``owner`` class passed into
--           ``__get__``::
-+                sage: class Foo(object):
-+                ...       lazy_import('sage.all', 'plot')
-+                sage: class Bar(Foo):
-+                ...       pass
-+                sage: type(Foo.__dict__['plot'])
-+                <type 'sage.misc.lazy_import.LazyImport'>
- 
--               sage: class Foo(object):
--               ...       lazy_import('sage.all', 'plot')
--               sage: class Bar(Foo):
--               ...       pass
--               sage: type(Foo.__dict__['plot'])
--               <type 'sage.misc.lazy_import.LazyImport'>
-+            Here is how :meth:`_get_object` is called internally upon
-+            ``Bar.plot``::
- 
--           Here is how :meth:`_get_object` is called internally upon
--           ``Bar.plot``::
--
--               sage: Foo.__dict__['plot']._get_object(Bar)
--               <function plot at ...>
--
--           Now ``Bar`` has been replaced in the dictionary of ``Foo``::
--
--               sage: type(Foo.__dict__['plot'])
--               <type 'function'>
-+                sage: Foo.__dict__['plot']._get_object()
-+                <function plot at ...>
-+                
-+            Now ``Bar`` has been replaced in the dictionary of ``Foo``::
-+            
-+                sage: type(Foo.__dict__['plot'])
-+                <type 'function'>
-         """
-         if self._object is None:
-             if startup_guard:
-@@ -213,18 +224,54 @@
-                 print 'Calling stack:'
-                 traceback.print_stack(None, None, sys.stdout)
-                 print '-' * 79
--            self._object = getattr(__import__(self._module, {}, {}, [self._name]), self._name)
--            alias = self._as_name or self._name
-+            obj = getattr(__import__(self._module, {}, {}, [self._name]), self._name)
-             if owner is None:
--                if self._namespace and self._namespace[alias] is self:
--                    self._namespace[alias] = self._object
-+                self._replace_all_lazy_imports(obj)
-             else:
-                 from inspect import getmro
-+                alias = self._as_name or self._name
-                 for cls in getmro(owner):
-                     if cls.__dict__.get(alias, None) is self:
--                        setattr(cls, alias, self._object)
-+                        setattr(cls, alias, obj)
-                         break
-+            self._object = obj
-         return self._object
-+
-+    def _replace_all_lazy_imports(self, obj):
-+        """
-+        Replace all references to the lazy import with ``obj``.
-+
-+        EXAMPLES::
-+        
-+            sage: from sage.misc.lazy_import import LazyImport
-+            sage: foo = LazyImport('sage.all', 'is_prime')
-+            sage: bar = foo
-+            sage: type(foo)
-+            <type 'sage.misc.lazy_import.LazyImport'>
-+            sage: type(bar)
-+            <type 'sage.misc.lazy_import.LazyImport'>
-+            sage: foo(1)
-+            False
-+            sage: type(foo)
-+            <type 'function'>
-+            sage: type(bar)
-+            <type 'function'>
-+            sage: foo is bar
-+            True
-+        """
-+        import gc
-+        gc_was_enabled = gc.isenabled()
-+        gc.disable()
-+        for ref in gc.get_referrers(self):
-+            if type(ref) is not dict:
-+                continue
-+            # the dicts are modules or classes holding lazy imports
-+            lazy_keys = [k for k,v in ref.iteritems() if v is self]
-+            for k in lazy_keys:
-+                ref[k] = obj
-+        if gc_was_enabled:
-+            gc.enable()
-+
-     
-     def _sage_doc_(self):
-         """

File trac_14187_lazy_import_test.patch

 # User Volker Braun <vbraun@stp.dias.ie>
 # Date 1362083025 36000
 # Node ID 70a9707a95f2ebdd61e6047e56e4ff5e7b2ebba7
-# Parent f8fbea9a346716af5ba987865acf395337a5472b
+# Parent 5ede04e6bce52102dca9323a193a09257b1dc027
 Warn developers if they resolve lazy imports during startup
 
 diff --git a/sage/all.py b/sage/all.py
 --- a/sage/all.py
 +++ b/sage/all.py
-@@ -313,3 +313,6 @@
+@@ -329,3 +329,6 @@
  # in set_random_seed() will result in the same sequence you got at
  # Sage startup).
  set_random_seed()
              self._object = getattr(__import__(self._module, {}, {}, [self._name]), self._name)
              alias = self._as_name or self._name
              if owner is None:
+@@ -774,6 +842,36 @@
+         """
+         return operator.index(self._get_object())
+ 
++    def __copy__(self):
++        """
++        Support copy()
++
++        TESTS::
++
++            sage: sage.all.foo = 10
++            sage: lazy_import('sage.all', 'foo')
++            sage: type(foo)
++            <type 'sage.misc.lazy_import.LazyImport'>
++            sage: copy(foo)
++            10
++        """
++        return self._get_object()
++
++    def __deepcopy__(self, memo=None):
++        """
++        Support copy()
++
++        TESTS::
++
++            sage: sage.all.foo = 10
++            sage: lazy_import('sage.all', 'foo')
++            sage: type(foo)
++            <type 'sage.misc.lazy_import.LazyImport'>
++            sage: deepcopy(foo)
++            10
++        """
++        return self._get_object()
++
+ 
+ def lazy_import(module, names, _as=None, namespace=None, bint overwrite=True):
+     """
 diff --git a/sage/rings/semirings/all.py b/sage/rings/semirings/all.py
 --- a/sage/rings/semirings/all.py
 +++ b/sage/rings/semirings/all.py

File trac_14357_lazy_everywhere.patch

+# HG changeset patch
+# User Volker Braun <vbraun@stp.dias.ie>
+# Date 1363031056 14400
+# Node ID 8cefe2e05ac231bb402c982ff1349356d129bcb7
+# Parent a7163022b65eb3d9118b7242f7e5da50e78f2331
+Replace all lazy references to a lazy import when resolving it.
+
+diff --git a/sage/libs/gap/libgap.pyx b/sage/libs/gap/libgap.pyx
+--- a/sage/libs/gap/libgap.pyx
++++ b/sage/libs/gap/libgap.pyx
+@@ -458,8 +458,6 @@
+         EXAMPLES::
+ 
+             sage: type(libgap)
+-            <type 'sage.misc.lazy_import.LazyImport'>
+-            sage: type(libgap._get_object())
+             <class 'sage.libs.gap.libgap.Gap'>
+         """
+         initialize()
+diff --git a/sage/misc/lazy_import.pyx b/sage/misc/lazy_import.pyx
+--- a/sage/misc/lazy_import.pyx
++++ b/sage/misc/lazy_import.pyx
+@@ -156,12 +156,6 @@
+         """
+         Return the wrapped object, importing it if necessary.
+ 
+-        INPUT:
+-
+-        - ``owner`` -- ``None`` or the class (or subclass thereof)
+-          which contains this :class:`LazyImport` object in its
+-          ``__dict__``.
+-
+         OUTPUT:
+ 
+         - the wrapped object
+@@ -172,38 +166,55 @@
+             sage: my_integer_ring = LazyImport('sage.rings.all', 'ZZ')
+             sage: my_integer_ring._object is None
+             True
++           
++        Create reference to the lazy import that cannot be replaced
++        since tuples are immutable::
++
++            sage: my_integer_ref = (my_integer_ring,)
++
++        Now resolve the lazy import::
++
++            sage: type(my_integer_ring)
++            <type 'sage.misc.lazy_import.LazyImport'>
+             sage: my_integer_ring._get_object()
+             Integer Ring
+-            sage: my_integer_ring._object is None
++            sage: type(my_integer_ring)
++            <type 'sage.rings.integer_ring.IntegerRing_class'>
++
++            sage: hasattr(my_integer_ring, '_object') 
+             False
++            sage: type(my_integer_ref[0])
++            <type 'sage.misc.lazy_import.LazyImport'>
++            sage: my_integer_ref[0]._object is my_integer_ring
++            True
+ 
+         .. note::
++ 
++            For a :class:`LazyImport` object that appears in a class
++            namespace, we need to do something special. Indeed, the
++            class namespace dictionary at the time of the class
++            definition is not the one that actually gets used. Thus,
++            when this function is called, :meth:`__get__`, ``owner``
++            should be set to the ``owner`` class passed into
++            ``__get__``::
+ 
+-           For a :class:`LazyImport` object that appears in a class
+-           namespace, we need to do something special. Indeed, the
+-           class namespace dictionary at the time of the class
+-           definition is not the one that actually gets used. Thus,
+-           when this function is called, :meth:`__get__`, ``owner``
+-           should be set to the ``owner`` class passed into
+-           ``__get__``::
++                sage: class Foo(object):
++                ...       lazy_import('sage.all', 'plot')
++                sage: class Bar(Foo):
++                ...       pass
++                sage: type(Foo.__dict__['plot'])
++                <type 'sage.misc.lazy_import.LazyImport'>
+ 
+-               sage: class Foo(object):
+-               ...       lazy_import('sage.all', 'plot')
+-               sage: class Bar(Foo):
+-               ...       pass
+-               sage: type(Foo.__dict__['plot'])
+-               <type 'sage.misc.lazy_import.LazyImport'>
++            Here is how :meth:`_get_object` is called internally upon
++            ``Bar.plot``::
+ 
+-           Here is how :meth:`_get_object` is called internally upon
+-           ``Bar.plot``::
+-
+-               sage: Foo.__dict__['plot']._get_object(Bar)
+-               <function plot at ...>
+-
+-           Now ``Bar`` has been replaced in the dictionary of ``Foo``::
+-
+-               sage: type(Foo.__dict__['plot'])
+-               <type 'function'>
++                sage: Foo.__dict__['plot']._get_object()
++                <function plot at ...>
++                
++            Now ``Bar`` has been replaced in the dictionary of ``Foo``::
++            
++                sage: type(Foo.__dict__['plot'])
++                <type 'function'>
+         """
+         if self._object is None:
+             if startup_guard:
+@@ -213,18 +224,54 @@
+                 print 'Calling stack:'
+                 traceback.print_stack(None, None, sys.stdout)
+                 print '-' * 79
+-            self._object = getattr(__import__(self._module, {}, {}, [self._name]), self._name)
+-            alias = self._as_name or self._name
++            obj = getattr(__import__(self._module, {}, {}, [self._name]), self._name)
+             if owner is None:
+-                if self._namespace and self._namespace[alias] is self:
+-                    self._namespace[alias] = self._object
++                self._replace_all_lazy_imports(obj)
+             else:
+                 from inspect import getmro
++                alias = self._as_name or self._name
+                 for cls in getmro(owner):
+                     if cls.__dict__.get(alias, None) is self:
+-                        setattr(cls, alias, self._object)
++                        setattr(cls, alias, obj)
+                         break
++            self._object = obj
+         return self._object
++
++    def _replace_all_lazy_imports(self, obj):
++        """
++        Replace all references to the lazy import with ``obj``.
++
++        EXAMPLES::
++        
++            sage: from sage.misc.lazy_import import LazyImport
++            sage: foo = LazyImport('sage.all', 'is_prime')
++            sage: bar = foo
++            sage: type(foo)
++            <type 'sage.misc.lazy_import.LazyImport'>
++            sage: type(bar)
++            <type 'sage.misc.lazy_import.LazyImport'>
++            sage: foo(1)
++            False
++            sage: type(foo)
++            <type 'function'>
++            sage: type(bar)
++            <type 'function'>
++            sage: foo is bar
++            True
++        """
++        import gc
++        gc_was_enabled = gc.isenabled()
++        gc.disable()
++        for ref in gc.get_referrers(self):
++            if type(ref) is not dict:
++                continue
++            # the dicts are modules or classes holding lazy imports
++            lazy_keys = [k for k,v in ref.iteritems() if v is self]
++            for k in lazy_keys:
++                ref[k] = obj
++        if gc_was_enabled:
++            gc.enable()
++
+     
+     def _sage_doc_(self):
+         """

File trac_14359_doctest_ansi_escapes.patch

+# HG changeset patch
+# Parent eaa78a5f41ed7caad550ee135c374ada386d62a0
+
+Ignore ansi escape sequences when matching doctest output
+
+diff --git a/sage/doctest/parsing.py b/sage/doctest/parsing.py
+--- a/sage/doctest/parsing.py
++++ b/sage/doctest/parsing.py
+@@ -31,6 +31,7 @@
+ tolerance_pattern = re.compile(r'\b((?:abs(?:olute)?)|(?:rel(?:ative)?))? *?tol(?:erance)?\b( +[0-9.e+-]+)?')
+ backslash_replacer = re.compile(r"""(\s*)sage:(.*)\\\ *
+ \ *(((\.){4}:)|((\.){3}))?\ *""")
++ansi_escape_pattern = re.compile(r'\x1b\[[0-9;]*m')
+ 
+ def parse_optional_tags(string):
+     """
+@@ -662,6 +663,7 @@
+             sage: print "1.000009"   # abs tol 1e-5
+             1.0
+         """
++        got = ansi_escape_pattern.sub('', got)
+         if isinstance(want, MarkedOutput):
+             if want.random:
+                 return True
+@@ -849,4 +851,6 @@
+                 else:
+                     diff += "Tolerance exceeded in %s of %s\n"%(len(fails), len(want_values))
+                     diff += "\n".join(fails[:3]) + "\n"
++        if ansi_escape_pattern.match(got) is not None:
++            diff += "Output contains ansi escape sequences\n"
+         return diff

File trac_14359_doctest_unicode_warning.patch

+# HG changeset patch
+# Parent 8ff540b515483823f6d95e81ef26f3871abbf005
+
+Fix spurious unicode warning during doctests
+
+diff --git a/doc/en/developer/conventions.rst b/doc/en/developer/conventions.rst
+--- a/doc/en/developer/conventions.rst
++++ b/doc/en/developer/conventions.rst
+@@ -420,7 +420,7 @@
+           Improve further function ``have_fresh_beers`` using algorithm
+           ``buy_a_better_fridge``::
+ 
+-              sage: have_fresh_beers('Bière de l'Yvette') # todo: not implemented
++              sage: have_fresh_beers('Bière de l\'Yvette') # todo: not implemented
+               Enjoy !
+ 
+ - A REFERENCES block to list books or papers (optional). This block serves
+diff --git a/sage/doctest/forker.py b/sage/doctest/forker.py
+--- a/sage/doctest/forker.py
++++ b/sage/doctest/forker.py
+@@ -1925,7 +1925,7 @@
+             sage: runner.failures
+             0
+             sage: ntests
+-            202
++            203
+         """
+         result = None
+         try:
+diff --git a/sage/doctest/parsing.py b/sage/doctest/parsing.py
+--- a/sage/doctest/parsing.py
++++ b/sage/doctest/parsing.py
+@@ -1,3 +1,4 @@
++## -*- encoding: utf-8 -*-
+ """
+ This module contains functions and classes that parse docstrings.
+ 
+@@ -20,8 +21,7 @@
+ 
+ import re, sys
+ import doctest
+-from sage.misc.preparser import preparse
+-from Cython.Build.Dependencies import strip_string_literals
++from sage.misc.preparser import preparse, strip_string_literals
+ 
+ float_regex = re.compile('([+-]?((\d*\.?\d+)|(\d+\.?))([eE][+-]?\d+)?)')
+ optional_regex = re.compile(r'(long time|not implemented|not tested|known bug)|([^ a-z]\s*optional\s*[:-]*((\s|\w)*))')
+@@ -69,12 +69,18 @@
+         set([])
+         sage: parse_optional_tags("    sage: print '  # long time'  # not tested")
+         set(['not tested'])
++
++    UTF-8 works::
++
++         sage: parse_optional_tags("'ěščřžýáíéďĎ'")
++         set([])
+     """
+-    safe, literals = strip_string_literals(string)
++    safe, literals, state = strip_string_literals(string)
+     first_line = safe.split('\n', 1)[0]
+     if '#' not in first_line:
+         return set()
+     comment = first_line[first_line.find('#')+1:]
++    comment = comment[comment.index('(')+1 : comment.rindex(')')]
+     # strip_string_literals replaces comments
+     comment = "#" + (literals[comment]).lower()
+ 
+@@ -115,11 +121,12 @@
+         sage: marked.abs_tol
+         0.01
+     """
+-    safe, literals = strip_string_literals(source)
++    safe, literals, state = strip_string_literals(source)
+     first_line = safe.split('\n', 1)[0]
+     if '#' not in first_line:
+         return want
+     comment = first_line[first_line.find('#')+1:]
++    comment = comment[comment.index('(')+1 : comment.rindex(')')]
+     # strip_string_literals replaces comments
+     comment = literals[comment]
+     if random_marker.search(comment):
+diff --git a/sage/misc/messaging.py b/sage/misc/messaging.py
+--- a/sage/misc/messaging.py
++++ b/sage/misc/messaging.py
+@@ -62,7 +62,7 @@
+     To set default values populate ``pushover_defaults``::
+ 
+         sage: sage.misc.messaging.pushover_defaults["user"] = "USER_TOKEN"
+-        sage: sage.misc.messaging.pushover("Hi, how are you?"") # not tested
++        sage: sage.misc.messaging.pushover("Hi, how are you?") # not tested
+ 
+     .. note::
+