예제 #1
0
    def apply_matrix(self, m, in_place=True, mapping=False):
        r"""
        Carry out the GL(2,R) action of m on this surface and return the result.
        
        If in_place=True, then this is done in place and changes the surface. 
        This can only be carried out if the surface is finite and mutable.
        
        If mapping=True, then we return a GL2RMapping between this surface and its image. 
        In this case in_place must be False.
        
        If in_place=False, then a copy is made before the deformation.
        """
        if mapping == True:
            assert in_place == False, "Can not modify in place and return a mapping."
            return GL2RMapping(self, m)
        if not in_place:
            if self.is_finite():
                from sage.structure.element import get_coercion_model
                cm = get_coercion_model()
                field = cm.common_parent(self.base_ring(), m.base_ring())
                s = self.copy(mutable=True, new_field=field)
                return s.apply_matrix(m)
            else:
                return m * self
        else:
            # Make sure m is in the right state
            from sage.matrix.constructor import Matrix
            m = Matrix(self.base_ring(), 2, 2, m)
            assert m.det() != self.base_ring().zero(
            ), "Can not deform by degenerate matrix."
            assert self.is_finite(
            ), "In place GL(2,R) action only works for finite surfaces."
            us = self.underlying_surface()
            assert us.is_mutable(
            ), "In place changes only work for mutable surfaces."
            for label in self.label_iterator():
                us.change_polygon(label, m * self.polygon(label))
            if m.det() < self.base_ring().zero():
                # Polygons were all reversed orientation. Need to redo gluings.

                # First pass record new gluings in a dictionary.
                new_glue = {}
                seen_labels = set()
                for p1 in self.label_iterator():
                    n1 = self.polygon(p1).num_edges()
                    for e1 in range(n1):
                        p2, e2 = self.opposite_edge(p1, e1)
                        n2 = self.polygon(p2).num_edges()
                        if p2 in seen_labels:
                            pass
                        elif p1 == p2 and e1 > e2:
                            pass
                        else:
                            new_glue[(p1, n1 - 1 - e1)] = (p2, n2 - 1 - e2)
                    seen_labels.add(p1)
                # Second pass: reassign gluings
                for (p1, e1), (p2, e2) in iteritems(new_glue):
                    us.change_edge_gluing(p1, e1, p2, e2)
            return self
 def apply_matrix(self,m,in_place=True, mapping=False):
     r"""
     Carry out the GL(2,R) action of m on this surface and return the result.
     
     If in_place=True, then this is done in place and changes the surface. 
     This can only be carried out if the surface is finite and mutable.
     
     If mapping=True, then we return a GL2RMapping between this surface and its image. 
     In this case in_place must be False.
     
     If in_place=False, then a copy is made before the deformation.
     """
     if mapping==True:
         assert in_place==False, "Can not modify in place and return a mapping."
         return GL2RMapping(self, m)
     if not in_place:
         if self.is_finite():
             from sage.structure.element import get_coercion_model
             cm = get_coercion_model()
             field = cm.common_parent(self.base_ring(), m.base_ring())
             s=self.copy(mutable=True, new_field=field)
             return s.apply_matrix(m)
         else:
             return m*self
     else:
         # Make sure m is in the right state
         from sage.matrix.constructor import Matrix
         m=Matrix(self.base_ring(), 2, 2, m)
         assert m.det()!=self.base_ring().zero(), "Can not deform by degenerate matrix."
         assert self.is_finite(), "In place GL(2,R) action only works for finite surfaces."
         us=self.underlying_surface()
         assert us.is_mutable(), "In place changes only work for mutable surfaces."
         for label in self.label_iterator():
             us.change_polygon(label,m*self.polygon(label))
         if m.det()<self.base_ring().zero():
             # Polygons were all reversed orientation. Need to redo gluings.
             
             # First pass record new gluings in a dictionary.
             new_glue={}
             seen_labels=set()
             for p1 in self.label_iterator():
                 n1=self.polygon(p1).num_edges()
                 for e1 in xrange(n1):
                     p2,e2=self.opposite_edge(p1,e1)
                     n2=self.polygon(p2).num_edges()
                     if p2 in seen_labels:
                         pass
                     elif p1==p2 and e1>e2:
                         pass
                     else:
                         new_glue[(p1, n1-1-e1)]=(p2, n2-1-e2)
                 seen_labels.add(p1)
             # Second pass: reassign gluings
             for (p1,e1),(p2,e2) in new_glue.iteritems():
                 us.change_edge_gluing(p1,e1,p2,e2)
         return self
예제 #3
0
파일: normal_form.py 프로젝트: yazici/sage
def _normalize_2x2(G):
    r"""
    Normalize this indecomposable `2` by `2` block.

    INPUT:

    ``G`` - a `2` by `2` matrix over `\ZZ_p`
    with ``type = 'fixed-mod'`` of the form::

        [2a  b]
        [ b 2c] * 2^n

    with `b` of valuation 1.

    OUTPUT:

    A unimodular `2` by `2` matrix ``B`` over `\ZZ_p` with
    ``B * G * B.transpose()``
    either::

        [0 1]              [2 1]
        [1 0] * 2^n  or    [1 2] * 2^n

    EXAMPLES::

        sage: from sage.quadratic_forms.genera.normal_form import _normalize_2x2
        sage: R = Zp(2, prec = 15, type = 'fixed-mod', print_mode='series', show_prec=False)
        sage: G = Matrix(R, 2, [-17*2,3,3,23*2])
        sage: B =_normalize_2x2(G)
        sage: B * G * B.T
        [2 1]
        [1 2]

        sage: G = Matrix(R,2,[-17*4,3,3,23*2])
        sage: B = _normalize_2x2(G)
        sage: B*G*B.T
        [0 1]
        [1 0]

        sage: G = 2^3 * Matrix(R, 2, [-17*2,3,3,23*2])
        sage: B = _normalize_2x2(G)
        sage: B * G * B.T
        [2^4 2^3]
        [2^3 2^4]
    """
    from sage.rings.all import PolynomialRing
    from sage.modules.free_module_element import vector
    B = copy(G.parent().identity_matrix())
    R = G.base_ring()
    P = PolynomialRing(R, 'x')
    x = P.gen()

    # The input must be an even block
    odd1 = (G[0, 0].valuation() < G[1, 0].valuation())
    odd2 = (G[1, 1].valuation() < G[1, 0].valuation())
    if odd1 or odd2:
        raise ValueError("Not a valid 2 x 2 block.")
    scale = 2**G[0, 1].valuation()
    D = Matrix(R, 2, 2, [d // scale for d in G.list()])
    # now D is of the form
    # [2a b ]
    # [b  2c]
    # where b has valuation 1.
    G = copy(D)

    # Make sure G[1, 1] has valuation 1.
    if D[1, 1].valuation() > D[0, 0].valuation():
        B.swap_columns(0, 1)
        D.swap_columns(0, 1)
        D.swap_rows(0, 1)
    if D[1, 1].valuation() != 1:
        # this works because
        # D[0, 0] has valuation at least 2
        B[1, :] += B[0, :]
        D = B * G * B.transpose()
    assert D[1, 1].valuation() == 1

    if mod(D.det(), 8) == 3:
        #  in this case we can transform D to
        #  2 1
        #  1 2
        # Find a point of norm 2
        # solve: 2 == D[1,1]*x^2 + 2*D[1,0]*x + D[0,0]
        pol = (D[1, 1] * x**2 + 2 * D[1, 0] * x + D[0, 0] - 2) // 2
        # somehow else pari can get a hickup see trac #24065
        pol = pol // pol.leading_coefficient()
        sol = pol.roots()[0][0]
        B[0, 1] = sol
        D = B * G * B.transpose()
        # make D[0, 1] = 1
        B[1, :] *= D[1, 0].inverse_of_unit()
        D = B * G * B.transpose()

        # solve: v*D*v == 2 with v = (x, -2*x+1)
        if D[1, 1] != 2:
            v = vector([x, -2 * x + 1])
            pol = (v * D * v - 2) // 2
            # somehow else pari can get a hickup see trac #24065
            pol = pol // pol.leading_coefficient()
            sol = pol.roots()[0][0]
            B[1, :] = sol * B[0, :] + (-2 * sol + 1) * B[1, :]
            D = B * G * B.transpose()
        # check the result
        assert D == Matrix(G.parent(), 2, 2, [2, 1, 1, 2]), "D1 \n %r" % D
    elif mod(D.det(), 8) == 7:
        # in this case we can transform D to
        #  0 1
        #  1 0
        # Find a point representing 0
        # solve: 0 == D[1,1]*x^2 + 2*D[1,0]*x + D[0,0]
        pol = (D[1, 1] * x**2 + 2 * D[1, 0] * x + D[0, 0]) // 2
        # somehow else pari can get a hickup, see trac #24065
        pol = pol // pol.leading_coefficient()
        sol = pol.roots()[0][0]
        B[0, :] += sol * B[1, :]
        D = B * G * B.transpose()
        # make the second basis vector have 0 square as well.
        B[1, :] = B[1, :] - D[1, 1] // (2 * D[0, 1]) * B[0, :]
        D = B * G * B.transpose()
        # rescale to get D[0,1] = 1
        B[0, :] *= D[1, 0].inverse_of_unit()
        D = B * G * B.transpose()
        # check the result
        assert D == Matrix(G.parent(), 2, 2, [0, 1, 1, 0]), "D2 \n %r" % D
    return B
예제 #4
0
파일: normal_form.py 프로젝트: yazici/sage
def _jordan_2_adic(G):
    r"""
    Transform a symmetric matrix over the `2`-adic integers into jordan form.

    Note that if the precision is too low, this method fails.
    The method is only tested for input over `\ZZ_2` of ``'type=fixed-mod'``.

    INPUT:

    - ``G`` -- symmetric `n` by `n` matrix in `\ZZ_p`

    OUTPUT:

    - ``D`` -- the jordan matrix
    - ``B`` -- transformation matrix, i.e, ``D = B * G * B^T``

    The matrix ``D`` is a block diagonal matrix consisting
    of `1` by `1` and `2` by `2` blocks.
    The `2` by `2` blocks are matrices of the form
    `[[2a,  b], [b, 2c]] * 2^k`
    with `b` of valuation `0`.

    EXAMPLES::

        sage: from sage.quadratic_forms.genera.normal_form import _jordan_2_adic
        sage: R = Zp(2, prec=3, print_mode='terse', show_prec=False)
        sage: A4 = Matrix(R,4,[2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2])
        sage: A4
        [2 7 0 0]
        [7 2 7 0]
        [0 7 2 7]
        [0 0 7 2]
        sage: D, B = _jordan_2_adic(A4)
        sage: D
        [ 2  7  0  0]
        [ 7  2  0  0]
        [ 0  0 12  7]
        [ 0  0  7  2]
        sage: D == B*A4*B.T
        True
        sage: B.determinant().valuation() == 0
        True
    """
    R = G.base_ring()
    D = copy(G)
    n = G.ncols()

    # transformation matrix
    B = Matrix.identity(R, n)

    # indices of the diagonal entrys which are already used
    cnt = 0
    minval = None
    while cnt < n:
        pivot = _find_min_p(D, cnt)
        piv1 = pivot[1]
        piv2 = pivot[2]
        minval = pivot[0]
        # the smallest valuation is on the diagonal
        if piv1 == piv2:
            # move pivot to position [cnt,cnt]
            if piv1 != cnt:
                B.swap_rows(cnt, piv1)
                D.swap_rows(cnt, piv1)
                D.swap_columns(cnt, piv1)
            # we are already orthogonal to the part with i < cnt
            # now make the rest orthogonal too
            for i in range(cnt + 1, n):
                if D[i, cnt] != 0:
                    c = D[i, cnt] // D[cnt, cnt]
                    B[i, :] += -c * B[cnt, :]
                    D[i, :] += -c * D[cnt, :]
                    D[:, i] += -c * D[:, cnt]
            cnt = cnt + 1
        # the smallest valuation is off the diagonal
        else:
            # move this 2 x 2 block to the top left (starting from cnt)
            if piv1 != cnt:
                B.swap_rows(cnt, piv1)
                D.swap_rows(cnt, piv1)
                D.swap_columns(cnt, piv1)
            if piv2 != cnt + 1:
                B.swap_rows(cnt + 1, piv2)
                D.swap_rows(cnt + 1, piv2)
                D.swap_columns(cnt + 1, piv2)
            # we split off a 2 x 2 block
            # if it is the last 2 x 2 block, there is nothing to do.
            if cnt != n - 2:
                content = R(2**minval)
                eqn_mat = D[cnt:cnt + 2, cnt:cnt + 2].list()
                eqn_mat = Matrix(R, 2, 2, [e // content for e in eqn_mat])
                # calculate the inverse without using division
                inv = eqn_mat.adjugate() * eqn_mat.det().inverse_of_unit()
                B1 = B[cnt:cnt + 2, :]
                B2 = D[cnt + 2:, cnt:cnt + 2] * inv
                for i in range(B2.nrows()):
                    for j in range(B2.ncols()):
                        B2[i, j] = B2[i, j] // content
                B[cnt + 2:, :] -= B2 * B1
                D[cnt:, cnt:] = B[cnt:, :] * G * B[cnt:, :].transpose()
            cnt += 2
    return D, B
예제 #5
0
def _normalize_2x2(G):
    r"""
    Normalize this indecomposable `2` by `2` block.

    INPUT:

    ``G`` - a `2` by `2` matrix over `\ZZ_p`
    with ``type = 'fixed-mod'`` of the form::

        [2a  b]
        [ b 2c] * 2^n

    with `b` of valuation 1.

    OUTPUT:

    A unimodular `2` by `2` matrix ``B`` over `\ZZ_p` with
    ``B * G * B.transpose()``
    either::

        [0 1]              [2 1]
        [1 0] * 2^n  or    [1 2] * 2^n

    EXAMPLES::

        sage: from sage.quadratic_forms.genera.normal_form import _normalize_2x2
        sage: R = Zp(2, prec = 15, type = 'fixed-mod', print_mode='series', show_prec=False)
        sage: G = Matrix(R, 2, [-17*2,3,3,23*2])
        sage: B =_normalize_2x2(G)
        sage: B * G * B.T
        [2 1]
        [1 2]

        sage: G = Matrix(R,2,[-17*4,3,3,23*2])
        sage: B = _normalize_2x2(G)
        sage: B*G*B.T
        [0 1]
        [1 0]

        sage: G = 2^3 * Matrix(R, 2, [-17*2,3,3,23*2])
        sage: B = _normalize_2x2(G)
        sage: B * G * B.T
        [2^4 2^3]
        [2^3 2^4]
    """
    from sage.rings.all import PolynomialRing
    from sage.modules.free_module_element import vector
    B = copy(G.parent().identity_matrix())
    R = G.base_ring()
    P = PolynomialRing(R, 'x')
    x = P.gen()

    # The input must be an even block
    odd1 = (G[0, 0].valuation() < G[1, 0].valuation())
    odd2 = (G[1, 1].valuation() < G[1, 0].valuation())
    if  odd1 or odd2:
            raise ValueError("Not a valid 2 x 2 block.")
    scale = 2 ** G[0,1].valuation()
    D = Matrix(R, 2, 2, [d // scale for d in G.list()])
    # now D is of the form
    # [2a b ]
    # [b  2c]
    # where b has valuation 1.
    G = copy(D)

    # Make sure G[1, 1] has valuation 1.
    if D[1, 1].valuation() > D[0, 0].valuation():
        B.swap_columns(0, 1)
        D.swap_columns(0, 1)
        D.swap_rows(0, 1)
    if D[1, 1].valuation() != 1:
        # this works because
        # D[0, 0] has valuation at least 2
        B[1, :] += B[0, :]
        D = B * G * B.transpose()
    assert D[1, 1].valuation() == 1

    if mod(D.det(), 8) == 3:
        #  in this case we can transform D to
        #  2 1
        #  1 2
        # Find a point of norm 2
        # solve: 2 == D[1,1]*x^2 + 2*D[1,0]*x + D[0,0]
        pol = (D[1,1]*x**2 + 2*D[1,0]*x + D[0,0]-2) // 2
        # somehow else pari can get a hickup see `trac`:#24065
        pol = pol // pol.leading_coefficient()
        sol = pol.roots()[0][0]
        B[0, 1] = sol
        D = B * G * B.transpose()
        # make D[0, 1] = 1
        B[1, :] *= D[1, 0].inverse_of_unit()
        D = B * G * B.transpose()

        # solve: v*D*v == 2 with v = (x, -2*x+1)
        if D[1, 1] != 2:
            v = vector([x, -2*x + 1])
            pol = (v*D*v - 2) // 2
            # somehow else pari can get a hickup `trac`:#24065
            pol = pol // pol.leading_coefficient()
            sol = pol.roots()[0][0]
            B[1, :] = sol * B[0,:] + (-2*sol + 1)*B[1, :]
            D = B * G * B.transpose()
        # check the result
        assert D == Matrix(G.parent(), 2, 2, [2, 1, 1, 2]), "D1 \n %r" %D
    elif mod(D.det(), 8) == 7:
        # in this case we can transform D to
        #  0 1
        #  1 0
        # Find a point representing 0
        # solve: 0 == D[1,1]*x^2 + 2*D[1,0]*x + D[0,0]
        pol = (D[1,1]*x**2 + 2*D[1,0]*x + D[0,0])//2
        # somehow else pari can get a hickup, see  `trac`:#24065
        pol = pol // pol.leading_coefficient()
        sol = pol.roots()[0][0]
        B[0,:] += sol*B[1, :]
        D = B * G * B.transpose()
        # make the second basis vector have 0 square as well.
        B[1, :] = B[1, :] - D[1, 1]//(2*D[0, 1])*B[0,:]
        D = B * G * B.transpose()
        # rescale to get D[0,1] = 1
        B[0, :] *= D[1, 0].inverse_of_unit()
        D = B * G * B.transpose()
        # check the result
        assert D == Matrix(G.parent(), 2, 2, [0, 1, 1, 0]), "D2 \n %r" %D
    return B
예제 #6
0
def _jordan_2_adic(G):
    r"""
    Transform a symmetric matrix over the `2`-adic integers into jordan form.

    Note that if the precision is too low, this method fails.
    The method is only tested for input over `\ZZ_2` of ``'type=fixed-mod'``.

    INPUT:

    - ``G`` -- symmetric `n` by `n` matrix in `\ZZ_p`

    OUTPUT:

    - ``D`` -- the jordan matrix
    - ``B`` -- transformation matrix, i.e, ``D = B * G * B^T``

    The matrix ``D`` is a block diagonal matrix consisting
    of `1` by `1` and `2` by `2` blocks.
    The `2` by `2` blocks are matrices of the form
    `[[2a,  b], [b, 2c]] * 2^k`
    with `b` of valuation `0`.

    EXAMPLES::

        sage: from sage.quadratic_forms.genera.normal_form import _jordan_2_adic
        sage: R = Zp(2, prec=3, print_mode='terse', show_prec=False)
        sage: A4 = Matrix(R,4,[2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2])
        sage: A4
        [2 7 0 0]
        [7 2 7 0]
        [0 7 2 7]
        [0 0 7 2]
        sage: D, B = _jordan_2_adic(A4)
        sage: D
        [ 2  7  0  0]
        [ 7  2  0  0]
        [ 0  0 12  7]
        [ 0  0  7  2]
        sage: D == B*A4*B.T
        True
        sage: B.determinant().valuation() == 0
        True
    """
    R = G.base_ring()
    D = copy(G)
    n = G.ncols()

    # transformation matrix
    B = Matrix.identity(R, n)

    # indices of the diagonal entrys which are already used
    cnt = 0
    minval = None
    while cnt < n:
            pivot = _find_min_p(D, cnt)
            piv1 = pivot[1]
            piv2 = pivot[2]
            minval_last = minval
            minval = pivot[0]
            # the smallest valuation is on the diagonal
            if piv1 == piv2:
                # move pivot to position [cnt,cnt]
                if piv1 != cnt:
                    B.swap_rows(cnt, piv1)
                    D.swap_rows(cnt, piv1)
                    D.swap_columns(cnt, piv1)
                # we are already orthogonal to the part with i < cnt
                # now make the rest orthogonal too
                for i in range(cnt+1, n):
                    if D[i, cnt] != 0:
                        c = D[i, cnt]//D[cnt, cnt]
                        B[i, :] += -c * B[cnt, :]
                        D[i, :] += -c * D[cnt, :]
                        D[:, i] += -c * D[:, cnt]
                cnt = cnt + 1
            # the smallest valuation is off the diagonal
            else:
                # move this 2 x 2 block to the top left (starting from cnt)
                if piv1 != cnt:
                    B.swap_rows(cnt, piv1)
                    D.swap_rows(cnt, piv1)
                    D.swap_columns(cnt, piv1)
                if piv2 != cnt+1:
                    B.swap_rows(cnt+1, piv2)
                    D.swap_rows(cnt+1, piv2)
                    D.swap_columns(cnt+1, piv2)
                # we split off a 2 x 2 block
                # if it is the last 2 x 2 block, there is nothing to do.
                if cnt != n-2:
                    content = R(2 ** minval)
                    eqn_mat = D[cnt:cnt+2, cnt:cnt+2].list()
                    eqn_mat = Matrix(R, 2, 2, [e // content for e in eqn_mat])
                    # calculate the inverse without using division
                    inv = eqn_mat.adjoint() * eqn_mat.det().inverse_of_unit()
                    B1 = B[cnt:cnt+2, :]
                    B2 = D[cnt+2:, cnt:cnt+2] * inv
                    for i in range(B2.nrows()):
                        for j in range(B2.ncols()):
                            B2[i, j]=B2[i, j] // content
                    B[cnt+2:, :] -= B2 * B1
                    D[cnt:, cnt:] = B[cnt:, :] * G * B[cnt:, :].transpose()
                cnt += 2
    return D, B