Ejemplo n.º 1
0
def gen_ccfterm_RNE( do_varify, rbt, usemotordyn=True, varify_trig=True ):
    from copy import deepcopy
    rbttmp = deepcopy(rbt)
    rbttmp.grav = zero_matrix(3,1)
    rbttmp.ddq = zero_matrix(rbttmp.dof,1)
    rbttmp.gen_geom()
    return gen_tau_RNE( do_varify, rbttmp, usemotordyn=usemotordyn, varify_trig=varify_trig )
Ejemplo n.º 2
0
def tau_to_regressor(tau,P,verify=False):
    '''
    given symbolic vectors tau and P,
    returns matrix Y
    which verifies
    Y * P = tau
    '''
    from sage.all import zero_matrix, SR

    m = tau.nrows()
    n = P.nrows()

    Y = copy( zero_matrix(SR,m,n) )

    for i in range(0 ,m):
        for j in range(0 ,P.nrows()):
            if verify:
                coeffs = ( tau[i,0 ].coeffs(P[j,0 ]) )
                for coeff in coeffs:
                    if coeff[1] > 1 or coeff[1] < 0 :
                        raise Exception('gen_dyn_lineqs: '+P[j,0 ].__repr__()+' is not linear')
                    if coeff[1] == 1 :
                        Y[i,j] = coeff[0]
            else:
                Y[i,j] = tau[i,0].coeff( P[j,0] )

    if verify and bool( ( Y * P - tau ).expand() != zero_matrix(m,1) ):
        raise Exception('gen_dyn_lineqs: linearity not verified')

    return Y
Ejemplo n.º 3
0
def _gen_gravterm_altRNE(do_varify, rbt, varify_trig=True):
    from copy import deepcopy
    rbttmp = deepcopy(rbt)
    rbttmp.dq = zero_matrix(rbttmp.dof,1)
    rbttmp.ddq = zero_matrix(rbttmp.dof,1)
    rbttmp.gen_geom()
    return _gen_tau_altRNE(do_varify, rbttmp, varify_trig)
Ejemplo n.º 4
0
def positive_lineality_space(n):
    A = kalmanson_matrix(n)
    n = A.nrows()
    c = A.ncols()
    eq = zero_matrix(n,1).augment(A).rows()
    ieq = zero_matrix(c,1).augment(identity_matrix(c)).rows()
    return Polyhedron(eqns=eq, ieqs=ieq)
Ejemplo n.º 5
0
  def gen_kinem( self ):

    self.Jpi = range(0 ,self.dof+1 )
    self.Jpi[0] = zero_matrix(SR,3,self.dof)
    for l in range(1 ,self.dof+1 ):
      self.Jpi[l] = matrix(SR,3 ,self.dof)
      for j in range(1 ,l+1 ):
          self.Jpi[l][0 :3 ,j-1 ] = utils.skew(self.zi[j-1 ]) * ( self.pi[l] - self.pi[j-1 ] )

      #Jpi[i] = Jpi[i].simplify_rational()
      #Jpi[i] = trig_reduce(Jpi[i])
      #Jpi[i] = Jpi[i].simplify()

    self.Joi = range(0 ,self.dof+1 )
    self.Joi[0] = zero_matrix(SR,3,self.dof)
    for l in range(1 ,self.dof+1 ):
      self.Joi[l] = matrix(SR,3 ,self.dof)
      for j in range(1 ,l+1 ):
          self.Joi[l][0 :3 ,j-1 ] = (self.zi[j-1 ])

      #Joi[i] = Joi[i].simplify_rational()
      #Joi[i] = Joi[i].simplify()

    self.Jcpi = range(0 ,self.dof+1 )
    self.Jcoi = self.Joi

    for l in range(1 ,self.dof+1 ):
      self.Jcpi[l] = self.Jpi[l] - utils.skew( self.Ri[l]*self.li[l] ) * self.Joi[l]

    return self
Ejemplo n.º 6
0
    def test_symplectic(self):
        # the symmetric transformation matrix should be symplectic
        Pa = self.atrott
        Pb = self.btrott
        R = involution_matrix(Pa, Pb)
        S = integer_kernel_basis(R)
        N1 = N1_matrix(Pa, Pb, S)
        H,Q = symmetric_block_diagonalize(N1)
        Gamma = symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=1e-4)
        g,g = Pa.dimensions()
        J = zero_matrix(ZZ,2*g,2*g)
        Ig = identity_matrix(ZZ, g, g)
        J[:g,g:] = Ig
        J[g:,:g] = -Ig
        self.assertEqual(Gamma.T*J*Gamma,J)

        Pa = self.aklein
        Pb = self.bklein
        R = involution_matrix(Pa, Pb, tol=1e-3)
        S = integer_kernel_basis(R)
        N1 = N1_matrix(Pa, Pb, S)
        H,Q = symmetric_block_diagonalize(N1)
        Gamma = symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=1e-3)
        g,g = Pa.dimensions()
        J = zero_matrix(ZZ,2*g,2*g)
        Ig = identity_matrix(ZZ, g, g)
        J[:g,g:] = Ig
        J[g:,:g] = -Ig
        self.assertEqual(Gamma.T*J*Gamma,J)

        Pa = self.afermat
        Pb = self.bfermat
        R = involution_matrix(Pa, Pb, tol=1e-3)
        S = integer_kernel_basis(R)
        N1 = N1_matrix(Pa, Pb, S)
        H,Q = symmetric_block_diagonalize(N1)
        Gamma = symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=1e-3)
        g,g = Pa.dimensions()
        J = zero_matrix(ZZ,2*g,2*g)
        Ig = identity_matrix(ZZ, g, g)
        J[:g,g:] = Ig
        J[g:,:g] = -Ig
        self.assertEqual(Gamma.T*J*Gamma,J)

        Pa = self.a6
        Pb = self.b6
        R = involution_matrix(Pa, Pb)
        S = integer_kernel_basis(R)
        N1 = N1_matrix(Pa, Pb, S)
        H,Q = symmetric_block_diagonalize(N1)
        Gamma = symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=1e-4)
        g,g = Pa.dimensions()
        J = zero_matrix(ZZ,2*g,2*g)
        Ig = identity_matrix(ZZ, g, g)
        J[:g,g:] = Ig
        J[g:,:g] = -Ig
        self.assertEqual(Gamma.T*J*Gamma,J)
Ejemplo n.º 7
0
    def test_symplectic(self):
        # the symmetric transformation matrix should be symplectic
        Pa = self.atrott
        Pb = self.btrott
        R = involution_matrix(Pa, Pb)
        S = integer_kernel_basis(R)
        N1 = N1_matrix(Pa, Pb, S)
        H, Q = symmetric_block_diagonalize(N1)
        Gamma = symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=1e-4)
        g, g = Pa.dimensions()
        J = zero_matrix(ZZ, 2 * g, 2 * g)
        Ig = identity_matrix(ZZ, g, g)
        J[:g, g:] = Ig
        J[g:, :g] = -Ig
        self.assertEqual(Gamma.T * J * Gamma, J)

        Pa = self.aklein
        Pb = self.bklein
        R = involution_matrix(Pa, Pb, tol=1e-3)
        S = integer_kernel_basis(R)
        N1 = N1_matrix(Pa, Pb, S)
        H, Q = symmetric_block_diagonalize(N1)
        Gamma = symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=1e-3)
        g, g = Pa.dimensions()
        J = zero_matrix(ZZ, 2 * g, 2 * g)
        Ig = identity_matrix(ZZ, g, g)
        J[:g, g:] = Ig
        J[g:, :g] = -Ig
        self.assertEqual(Gamma.T * J * Gamma, J)

        Pa = self.afermat
        Pb = self.bfermat
        R = involution_matrix(Pa, Pb, tol=1e-3)
        S = integer_kernel_basis(R)
        N1 = N1_matrix(Pa, Pb, S)
        H, Q = symmetric_block_diagonalize(N1)
        Gamma = symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=1e-3)
        g, g = Pa.dimensions()
        J = zero_matrix(ZZ, 2 * g, 2 * g)
        Ig = identity_matrix(ZZ, g, g)
        J[:g, g:] = Ig
        J[g:, :g] = -Ig
        self.assertEqual(Gamma.T * J * Gamma, J)

        Pa = self.a6
        Pb = self.b6
        R = involution_matrix(Pa, Pb)
        S = integer_kernel_basis(R)
        N1 = N1_matrix(Pa, Pb, S)
        H, Q = symmetric_block_diagonalize(N1)
        Gamma = symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=1e-4)
        g, g = Pa.dimensions()
        J = zero_matrix(ZZ, 2 * g, 2 * g)
        Ig = identity_matrix(ZZ, g, g)
        J[:g, g:] = Ig
        J[g:, :g] = -Ig
        self.assertEqual(Gamma.T * J * Gamma, J)
Ejemplo n.º 8
0
def tau_2_v(robot,tau,g=None):
    Dg = robot._D_grav_2_zero()
    if Dg:
        v = tau.subs( dict( utils.subsm(robot.ddq,zero_matrix(robot.dof,1 )).items() + Dg.items() ) )
    else:
        if not g:
            raise Exception('tau_2_v: needs the g parameter')
        v = tau.subs( dict( utils.subsm(robot.ddq,zero_matrix(robot.dof,1 )) ) ) - g
    return v
def cp_d_law(x, dd):
    try:
        d = dd[0]
    except TypeError:
        d = dd
    if d == 0:
        return zero_matrix(QQ, 1, len(x))
    if d == 1:
        return zero_matrix(QQ, len(x), max(0, len(x) - 1))
    if d == 2:
        return zero_matrix(max(0, len(x) - 1), 0)
    if d >= 3:
        return zero_matrix(QQ, 0, 0)
Ejemplo n.º 10
0
  def gen_geom(self):
    
    self.Tdhi = range(self.dof+1)
    self.Tdhi[0] = identity_matrix(SR,4 )
    self.Tdhi_inv = range(self.dof+1)
    self.Tdhi_inv[0] = identity_matrix(SR,4 )
    self.Rdhi = range(self.dof+1 )
    self.Rdhi[0] = identity_matrix(SR,3 )
    self.pdhi = range(self.dof+1 )
    self.pdhi[0] = zero_matrix(SR,3,1 )
    self.pdhfi = range(self.dof+1 )
    self.pdhfi[0] = zero_matrix(SR,3,1 )
    
    p_dhf =  ( self.T_dh[0 :3 ,0 :3 ].transpose() * self.T_dh[0 :3 ,3 ] ).simplify_trig()
    
    T_dh_inv = utils.inverse_T(self.T_dh).simplify_trig()
    
    for l in range(self.dof):
      
      D = utils.LoP_to_D(zip(self.params_dh , self.links_dh[l]))
      
      self.Tdhi[l+1] = self.T_dh.subs(D)
      self.Tdhi_inv[l+1] = T_dh_inv.subs(D)
      self.Rdhi[l+1] = self.Tdhi[l+1][0 :3 ,0 :3 ]
      self.pdhi[l+1] = self.Tdhi[l+1][0 :3 ,3 ]
      self.pdhfi[l+1] = p_dhf.subs(D)
    
    self.Ti = range(self.dof+1 )
    self.Ti[0] = identity_matrix(SR,4 )
    
    for l in range(1 , self.dof+1 ):
      
      self.Ti[l] = self.Ti[l-1 ] *  self.Tdhi[l]
          
      #Ti[l] = Ti[l].simplify_rational()
      #Ti[l] = trig_reduce(Ti[l])
      #Ti[l] = Ti[l].simplify()
    
    self.Ri = range(0 ,self.dof+1 )
    self.pi = range(0 ,self.dof+1 )
    self.zi = range(0 ,self.dof+1 )
    
    for l in range(0 ,self.dof+1 ):
      self.Ri[l] = self.Ti[l][0 :3 ,0 :3 ]
      self.pi[l] = self.Ti[l][0 :3 ,3 ]
      self.zi[l] = self.Ri[l][0 :3 ,2 ]

    return self
 def generic_prod_mat(dim_tuple):
     if dim_tuple in gen_prod_mat:
         return gen_prod_mat[dim_tuple]
     k = len(dim_tuple)
     first_column = zero_matrix(ZZ, k, 1)
     last_column = matrix(ZZ, k, 1, [d for d in dim_tuple])
     # If dim_list is all zeros, then return a single matrix of zeros.
     if first_column == last_column:
         return [first_column]
     current_batch = [first_column]
     next_batch = []
     gpms = []
     while len(current_batch) != 0:
         for m in current_batch:
             l = m.ncols()
             next_column_options = [range(m[r, l - 1], min(m[r, l - 1] + 2, dim_tuple[r] + 1)) for r in range(k)]
             new_column_iterator = itertools.product(*next_column_options)
             # we don't want the same column again.
             drop = next(new_column_iterator)
             for next_column_tuple in new_column_iterator:
                 next_column = matrix(ZZ, k, 1, next_column_tuple)
                 mm = block_matrix([[m, matrix(ZZ, k, 1, next_column)]], subdivide=False)
                 if next_column == last_column:
                     gpms += [mm]
                 else:
                     next_batch += [mm]
         current_batch = next_batch
         next_batch = []
     gen_prod_mat[dim_tuple] = gpms
     return gpms
Ejemplo n.º 12
0
def adjdual(g, h):
    from sage.all import block_matrix, zero_matrix
    wg = g[0:3, 0]
    vg = g[3:6, 0]
    return block_matrix(
        [[skew(wg), zero_matrix(3, 3)], [skew(vg), skew(wg)]],
        subdivide=False).transpose() * h
Ejemplo n.º 13
0
def symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=1e-4):
    r"""Returns the symplectic matrix `\Gamma` mapping the period matrices `Pa,Pb`
    to a symmetric period matrices.

    A helper function to :func:`symmetrize_periods`.

    Parameters
    ----------
    Pa : complex matrix
        A `g x g` a-period matrix.
    Pb : complex matrix
        A `g x g` b-period matrix.
    S : integer matrix
        Integer kernel basis matrix.
    H : integer matrix
        Topological type classification matrix.
    Q : integer matrix
        The transformation matrix from `symmetric_block_diagonalize`.
    tol : double
        (Default: 1e-4) Tolerance used to verify integrality of intermediate
        matrices. Dependent on precision of period matrices.

    Returns
    -------
    Gamma : integer matrix
        A `2g x 2g` symplectic matrix.
    """
    # compute A and B
    g,g = Pa.dimensions()
    rhs = S*Q.change_ring(ZZ)
    A = rhs[:g,:g].T
    B = rhs[g:,:g].T
    H = H.change_ring(ZZ)

    # compute C and D
    half = QQ(1)/QQ(2)
    temp = (A*Re(Pa) + B*Re(Pb)).inverse()
    CT = half*A.T*H - Re(Pb)*temp
    CT_ZZ = CT.round().change_ring(ZZ)
    C = CT_ZZ.T

    DT = half*B.T*H + Re(Pa)*temp
    DT_ZZ = DT.round().change_ring(ZZ)
    D = DT_ZZ.T

    # sanity checks: make sure C and D are integral
    C_error = (CT.round() - CT).norm()
    D_error = (DT.round() - DT).norm()
    if (C_error > tol) or (D_error > tol):
        raise ValueError("The symmetric transformation matrix is not integral. "
                         "Try increasing the precision of the input period "
                         "matrices.")

    # construct Gamma
    Gamma = zero_matrix(ZZ, 2*g, 2*g)
    Gamma[:g,:g] = A
    Gamma[:g,g:] = B
    Gamma[g:,:g] = C
    Gamma[g:,g:] = D
    return Gamma
Ejemplo n.º 14
0
def kalmanson_matrix(n, aug=False):
    r,c = triu_indices(n, 1)
    k = len(r)
    inds = np.arange(k)
    row_ind = lambda (i,j): inds[np.logical_and(r==i-1, c==j-1)]
    upright = lambda (i,j): (i,j) if i<j else (j,i)
    get_ind = lambda ind_lst: np.array(map(row_ind, map(upright, grouper(2, ind_lst))))

    rows = []
    for i in range(1,n-2):
        for j in range(i+2, n):
            ind_lst = (i, j+1, i+1, j, i, j, i+1, j+1)
            indices = get_ind(ind_lst)
            row = np.zeros(k, dtype=np.int)
            row[indices] = [-1, -1, 1, 1]           
            rows.append(row)

    sub = len(rows)

    for i in range(2, n-1):
        ind_lst = (i, 1, i+1, n, i, n, i+1, 1)
        indices = get_ind(ind_lst)
        row = np.zeros(k, dtype=np.int)
        row[indices] = [-1, -1, 1, 1]           
        rows.append(row)

    mat = matrix(np.vstack(rows))
    mat.subdivide(sub, None)
    if aug:
        return zero_matrix(len(rows),1).augment(mat)
    else:
        return mat
Ejemplo n.º 15
0
def gen_gravterm_EL(robot, potential_energy=None):
    U = potential_energy if potential_energy else gen_potential_energy(robot)
    from copy import copy
    g = copy(zero_matrix(SR, robot.dof, 1))
    for i in range(0, robot.dof):
        g[i, 0] = U.derivative(robot.q[i, 0])
    return g
Ejemplo n.º 16
0
def gen_massmatrix_RNE( do_varify, rbt, usemotordyn = True, varify_trig = True ):
  
    from copy import deepcopy
    
    Si = _gen_rbt_Si(rbt)
    
    IIi = range(0,rbt.dof+1)
    ### Linear dynamic parameters:
    for i in range(1,rbt.dof+1): IIi[i] = block_matrix( [ rbt.Ifi[i] , skew(rbt.mli[i]) , -skew(rbt.mli[i]) , rbt.mi[i]*identity_matrix(3) ] ,subdivide=False)
    ### Not linear dynamic parameters:
    #for i in range(1,dof+1): IIi[i] = block_matrix( [ rbt.Ifi_from_Ici[i] , skew(rbt.mli_e[i]) , -skew(rbt.mli_e[i]) , rbt.mi[i]*identity_matrix(3) ] ,subdivide=False)
    
    def custom_simplify( expression ):
        #return trig_reduce(expression.expand()).simplify_rational()
        return expression.simplify_rational()
    
    varify_func = None
    
    if do_varify:
        auxvars = []
        def varify_func(exp,varrepr):
            if varify_trig : exp = exp.subs( LoP_to_D(rbt.LoP_trig_f2v) )
            exp = custom_simplify( exp )
            return m_varify(exp, auxvars, poolrepr='auxM', condition_func=is_compound)
    
    M = matrix(SR,rbt.dof,rbt.dof)
    
    rbttmp = deepcopy(rbt)
    rbttmp.grav = zero_matrix(3,1)
    rbttmp.dq = zero_matrix(rbttmp.dof,1)
    
    for i in range(M.nrows()):
        rbttmp.ddq = zero_matrix(rbttmp.dof,1)
        rbttmp.ddq[i,0] = 1.0
        rbttmp.gen_geom()
        
        Vi, dVi = _forward_RNE( rbttmp, Si, varify_func )
        Mcoli = _backward_RNE( rbttmp, IIi, Si, Vi, dVi, usemotordyn, None, varify_func = varify_func )
        
        # Do like this since M is symmetric:
        M[:,i] = matrix(SR,i,1,M[i,:i].list()).stack( Mcoli[i:,:] )
    
    if do_varify:
        if varify_trig : auxvars = rbt.LoP_trig_v2f + auxvars
        return auxvars , M
    else:
        return M
Ejemplo n.º 17
0
def _backward_RNE( rbt, IIi, Si, Vi, dVi, usemotordyn=True, Imzi=None, varify_func=None ) :
  
    from copy import copy
    
    dof = rbt.dof
    Tdhi_inv = copy(rbt.Tdhi_inv)
    Tdhi_inv.append(identity_matrix(4))
    
    Fi = range(0,dof+2)
    tau = matrix(SR,dof,1)
    
    Fi[dof+1] = copy(zero_matrix(SR,6,1))

    if usemotordyn:
      nfi_motor = [zero_matrix(3,1) for i in xrange(dof+1)]
      for mi,m in enumerate(rbt.motors):
        if Imzi == None: Im = m[0]
        else: Im = Imzi[mi]
        qm = m[1]; l = m[2]; zm = m[3]
        dqm = qm.subs(rbt.D_q_v2f).derivative(rbt.t).subs(rbt.D_q_f2v)
        ddqm = dqm.subs(rbt.D_q_v2f).derivative(rbt.t).subs(rbt.D_q_f2v)
        nfi_motor[l] += ddqm * Im * zm + dqm * Im * cross_product( Vi[l][:3,:] , zm )
    
    # Backward
    for i in range(dof,0,-1):
        Fi[i] =  Adjdual( Tdhi_inv[i+1], Fi[i+1] )  +  IIi[i] * dVi[i]  -  adjdual( Vi[i],  IIi[i] * Vi[i] )

        if usemotordyn:
          Fi[i][:3,:] += nfi_motor[i]
        
        if varify_func: Fi[i] = varify_func( Fi[i] , 'F_'+str(i) )
        
        tau[i-1,0] =  ( Si[i].transpose() *  Fi[i] )[0,0]

        if usemotordyn:
          for mi,m in enumerate(rbt.motors):
            if Imzi == None: Im = m[0]
            else: Im = Imzi[mi]
            qm = m[1]; l = m[2]; zm = m[3]
            dqm = qm.subs(rbt.D_q_v2f).derivative(rbt.t).subs(rbt.D_q_f2v)
            ddqm = dqm.subs(rbt.D_q_v2f).derivative(rbt.t).subs(rbt.D_q_f2v)
            km = qm.coeff(rbt.q[i-1,0])
            if km != 0.0:
              tau[i-1,0] += km * Im * ( ( dVi[l][:3,:] + ddqm * zm + dqm * cross_product( Vi[l][:3,:], zm ) ).transpose() * zm )[0,0]
    
    return tau
Ejemplo n.º 18
0
def sympytosage(sm):
    from copy import copy
    from sage.all import zero_matrix, SR
    m = copy(zero_matrix(SR, sm.shape[0], sm.shape[1]))
    for i in range(m.nrows()):
        for j in range(m.ncols()):
            m[i, j] = sm[i, j]._sage_()
    return m
Ejemplo n.º 19
0
def symmetrize_periods(Pa, Pb, tol=1e-4):
    r"""Returns symmetric a- and b-periods `Pa_symm` and `Pb_symm`, as well as the
    corresponding symplectic operator `Gamma` such that `Gamma [Pa \\ Pb] =
    [Pa_symm \\ Pb_symm]`.

    Parameters
    ----------
    Pa : complex matrix
    Pb : complex matrix
        The a- and b-periods, respectively, of a genus `g` Riemann surface.
    tol : double
        (Default: 1e-4) Tolerance used to verify integrality of intermediate
        matrices. Dependent on precision of period matrices.

    Returns
    -------
    Gamma : integer matrix
        The symplectic transformation operator.
    Pa : complex matrix
    Pb : complex matrix
        Symmetric a- and b-periods, respectively, of a genus `g` Riemann surface.

    Notes
    -----
    The algorithm described in Kalla, Klein actually operates on the transposes
    of the a- and b-period matrices.
    """
    # coerce from numpy, if necessary
    if isinstance(Pa, numpy.ndarray):
        Pa = Matrix(CDF, numpy.ascontiguousarray(Pa))
    if isinstance(Pb, numpy.ndarray):
        Pb = Matrix(CDF, numpy.ascontiguousarray(Pb))

    # use the transposes of the period matrices and coerce to Sage matrices
    Pa = Pa.T
    Pb = Pb.T

    # use above functions to obtain topological type matrix
    g, g = Pa.dimensions()
    R = involution_matrix(Pa, Pb, tol=tol)
    S = integer_kernel_basis(R)
    N1 = N1_matrix(Pa, Pb, S, tol=tol)
    H, Q = symmetric_block_diagonalize(N1)
    Gamma = symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=tol)

    # compute the corresponding symmetric periods
    stacked_periods = zero_matrix(CDF, 2 * g, g)
    stacked_periods[:g, :] = Pa
    stacked_periods[g:, :] = Pb
    stacked_symmetric_periods = Gamma * stacked_periods
    Pa_symm = stacked_symmetric_periods[:g, :]
    Pb_symm = stacked_symmetric_periods[g:, :]

    # transpose results back
    Pa_symm = Pa_symm.T
    Pb_symm = Pb_symm.T
    return Pa_symm, Pb_symm
Ejemplo n.º 20
0
def symmetrize_periods(Pa, Pb, tol=1e-4):
    r"""Returns symmetric a- and b-periods `Pa_symm` and `Pb_symm`, as well as the
    corresponding symplectic operator `Gamma` such that `Gamma [Pa \\ Pb] =
    [Pa_symm \\ Pb_symm]`.

    Parameters
    ----------
    Pa : complex matrix
    Pb : complex matrix
        The a- and b-periods, respectively, of a genus `g` Riemann surface.
    tol : double
        (Default: 1e-4) Tolerance used to verify integrality of intermediate
        matrices. Dependent on precision of period matrices.

    Returns
    -------
    Gamma : integer matrix
        The symplectic transformation operator.
    Pa : complex matrix
    Pb : complex matrix
        Symmetric a- and b-periods, respectively, of a genus `g` Riemann surface.

    Notes
    -----
    The algorithm described in Kalla, Klein actually operates on the transposes
    of the a- and b-period matrices.
    """
    # coerce from numpy, if necessary
    if isinstance(Pa, numpy.ndarray):
        Pa = Matrix(CDF, numpy.ascontiguousarray(Pa))
    if isinstance(Pb, numpy.ndarray):
        Pb = Matrix(CDF, numpy.ascontiguousarray(Pb))

    # use the transposes of the period matrices and coerce to Sage matrices
    Pa = Pa.T
    Pb = Pb.T

    # use above functions to obtain topological type matrix
    g,g = Pa.dimensions()
    R = involution_matrix(Pa, Pb, tol=tol)
    S = integer_kernel_basis(R)
    N1 = N1_matrix(Pa, Pb, S, tol=tol)
    H,Q = symmetric_block_diagonalize(N1)
    Gamma = symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=tol)

    # compute the corresponding symmetric periods
    stacked_periods = zero_matrix(CDF, 2*g, g)
    stacked_periods[:g,:] = Pa
    stacked_periods[g:,:] = Pb
    stacked_symmetric_periods = Gamma*stacked_periods
    Pa_symm = stacked_symmetric_periods[:g,:]
    Pb_symm = stacked_symmetric_periods[g:,:]

    # transpose results back
    Pa_symm = Pa_symm.T
    Pb_symm = Pb_symm.T
    return Pa_symm, Pb_symm
Ejemplo n.º 21
0
def gen_regressor_RNE( do_varify, rbt, usemotordyn = True, usefricdyn = True, varify_trig = True ):
  
    from copy import copy
    
    Si = _gen_rbt_Si(rbt)

    if usefricdyn:
      fric = gen_Dyn_fricterm(rbt)
    
    def custom_simplify( expression ):
        #return trig_reduce(expression.expand()).simplify_rational()
        return expression.simplify_rational()
    
    varify_func = None
    
    if do_varify:
        auxvars = []
        def varify_func(exp,varrepr):
            if varify_trig : exp = exp.subs( LoP_to_D(rbt.LoP_trig_f2v) )
            exp = custom_simplify( exp )
            return m_varify(exp, auxvars, poolrepr='auxY', condition_func=is_compound)
    
    
    Vi, dVi = _forward_RNE( rbt, Si, varify_func )
    
    P = rbt.Parms(usemotordyn,usefricdyn)
    
    Y = matrix(SR,rbt.dof,P.nrows())
    
    for p in range(P.nrows()) :
        
        select =  subsm( P, zero_matrix(P.nrows(),1) )
        select.update( {P[p,0]:Integer(1)} )
        
        IIi = range(0,rbt.dof+1)
        for i in range(1,rbt.dof+1):
            IIi[i] = block_matrix( [ rbt.Ifi[i].subs(select) , skew(rbt.mli[i].subs(select)) , -skew(rbt.mli[i].subs(select)) , rbt.mi[i].subs(select)*identity_matrix(3) ] ,subdivide=False)
        
        if usemotordyn:
          Imzi = deepcopy(rbt.Imzi)
          for i,Im in enumerate(Imzi):
            Imzi[i] = Im.subs(select)
        else:
          Imzi = None
      
        Y[:,p] = _backward_RNE( rbt, IIi, Si, Vi, dVi, usemotordyn, Imzi, varify_func )
        
        if usefricdyn:
          Y[:,p] += fric.subs(select)
    
    if do_varify:
        if varify_trig : auxvars = rbt.LoP_trig_v2f + auxvars
        return auxvars , Y
    else:
        return Y
Ejemplo n.º 22
0
def _forward_RNE( rbt, Si, varify_func=None ):
  
    from copy import copy
    
    dof = rbt.dof
    
    Vi = range(0,dof+1)
    dVi = range(0,dof+1)
    
    Vi[0] = copy(zero_matrix(SR,6,1))
    dVi[0] = - zero_matrix(SR,3,1).stack( rbt.grav )
    
    # Forward
    for i in range(1,dof+1):
        Vi[i] =  Adj( rbt.Tdhi_inv[i], Vi[i-1] )  +  Si[i] * rbt.dq[i-1,0]
        if varify_func: Vi[i] = varify_func( Vi[i] , 'V_'+str(i) )
        
        dVi[i] =  Si[i] * rbt.ddq[i-1,0]  +  Adj( rbt.Tdhi_inv[i], dVi[i-1] )  +  adj(  Adj( rbt.Tdhi_inv[i], Vi[i-1] ),  Si[i] * rbt.dq[i-1,0] )
        if varify_func: dVi[i] = varify_func( dVi[i] , 'dV_'+str(i) )

    return Vi, dVi
Ejemplo n.º 23
0
def _gen_ccfmatrix_EL(robot, massmatrix=None, usemotordyn=True):
    M = massmatrix if massmatrix else gen_massmatrix_EL(robot, usemotordyn)
    from copy import copy
    C = copy(zero_matrix(SR, robot.dof, robot.dof))
    for i, j in [(i, j) for i in range(robot.dof) for j in range(robot.dof)]:
        C[i, j] = 0
        for k in range(robot.dof):
            C[i, j] += 1.0 / 2.0 * (
                M[i, j].derivative(robot.q[k, 0]) +
                M[i, k].derivative(robot.q[j, 0]) -
                M[j, k].derivative(robot.q[i, 0])) * robot.dq[k, 0]
    return C
Ejemplo n.º 24
0
def _gen_massmatrix_EL(robot, usemotordyn=True):
    print "Warning: result uses elementary dynamic parameters (opposed to grouped parameters to which dynamic model is linear)."
    if usemotordyn:
        raise Exception(
            'gen_massmatrix_EL has no implementation for usemotordyn=True yet')
    from copy import copy
    M = copy(zero_matrix(SR, robot.dof, robot.dof))
    for i in range(1, robot.dof + 1):
        M = M + robot.mi[i] * robot.Jcpi[i].transpose(
        ) * robot.Jcpi[i] + robot.Jcoi[i].transpose() * robot.Ri[
            i] * robot.Ici[i] * robot.Ri[i].transpose() * robot.Jcoi[i]
    #for i in range(1 ,robot.dof+1 ):
    #M = M + robot.mi[i]*robot.Jcpi[i].transpose()*robot.Jcpi[i] + robot.Jcoi[i].transpose()*robot.Ri[i]*( robot.Ifi[i] - robot.mi[i] * utils.skew( robot.Ri[i]*robot.li[i] ).transpose() * utils.skew( robot.Ri[i]*robot.li[i] )  )*robot.Ri[i].transpose()*robot.Jcoi[i]
    return M
Ejemplo n.º 25
0
def tau_2_M(robot,tau,g=None):
    from sage.all import zero_matrix, SR
    from copy import copy
    M = copy(zero_matrix(SR,robot.dof,robot.dof))
    Dg = robot._D_grav_2_zero()
    if Dg:
        for i in range(0 ,robot.dof) :
            M[:,i] = tau( dict( utils.subsm( robot.ddq , identity_matrix(robot.dof)[:,i] ).items() + utils.subsm( robot.dq , zero_matrix(robot.dof,1 ) ).items() + Dg.items()  ) )
    else:
        if not g:
            raise Exception('tau_2_M: needs the g parameter')
        for i in range(0 ,robot.dof) :
            M[:,i] = tau( dict( utils.subsm( robot.ddq , identity_matrix(robot.dof)[:,i] ).items() + utils.subsm( robot.dq , zero_matrix(robot.dof,1 ) ).items()  ) ) - g
    return M
Ejemplo n.º 26
0
def QuadraticForm_from_quadric(Q):
    """
    On input a homogeneous polynomial of degree 2 return the Quadratic Form corresponding to it.
    """
    R = Q.parent()
    assert all([sum(e)==2 for e in Q.exponents()])
    M = copy(zero_matrix(R.ngens(),R.ngens()))
    for i in range(R.ngens()):
        for j in range(R.ngens()):
            if i==j:
                M[i,j]=2*Q.coefficient(R.gen(i)*R.gen(j))
            else:
                M[i,j]=Q.coefficient(R.gen(i)*R.gen(j))
   
    return QuadraticForm(M)
Ejemplo n.º 27
0
        def compute_R(Gamma, H):
            H = H.change_ring(ZZ)
            g,g = H.dimensions()
            A = Gamma[:g,:g]
            B = Gamma[:g,g:]
            C = Gamma[g:,:g]
            D = Gamma[g:,g:]
            Ig = identity_matrix(ZZ,g)

            R = zero_matrix(ZZ,2*g,2*g)
            R[:g,:g] = (2*C.T*B - A.T*H*B + Ig).T
            R[:g,g:] = 2*D.T*B - B.T*H*B
            R[g:,:g] = -2*C.T*A + A.T*H*A
            R[g:,g:] = -(2*C.T*B - A.T*H*B + Ig)
            return R
Ejemplo n.º 28
0
        def compute_R(Gamma, H):
            H = H.change_ring(ZZ)
            g, g = H.dimensions()
            A = Gamma[:g, :g]
            B = Gamma[:g, g:]
            C = Gamma[g:, :g]
            D = Gamma[g:, g:]
            Ig = identity_matrix(ZZ, g)

            R = zero_matrix(ZZ, 2 * g, 2 * g)
            R[:g, :g] = (2 * C.T * B - A.T * H * B + Ig).T
            R[:g, g:] = 2 * D.T * B - B.T * H * B
            R[g:, :g] = -2 * C.T * A + A.T * H * A
            R[g:, g:] = -(2 * C.T * B - A.T * H * B + Ig)
            return R
Ejemplo n.º 29
0
def QuadraticForm_from_quadric(Q):
    """
    On input a homogeneous polynomial of degree 2 return the Quadratic Form corresponding to it.
    """
    R = Q.parent()
    assert all([sum(e)==2 for e in Q.exponents()])
    M = copy(zero_matrix(R.ngens(),R.ngens()))
    for i in range(R.ngens()):
        for j in range(R.ngens()):
            if i==j:
                M[i,j]=2*Q.coefficient(R.gen(i)*R.gen(j))
            else:
                M[i,j]=Q.coefficient(R.gen(i)*R.gen(j))
   
    return QuadraticForm(M)
Ejemplo n.º 30
0
def parm_identbase(Y,P):
    from sage.all import zero_matrix
    
    m = Y.nrows()
    n = P.nrows()
    
    nonzerol = range(0,n)
    for i in range(0,n) :
    #if Y[:,i].is_zero() :
        if bool(Y[:,i] == zero_matrix(m,1)) :
            nonzerol.remove(i)
    
    PB = P[nonzerol,:]
    YB = Y[:,nonzerol]
    
    return YB,PB
def prep_cmb_row((i, n, pmt, nn_to_pm, prod_mats, pm_to_nn)):
    row = zero_matrix(ZZ, 1, pmt)
    p_cols = nn_to_pm[i].columns()
    for j in range(i + 1, pmt):
        q = nn_to_pm[j]
        both_cols = list(set(p_cols + q.columns()))
        both_cols.sort()
        combined = block_matrix([[matrix(ZZ, n, 1, list(v)) for v in both_cols]], subdivide=False)
        combined.set_immutable()
        if combined in prod_mats:
            row[0, j] = pm_to_nn[combined]
        else:
            row[0, j] = -1
    if verbose:
        if i % 100 == 0:
            print 'Finished row ' + str(i)
    return [row]
Ejemplo n.º 32
0
def N1_matrix(Pa, Pb, S, tol=1e-4):
    r"""Returns the matrix `N1` from the integer kernel of the anti-holomorphic
    involution matrix.

    This matrix `N1` is used directly to determine the topological type of a
    Riemann surface. Used as input in `symmetric_block_diagonalize`.

    Paramters
    ---------
    S : integer matrix
        A `2g x g` Z-basis of the kernel of the anti-holomorphic involution.
        (See `integer_kernel_basis`.)
    tol : double
        (Default: 1e-4) Tolerance used to veryify integrality of the matrix.
        Dependent on precision of period matrices.

    Returns
    -------
    N1 : GF(2) matrix
        A `g x g` matrix from which we can compute the topological type.

    """
    # compute the Smith normal form of S, itself
    g = S.ncols()
    S1 = S[:g,:]
    S2 = S[g:,:]
    ES, US, VS = S.smith_form()

    # construct the matrix N1 piece by piece
    Nper = zero_matrix(RDF, 2*g,g)
    Nper[:g,:] = -Re(Pb)[:,:]
    Nper[g:,:] = Re(Pa)[:,:]
    Nhat = (S1.T*Re(Pa) + S2.T*Re(Pb)).inverse()
    Ntilde = 2*US*Nper*Nhat
    N1_RDF = VS*Ntilde[:g,:]
    N1 = N1_RDF.round().change_ring(GF(2))

    # sanity check: N1 should be integral
    error = (N1_RDF.round() - N1_RDF).norm()
    if error > tol:
        raise ValueError("The N1 matrix is not integral. Try increasing the "
                         "precision of the input period matrices.")
    return N1
Ejemplo n.º 33
0
def N1_matrix(Pa, Pb, S, tol=1e-4):
    r"""Returns the matrix `N1` from the integer kernel of the anti-holomorphic
    involution matrix.

    This matrix `N1` is used directly to determine the topological type of a
    Riemann surface. Used as input in `symmetric_block_diagonalize`.

    Paramters
    ---------
    S : integer matrix
        A `2g x g` Z-basis of the kernel of the anti-holomorphic involution.
        (See `integer_kernel_basis`.)
    tol : double
        (Default: 1e-4) Tolerance used to veryify integrality of the matrix.
        Dependent on precision of period matrices.

    Returns
    -------
    N1 : GF(2) matrix
        A `g x g` matrix from which we can compute the topological type.

    """
    # compute the Smith normal form of S, itself
    g = S.ncols()
    S1 = S[:g, :]
    S2 = S[g:, :]
    ES, US, VS = S.smith_form()

    # construct the matrix N1 piece by piece
    Nper = zero_matrix(RDF, 2 * g, g)
    Nper[:g, :] = -Re(Pb)[:, :]
    Nper[g:, :] = Re(Pa)[:, :]
    Nhat = (S1.T * Re(Pa) + S2.T * Re(Pb)).inverse()
    Ntilde = 2 * US * Nper * Nhat
    N1_RDF = VS * Ntilde[:g, :]
    N1 = N1_RDF.round().change_ring(GF(2))

    # sanity check: N1 should be integral
    error = (N1_RDF.round() - N1_RDF).norm()
    if error > tol:
        raise ValueError("The N1 matrix is not integral. Try increasing the " "precision of the input period matrices.")
    return N1
Ejemplo n.º 34
0
 def _convert_kappa_basis(self,r):
     """
     Returns a matrix that when multiplied on the right of the FZ_matrix with pushforward of psi basis will give the FZ_matrix for the kappa monomial basis.
     """
     M = zero_matrix(len(self._dstrata[r]))
     for Gind,G in enumerate(self._dstrata[r].keys()):
         #print G
         #Gf = forget_decorations(G)
         R, kappa = PsiKappaVars(G,kappa_only = True)
         kappa_dec = 1
         for v in range(1, G.num_vertices()+1):
             #print kappa, G.M[v,0]
             kappa_dec *= X_to_kappa(G.M[v,0],lambda a: kappa[(a,v)])
             #print G.M[v,0], X_to_kappa(G.M[v,0],lambda a: kappa[(a,v)])
         
         #print "kd", kappa_dec
         if kappa_dec == 1:
             M[Gind,Gind] = 1
         else:
             for mon, coef in kappa_dec.dict().items():
                 Gd = decorate_with_monomial(R, G.forget_kappas(), mon)
                 M[Gind, self._dstrata[r][Gd]] += coef
             
     return M #.transpose()
Ejemplo n.º 35
0
def symmetric_transformation_matrix(Pa, Pb, S, H, Q, tol=1e-4):
    r"""Returns the symplectic matrix `\Gamma` mapping the period matrices `Pa,Pb`
    to a symmetric period matrices.

    A helper function to :func:`symmetrize_periods`.

    Parameters
    ----------
    Pa : complex matrix
        A `g x g` a-period matrix.
    Pb : complex matrix
        A `g x g` b-period matrix.
    S : integer matrix
        Integer kernel basis matrix.
    H : integer matrix
        Topological type classification matrix.
    Q : integer matrix
        The transformation matrix from `symmetric_block_diagonalize`.
    tol : double
        (Default: 1e-4) Tolerance used to verify integrality of intermediate
        matrices. Dependent on precision of period matrices.

    Returns
    -------
    Gamma : integer matrix
        A `2g x 2g` symplectic matrix.
    """
    # compute A and B
    g, g = Pa.dimensions()
    rhs = S * Q.change_ring(ZZ)
    A = rhs[:g, :g].T
    B = rhs[g:, :g].T
    H = H.change_ring(ZZ)

    # compute C and D
    half = QQ(1) / QQ(2)
    temp = (A * Re(Pa) + B * Re(Pb)).inverse()
    CT = half * A.T * H - Re(Pb) * temp
    CT_ZZ = CT.round().change_ring(ZZ)
    C = CT_ZZ.T

    DT = half * B.T * H + Re(Pa) * temp
    DT_ZZ = DT.round().change_ring(ZZ)
    D = DT_ZZ.T

    # sanity checks: make sure C and D are integral
    C_error = (CT.round() - CT).norm()
    D_error = (DT.round() - DT).norm()
    if (C_error > tol) or (D_error > tol):
        raise ValueError(
            "The symmetric transformation matrix is not integral. "
            "Try increasing the precision of the input period "
            "matrices."
        )

    # construct Gamma
    Gamma = zero_matrix(ZZ, 2 * g, 2 * g)
    Gamma[:g, :g] = A
    Gamma[:g, g:] = B
    Gamma[g:, :g] = C
    Gamma[g:, g:] = D
    return Gamma
Ejemplo n.º 36
0
def symmetric_block_diagonalize(N1):
    r"""Returns matrices `H` and `Q` such that `N1 = Q*H*Q.T` and `H` is block
    diagonal.

    The algorithm used here is as follows. Whenever a row operation is
    performed (via multiplication on the left by a transformation matrix `q`)
    the corresponding symmetric column operation is also performed via
    multiplication on the right by `q^T`.

    For each column `j` of `N1`:

    1. If column `j` consists only of zeros then swap with the last column with
       non-zero entries.

    2. If there is a `1` in position `j` of the column (i.e. a `1` lies on the
       diagonal in this column) then eliminate further entries below as in
       standard Gaussian elimination.

    3. Otherwise, if there is a `1` in the column, but not in position `j` then
       rows are swapped in a way that it appears in the position `j+1` of the
       column. Eliminate further entries below as in standard Gaussian
       elimination.

    4. After elimination, if `1` lies on the diagonal in column `j` then
       increment `j` by one. If instead the block matrix `[0 1 \\ 1 0]` lies
       along the diagonal then eliminate under the `(j,j+1)` element (the upper
       right element) of this `2 x 2` block and increment `j` by two.

    5. Repeat until `j` passes the final column or until further columns
       consists of all zeros.

    6. Finally, perform the appropriate transformations such that all `2 x 2`
       blocks in `H` appear first in the diagonalization. (Uses the
       `diagonal_locations` helper function.)

    Parameters
    ----------
    N1 : GF(2) matrix

    Returns
    -------
    H : GF(2) matrix
        Symmetric `g x g` matrix where the diagonal elements consist of either
        a "1" or a `2 x 2` block matrix `[0 1 \\ 1 0]`.
    Q : GF(2) matrix
        The corresponding transformation matrix.
    """
    g = N1.nrows()
    H = zero_matrix(GF(2), g)
    Q = identity_matrix(GF(2), g)

    # if N1 is the zero matrix the H is also the zero matrix (and Q is the
    # identity transformation)
    if (N1 % 2) == 0:
        return H, Q

    # perform the "modified gaussian elimination"
    B = Matrix(GF(2), [[0, 1], [1, 0]])
    H = N1.change_ring(GF(2))
    j = 0
    while (j < g) and (H[:, j:] != 0):
        # if the current column is zero then swap with the last non-zero column
        if H.column(j) == 0:
            last_non_zero_col = max(k for k in range(j, g) if H.column(k) != 0)
            Q.swap_columns(j, last_non_zero_col)
            H = Q.T * N1 * Q

        # if the current diagonal element is 1 then gaussian eliminate as
        # usual. otherwise, swap rows so that a "1" appears in H[j+1,j] and
        # then eliminate from H[j+1,j]
        if H[j, j] == 1:
            rows_to_eliminate = (r for r in range(g) if H[r, j] == 1 and r != j)
            for r in rows_to_eliminate:
                Q.add_multiple_of_column(r, j, 1)
            H = Q.T * N1 * Q
        else:
            # find the first non-zero element in the column after the diagonal
            # element and swap rows with this element
            first_non_zero = min(k for k in range(j, g) if H[k, j] != 0)
            Q.swap_columns(j + 1, first_non_zero)
            H = Q.T * N1 * Q

            # eliminate *all* other ones in the column, including those above
            # the element (j,j+1)
            rows_to_eliminate = (r for r in range(g) if H[r, j] == 1 and r != j + 1)
            for r in rows_to_eliminate:
                Q.add_multiple_of_column(r, j + 1, 1)
            H = Q.T * N1 * Q

        # increment the column based on the diagonal element
        if H[j, j] == 1:
            j += 1
        elif H[j : (j + 2), j : (j + 2)] == B:
            # in the block diagonal case, need to eliminate below the j+1 term
            rows_to_eliminate = (r for r in range(g) if H[r, j + 1] == 1 and r != j)
            for r in rows_to_eliminate:
                Q.add_multiple_of_column(r, j, 1)
            H = Q.T * N1 * Q
            j += 2

    # finally, check if there are blocks of "special" form. that is, shift all
    # blocks such that they occur first along the diagonal of H
    index_one, index_B = diagonal_locations(H)
    while index_one < index_B:
        j = index_B

        Qtilde = zero_matrix(GF(2), g)
        Qtilde[0, 0] = 1
        Qtilde[j, 0] = 1
        Qtilde[j + 1, 0] = 1
        Qtilde[0, j] = 1
        Qtilde[0, j + 1] = 1
        Qtilde[j : (j + 2), j : (j + 2)] = B

        Q = Q * Qtilde
        H = Q.T * N1 * Q

        # continue until none are left
        index_one, index_B = diagonal_locations(H)

    # above, we used Q to store column operations on N1. switch to rows
    # operations on H so that N1 = Q*H*Q.T
    Q = Q.T.inverse()
    return H, Q
Ejemplo n.º 37
0
    def t1_prime(self, n=5, p=65521):
        """
        Return a multiple of element t1 of the Hecke algebra mod 2,
        computed using the Hecke operator $T_n$, where n is self.n.
        To make computation faster we only check if ...==0 mod p.
        Hence J will contain more elements, hence we get a multiple.
        
        INPUT:
        
            - `n` -- integer (optional default=5)
            - `p` -- prime (optional default=65521)

        OUTPUT:

            - a mod 2 matrix

        EXAMPLES::

            sage: from mdsage import *
            sage: C = KamiennyCriterion(29)
            sage: C.t1_prime()
            22 x 22 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries)
            sage: C.t1_prime(n=3) == 1
            True
            sage: C = KamiennyCriterion(37)
            sage: C.t1_prime()[0]
            (1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0)
        """
        if self.verbose: tm = cputime(); mem = get_memory_usage(); print "t1 start"
        T = self.S.hecke_matrix(n)
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "hecke 1"
        f = self.hecke_polynomial(n) # this is the same as T.charpoly()
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "char 1"
        Fint = f.factor()
        if all(i[1]!=1 for i in Fint):
            return matrix_modp(zero_matrix(T.nrows()))
        #    raise ValueError("T_%s needs to be a generator of the hecke algebra"%n)
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "factor 1, Fint = %s"%(Fint)
        R = f.parent().change_ring(GF(p))
        F = Fint.base_change(R)
        # Compute the iterators of T acting on the winding element.
        e = self.M([0, oo]).element().dense_vector().change_ring(GF(p))
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "wind"
        t = matrix_modp(self.M.hecke_matrix(n).dense_matrix(), p)
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "hecke 2"
        g = t.charpoly()
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "char 2"
        Z = t.iterates(e, t.nrows(), rows=True)
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "iter"
        # We find all factors F[i][0] for f such that
        # (g/F[i][0])(t) * e = 0.
        # We do this by computing the polynomial
        #       h = g/F[i][0],
        # turning it into a vector v, and computing
        # the matrix product v * Z.  If the product
        # is 0, then e is killed by h(t).
        J = []
        for i in range(len(F)):
            if F[i][1]!=1:
                J.append(i)
                continue
            h, r = g.quo_rem(F[i][0] ** F[i][1])
            assert r == 0
            v = vector(GF(p), h.padded_list(t.nrows()))
            if v * Z == 0:
                J.append(i)
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "zero check"

        if self.verbose: print "J =", J
        if len(J) == 0:
            # The annihilator of e is the 0 ideal.
            return matrix_modp(identity_matrix(T.nrows()))

        # Finally compute t1.  I'm concerned about how
        # long this will take, so we reduce T mod 2 first.

        # It is important to call "self.T(2)" to get the mod-2
        # reduction of T2 with respect to the right basis (e.g., the
        # integral basis in case use_integral_structure is true.
        Tmod2 = self.T(n)
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "hecke mod" 
        g = prod(Fint[i][0].change_ring(GF(2)) ** Fint[i][1] for i in J)
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "g has degree %s"%(g.degree())
        t1 = g(Tmod2)
        if self.verbose: print "time and mem", cputime(tm), get_memory_usage(mem), "t1 finnished"
        return t1        
Ejemplo n.º 38
0
def symmetric_block_diagonalize(N1):
    r"""Returns matrices `H` and `Q` such that `N1 = Q*H*Q.T` and `H` is block
    diagonal.

    The algorithm used here is as follows. Whenever a row operation is
    performed (via multiplication on the left by a transformation matrix `q`)
    the corresponding symmetric column operation is also performed via
    multiplication on the right by `q^T`.

    For each column `j` of `N1`:

    1. If column `j` consists only of zeros then swap with the last column with
       non-zero entries.

    2. If there is a `1` in position `j` of the column (i.e. a `1` lies on the
       diagonal in this column) then eliminate further entries below as in
       standard Gaussian elimination.

    3. Otherwise, if there is a `1` in the column, but not in position `j` then
       rows are swapped in a way that it appears in the position `j+1` of the
       column. Eliminate further entries below as in standard Gaussian
       elimination.

    4. After elimination, if `1` lies on the diagonal in column `j` then
       increment `j` by one. If instead the block matrix `[0 1 \\ 1 0]` lies
       along the diagonal then eliminate under the `(j,j+1)` element (the upper
       right element) of this `2 x 2` block and increment `j` by two.

    5. Repeat until `j` passes the final column or until further columns
       consists of all zeros.

    6. Finally, perform the appropriate transformations such that all `2 x 2`
       blocks in `H` appear first in the diagonalization. (Uses the
       `diagonal_locations` helper function.)

    Parameters
    ----------
    N1 : GF(2) matrix

    Returns
    -------
    H : GF(2) matrix
        Symmetric `g x g` matrix where the diagonal elements consist of either
        a "1" or a `2 x 2` block matrix `[0 1 \\ 1 0]`.
    Q : GF(2) matrix
        The corresponding transformation matrix.
    """
    g = N1.nrows()
    H = zero_matrix(GF(2), g)
    Q = identity_matrix(GF(2), g)

    # if N1 is the zero matrix the H is also the zero matrix (and Q is the
    # identity transformation)
    if (N1 % 2) == 0:
        return H,Q

    # perform the "modified gaussian elimination"
    B = Matrix(GF(2),[[0,1],[1,0]])
    H = N1.change_ring(GF(2))
    j = 0
    while (j < g) and (H[:,j:] != 0):
        # if the current column is zero then swap with the last non-zero column
        if H.column(j) == 0:
            last_non_zero_col = max(k for k in range(j,g) if H.column(k) != 0)
            Q.swap_columns(j,last_non_zero_col)
            H = Q.T*N1*Q

        # if the current diagonal element is 1 then gaussian eliminate as
        # usual. otherwise, swap rows so that a "1" appears in H[j+1,j] and
        # then eliminate from H[j+1,j]
        if H[j,j] == 1:
            rows_to_eliminate = (r for r in range(g) if H[r,j] == 1 and r != j)
            for r in rows_to_eliminate:
                Q.add_multiple_of_column(r,j,1)
            H = Q.T*N1*Q
        else:
            # find the first non-zero element in the column after the diagonal
            # element and swap rows with this element
            first_non_zero = min(k for k in range(j,g) if H[k,j] != 0)
            Q.swap_columns(j+1,first_non_zero)
            H = Q.T*N1*Q

            # eliminate *all* other ones in the column, including those above
            # the element (j,j+1)
            rows_to_eliminate = (r for r in range(g) if H[r,j] == 1 and r != j+1)
            for r in rows_to_eliminate:
                Q.add_multiple_of_column(r,j+1,1)
            H = Q.T*N1*Q

        # increment the column based on the diagonal element
        if H[j,j] == 1:
            j += 1
        elif H[j:(j+2),j:(j+2)] == B:
            # in the block diagonal case, need to eliminate below the j+1 term
            rows_to_eliminate = (r for r in range(g) if H[r,j+1] == 1 and r != j)
            for r in rows_to_eliminate:
                Q.add_multiple_of_column(r,j,1)
            H = Q.T*N1*Q
            j += 2

    # finally, check if there are blocks of "special" form. that is, shift all
    # blocks such that they occur first along the diagonal of H
    index_one, index_B = diagonal_locations(H)
    while index_one < index_B:
        j = index_B

        Qtilde = zero_matrix(GF(2), g)
        Qtilde[0,0] = 1
        Qtilde[j,0] = 1; Qtilde[j+1,0] = 1
        Qtilde[0,j] = 1; Qtilde[0,j+1] = 1
        Qtilde[j:(j+2),j:(j+2)] = B

        Q = Q*Qtilde
        H = Q.T*N1*Q

        # continue until none are left
        index_one, index_B = diagonal_locations(H)

    # above, we used Q to store column operations on N1. switch to rows
    # operations on H so that N1 = Q*H*Q.T
    Q = Q.T.inverse()
    return H,Q
Ejemplo n.º 39
0
def upper_bound_tate(cp, frob_matrix, precision, over_Qp=False, pedantic=True):
    """
    Return a upper bound for Tate classes over characteristic 0
    TODO: improove documentation
    """
    p = cp.list()[-1].prime_factors()[0]
    # it would be nice to use QpLF
    OK = ZpCA(p, prec=precision)

    # adjust precision
    frob_matrix = matrix(OK, frob_matrix)

    # get the p-adic eigenvalues
    _, _, cyc_factorization = rank_fieldextension(cp)

    # a bit hacky
    val = [
        min(elt.valuation() for elt in col) for col in frob_matrix.columns()
    ]
    projection_cols = frob_matrix.ncols() - val.index(0)
    assert set(val[-projection_cols:]) == {0}
    # P1 = | zero matrix |
    #      | Identity    |
    P1 = zero_matrix(frob_matrix.ncols() - projection_cols,
                     projection_cols).stack(identity_matrix(projection_cols))
    # computing a kernel, either via smith form or howell form
    # involves some kind of gauss elimination,
    # and thus having the columns with lowest valuation first improves
    # the numerical stability of the algorithms
    P1.reverse_rows_and_columns()
    frob_matrix.reverse_rows_and_columns()

    @cached_function
    def frob_power(k):
        if k == 0:
            return identity_matrix(frob_matrix.ncols())
        elif k == 1:
            return frob_matrix
        else:
            return frob_matrix * frob_power(k - 1)

    factor_i = []
    dim_Ti = []
    obsi = []
    dim_Li = []
    for cyc_fac, cyc_exp in cyc_factorization:
        factor_i.append((cyc_fac, cyc_exp))
        Ti = matrix(0, frob_matrix.ncols())
        obsij = []
        dim_Tij = []
        dim_Lij = []
        for fac, exp in tate_factor_Zp(cyc_fac):
            # the rows of Tij are a basis for Tij
            # the 'computed' argument avoids echelonizing the kernel basis
            # which might induce some precision loss on the projection
            #Tij = fac(frob_matrix).right_kernel_matrix(basis='computed')

            # computing the right kernel with smith form
            # howell form or strong echelon could also be good options
            Tij = padic_right_kernel_matrix(fac(frob_matrix))
            if Tij.nrows() != fac.degree() * exp * cyc_exp:
                raise PrecisionError(
                    "Number of eigenvectors (%d) doesn't match the number of eigenvalues (%d), increasing  precision should solve this"
                    % (Tij.nrows(), fac.degree() * exp * cyc_exp))
            if over_Qp:
                dim_Tij.append(Tij.nrows())
                obs_map = Tij * P1
                rank_obs_ij = obs_map.rank()
                obsij.append(rank_obs_ij)
                Lijmatrix = matrix(Tij.base_ring(), Tij.nrows(), 0)
                for ell in range(fac.degree()):
                    Lijmatrix = Lijmatrix.augment(
                        Tij * frob_power(ell).transpose() * P1)
                # Lij = right_kernel(K) subspace of Tij that is invariant under Frob and unobstructed
                Krank = Lijmatrix.rank()
                dim_Lij.append(Tij.nrows() - Krank)
                if dim_Lij[-1] % fac.degree() != 0:
                    old_dim = dim_Li[-1]
                    deg = fac.degree()
                    new_dim = dim_Li[-1] = deg * (old_dim // deg)
                    if pedantic:
                        warnings.warn(
                            "rounding dimension of Li from %d to %d for factor = %s"
                            % (old_dim, new_dim, fac))

            Ti = Ti.stack(Tij)

        if over_Qp:
            dim_Ti.append(dim_Tij)
            obsi.append(obsij)
            dim_Li.append(dim_Lij)
        else:
            obs_map = Ti * P1
            if Ti.nrows() != cyc_fac.degree() * cyc_exp:
                raise PrecisionError(
                    "Number of eigenvectors (%d) doesn't match the number of eigenvalues (%d), increasing  precision should solve this"
                    % (Tij.nrows(), cyc_fac.degree() * cyc_exp))
            dim_Ti.append(Ti.nrows())
            rank_obs_i = padic_rank(obs_map)
            obsi.append(Ti.nrows() - rank_obs_i)
            Limatrix = matrix(Ti.base_ring(), Ti.nrows(), 0)
            for ell in range(0, cyc_fac.degree()):
                Limatrix = Limatrix.augment(Ti * frob_power(ell).transpose() *
                                            P1)
            #print(Limatrix.smith_form(exact=False, integral=True, transformation=False).diagonal())
            # Li = right_kernel(K) subspace of Tij that is invariant under Frob and unobstructed
            Krank = padic_rank(Limatrix)
            dim_Li.append(Ti.nrows() - Krank)
            if dim_Li[-1] % cyc_fac.degree() != 0:
                old_dim = dim_Li[-1]
                deg = cyc_fac.degree()
                new_dim = dim_Li[-1] = deg * (old_dim // deg)
                if pedantic:
                    warnings.warn(
                        "rounding dimension of Li from %d to %d for cyc_factor = %s"
                        % (old_dim, new_dim, cyc_fac))
    return factor_i, dim_Ti, obsi, dim_Li,
Ejemplo n.º 40
0
def prune_dg_module_on_poset(dgm, ab, verbose=False, assume_sorted=False):
    a, b = ab
    tv = dgm.cat.objects[0]
    ring = dgm.ring
    cat = dgm.target_cat
    #diff_dict = {d:dgm.differential(tv, (d,)) for d in range(a - 1, b + 1)}
    diff_dict = {}
    for d in range(a - 1, b + 1):
        if verbose:
            print('computing differential in degree ' + str(d))
        diff_dict[d] = dgm.differential(tv, (d,))
    if verbose:
        print('original differentials computed')

    # Since we assume that cat is a poset,
    # we may convert the differentials to usual sagemath matrices
    # as long as we keep track of the row labels.
    #
    # triv = cat.trivial_representation(ring)
    # m_dict = {}
    # for d in range(a - 1, b + 1):
    #     m_dict[d] = triv(diff_dict[d])

    m_dict = {}
    for d in range(a - 1, b + 1):
        if verbose:
            print('Expanding the differential in degree ' + str(d))
        entries = []
        z = 0
        dv = diff_dict[d].data_vector
        source = diff_dict[d].source
        target = diff_dict[d].target
        for x in source:
            for y in target:
                if len(cat.hom(x, y)) == 1:
                    entries += [dv[z]]
                    z += 1
                else:
                    entries += [ring(0)]
        m_dict[d] = matrix(ring, len(source), len(target), entries)

    # This dict will keep track of the row labels
    m_source = {}
    # and dict will keep track of the target labels
    m_target = {}

    if assume_sorted:
        for d in range(a - 1, b + 1):
            for x in cat.objects:
                m_source[d, x] = 0
                m_target[d, x] = 0
                for y in diff_dict[d].source:
                    if x == y:
                        m_source[d, x] += 1
                for y in diff_dict[d].target:
                    if x == y:
                        m_target[d, x] += 1
            source_assumed = [x for x in cat.objects for _ in range(m_source[d, x])]
            if diff_dict[d].source != source_assumed:
                raise ValueError('This dgModule is not sorted in degree ' + str(d))
    else:
        # Time to sort the rows
        for d in range(a - 1, b + 1):
            targ = m_dict[d].ncols()
            rows = m_dict[d].rows()
            new_rows = []
            for x in cat.objects:
                m_source[d, x] = 0
                for i, r in enumerate(rows):
                    if diff_dict[d].source[i] == x:
                        m_source[d, x] += 1
                        new_rows += [r]
            if len(new_rows) == 0:
                m_dict[d] = zero_matrix(ring, 0, targ)
            else:
                m_dict[d] = block_matrix(ring, [[matrix(ring, 1, targ, list(r))] for r in new_rows])

        # and now the columns
        for d in range(a - 1, b + 1):
            sour = m_dict[d].nrows()
            cols = m_dict[d].columns()
            new_cols = []
            for x in cat.objects:
                m_target[d, x] = 0
                for i, c in enumerate(cols):
                    if diff_dict[d].target[i] == x:
                        m_target[d, x] += 1
                        new_cols += [c]
            if len(new_cols) == 0:
                m_dict[d] = zero_matrix(ring, sour, 0)
            else:
                m_dict[d] = block_matrix(ring, [[matrix(ring, sour, 1, list(c)) for c in new_cols]])

    # if verbose:
    #     for d in range(a - 1, b + 1):
    #         print
    #         print [m_source[d, x] for x in cat.objects]
    #         for r in m_dict[d]:
    #             print r
    #         print [m_target[d, x] for x in cat.objects]

    # Find the desired row- and column-operations
    # and change the labels (slightly prematurely)
    for d in range(a, b):
        for x in cat.objects:
            upper_left = m_dict[d][:m_source[d, x], :m_target[d, x]]
            if verbose:
                print('Computing Smith form of a matrix with dimensions ' + str(upper_left.dimensions()))
            dropped, sc, sr, tc, tr = prune_matrix(upper_left)
            if verbose:
                print('Dropping ' + str(dropped) + ' out of ' + str(m_source[d, x]) + \
                      ' occurrences of ' + str(x) + ' in degree ' + str(d - 1))
            m_target[d - 1, x] -= dropped
            m_source[d + 1, x] -= dropped
            cid = m_dict[d - 1].ncols() - sc.nrows()
            zul = zero_matrix(ring, sc.nrows(), cid)
            zlr = zero_matrix(ring, cid, sc.ncols())
            m_dict[d - 1] = m_dict[d - 1] * block_matrix([[zul, sc], [identity_matrix(ring, cid), zlr]])
            rid = m_dict[d + 1].nrows() - tr.ncols()
            zul = zero_matrix(ring, rid, tr.ncols())
            zlr = zero_matrix(ring, tr.nrows(), rid)
            m_dict[d + 1] = block_matrix([[zul, identity_matrix(ring, rid)], [tr, zlr]]) * m_dict[d + 1]

            row_rest = m_dict[d].nrows() - m_source[d, x]
            col_rest = m_dict[d].ncols() - m_target[d, x]

            m_dict[d] = block_diagonal_matrix([sr, identity_matrix(ring, row_rest)]) * m_dict[d]
            m_dict[d] = m_dict[d] * block_diagonal_matrix([tc, identity_matrix(ring, col_rest)])

            rest_rest = m_dict[d][m_source[d, x]:, m_target[d, x]:]
            rest_dropped = m_dict[d][m_source[d, x]:, :dropped]
            dropped_rest = m_dict[d][:dropped, m_target[d, x]:]
            rest_kept = m_dict[d][m_source[d, x]:, dropped:m_target[d, x]]
            kept_rest = m_dict[d][dropped:m_source[d, x], m_target[d, x]:]
            kept_kept = m_dict[d][dropped:m_source[d, x], dropped:m_target[d, x]]
            m_dict[d] = block_matrix(ring, [[rest_rest - rest_dropped * dropped_rest, rest_kept],
                                            [kept_rest,                               kept_kept]])
            m_source[d, x] -= dropped
            m_target[d, x] -= dropped

    for d in range(a - 1, b + 1):
        source = [x for x in cat.objects for _ in range(m_source[d, x])]
        target = [x for x in cat.objects for _ in range(m_target[d, x])]
        dv = [w for i, r in enumerate(m_dict[d].rows()) for j, w in enumerate(r)
              if len(cat.hom(source[i], target[j])) == 1]
        data_vector = vector(ring, dv)
        diff_dict[d] = CatMat(ring, cat, source, data_vector, target)

    def pruned_f_law(d_singleton, x, f, y):
        d = d_singleton[0]
        if d in range(a - 1, b + 1):
            return CatMat.identity_matrix(ring, cat, diff_dict[d].source)
        return dgm.module_in_degree((d,))(x, f, y)

    def pruned_d_law(x, d_singleton):
        d = d_singleton[0]
        if d in range(a - 1, b + 1):
            return diff_dict[d]
        return dgm.differential(x, (d,))

    return dgModule(TerminalCategory, ring, pruned_f_law, [pruned_d_law], target_cat=cat)