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)
def _jordan_decomposition_odd_p(S, p): ''' Input: S: half integral matrix p: prime Output: a list l = [p^n1 * u1, p^n2 * u2, ... p^nk * uk] such that n1 <= n2 <= ... nk and diag(l) is Z_p equivalent to S. ''' p = Integer(p) acc = [] n = len(S.columns()) while True: if n == 1: return acc + [S[0, 0]] i0, j0 = find_min_ord_elet(S, p) if i0 != j0: u = identity_matrix(QQ, n) u[(j0, i0)] = 1 S = bracket_action(S, u) j0 = i0 S = _jordan_dcomp_diag(i0, n, S) acc.append(S[(0, 0)]) S = S.submatrix(row=1, col=1) n -= 1
def ideal(self, z): Imod = self.ideal_mod_p(z) A = Imod.basis_matrix().lift() from sage.all import identity_matrix p = self.p B = A.stack(p*identity_matrix(ZZ,8)) V = B.row_module() return V
def dual_instance1(A, scale=1): """ Generate dual attack basis for LWE normal form. :param A: LWE matrix A """ q = A.base_ring().order() n = A.ncols() B = A.matrix_from_rows(range(0, n)).inverse().change_ring(ZZ) L = identity_matrix(ZZ, n).augment(B) L = L.stack(matrix(ZZ, n, n).augment(q*identity_matrix(ZZ, n))) for i in range(0, 2*n): for j in range(n, 2*n): L[i, j] = scale*L[i, j] return L
def topologically_evaluate_regular(self, datum): if not datum.is_regular(): raise ValueError('need a regular datum') euler_cap = {} torus_factor_dim = {} N = Set(range(len(datum.polynomials))) _, d, _ = split_off_torus([datum.initials[i].num for i in N]) min_dim = datum.ambient_dim - d # NOTE: triangulation/"topologisation" of RationalSet instances only # considers cones of maximal dimension. if datum.RS.dim() <= min_dim - 2: return yield if datum.RS.dim() >= min_dim: raise RuntimeError('this should be impossible') for I in Subsets(N): F = [datum.initials[i].num for i in I] V = SubvarietyOfTorus(F, torus_dim=datum.ambient_dim) U,W = V.split_off_torus() torus_factor_dim[I] = W.torus_dim assert torus_factor_dim[I] >= min_dim if W.torus_dim > min_dim: continue euler_cap[I] = U.khovanskii_characteristic() if U.is_nondegenerate() else U.euler_characteristic() for I in Subsets(N): chi = sum((-1)**len(J) * euler_cap[I + J] for J in Subsets(N - I) if torus_factor_dim[I + J] == min_dim) if not chi: continue I = list(I) id = identity_matrix(ZZ, len(I)) def vectorise(first, k, vec): w = id[I.index(k)] if k in I else vector(ZZ,len(I)) return vector(ZZ, [first] + list(vec) + list(w)) polytopes = [] for (i, j) in self.pairs: vertices = [vectorise(0, k, datum.ideals[i].initials[m].exponents()[0]) for m, k in enumerate(datum._ideal2poly[i])] +\ [vectorise(1, k, datum.ideals[j].initials[m].exponents()[0]) for m, k in enumerate(datum._ideal2poly[j])] polytopes.append(Polyhedron(vertices=vertices, ambient_dim=1+datum.ambient_dim + len(I))) extended_RS = (RationalSet(StrictlyPositiveOrthant(1)) * datum.RS * RationalSet(StrictlyPositiveOrthant(len(I)))) for surf in topologically_evaluate_monomial_integral(extended_RS, polytopes, self.integrand, dims=[min_dim+len(I)]): yield SURF(scalar=chi*surf.scalar, rays=surf.rays)
def _jordan_dcomp_diag(i0, n, S): u = perm_mat(0, i0, n) S = bracket_action(S, u) # (0, 0) elment is the min order. u = identity_matrix(QQ, n) a = S[(0, 0)] for j in range(1, n): u[(0, j)] = -S[(0, j)] / a return bracket_action(S, u)
def _jordan_decomposition_2(S): ''' Input: S: half integral matrix Output: list of tuples (a, b) Here a is an integer which is an exponent. b is equal to an element of [1, 3, 5, 7] or 'h' or 'y'. ''' n = len(S.columns()) acc = [] while True: i0, j0 = find_min_ord_elet(S, 2) if (n == 1) or (n == 2 and i0 != j0): mat_lst = acc + [S] break if i0 == j0: S = _jordan_dcomp_diag(i0, n, S) acc.append(S.submatrix(nrows=1, ncols=1)) S = S.submatrix(row=1, col=1) n -= 1 else: # (0, 1) element has the minimal order. S = bracket_action(S, perm_mat2(i0, j0, n)) u = identity_matrix(QQ, n) for j in range(2, n): s00, s01, s11 = S[(0, 0)], S[(0, 1)], S[(1, 1)] d = s00 * s11 - s01 ** 2 s0j = S[(0, j)] s1j = S[(1, j)] a0 = (-s11 * s0j + s01 * s1j) / d a1 = (s01 * s0j - s00 * s1j) / d u[(0, j)] = a0 u[(1, j)] = a1 S = bracket_action(S, u) acc.append(S.submatrix(nrows=2, ncols=2)) S = S.submatrix(row=2, col=2) n -= 2 res = [] for m in mat_lst: if m.ncols() == 1: a = m[0, 0] e = valuation(a, two) u = (a / two ** e) % 8 res.append((e, u)) else: e = valuation(m[0, 1], two) + 1 m = m / two ** (e - 1) if m.det() % 8 == 3: h_or_y = 'y' else: h_or_y = 'h' res.append((e, h_or_y)) return res
def involution_matrix(Pa, Pb, tol=1e-4): r"""Returns the transformation matrix `R` corresponding to the anti-holomorphic involution on the periods of the Riemann surface. Given an aritrary `2g x g` period matrix `[Pa, Pb]^T` of a genus `g` Riemann surface `X` the action of the anti-holomorphic involution on `X` of these periods is given by left-multiplication by a `2g x 2g` matrix `R`. That is, .. math:: [\tau P_a^T, \tau P_b^T]^T = R [P_a^T, P_b^T]^T 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 veryify integrality of transformation matrix. Dependent on precision of period matrices. Returns ------- R : complex matrix The anti-holomorphic involution matrix. Todo ---- For numerical stability, replace matrix inversion with linear system solves. """ g, g = Pa.dimensions() R_RDF = Matrix(RDF, 2 * g, 2 * g) Ig = identity_matrix(RDF, g) M = Im(Pb.T) * Re(Pa) - Im(Pa.T) * Re(Pb) Minv = M.inverse() R_RDF[:g, :g] = (2 * Re(Pb) * Minv * Im(Pa.T) + Ig).T R_RDF[:g, g:] = -2 * Re(Pa) * Minv * Im(Pa.T) R_RDF[g:, :g] = 2 * Re(Pb) * Minv * Im(Pb.T) R_RDF[g:, g:] = -(2 * Re(Pb) * Minv * Im(Pa.T) + Ig) R = R_RDF.round().change_ring(ZZ) # sanity check: make sure that R_RDF is close to integral. we perform this # test here since the matrix returned should be over ZZ error = (R_RDF.round() - R_RDF).norm() if error > tol: raise ValueError( "The anti-holomorphic involution matrix is not " "integral. Try increasing the precision of the input " "period matrices." ) return R
def poly_to_rep(f): """ For a polynomial f in F[x], return the matrix corresponding to the left action of x on F[x]/(f). """ assert f.is_monic() x = f.parent().gen() d = f.degree() last_column = [-f[e] for e in range(d)] I = identity_matrix(d) M = matrix(I.rows()[1:] + [last_column]) assert M.charpoly() == f return M.transpose()
def complex_to_lattice(z, d, a, N=None): """ Given an algebraic number z of degree d, set of up the lattice which tries to express a in terms of powers of z, where the last two colmns are weighted by N. """ if N is None: N = ZZ(2)**(z.prec() - 10) nums = [z**k for k in range(d)] + [a] last_columns = [[round(N * real_part(x)) for x in nums], [round(N * imag_part(x)) for x in nums]] A = matrix(identity_matrix(len(nums)).columns() + last_columns) return A.transpose()
def _spanning_tree(self, root=None): r""" Return - a list of indices of edges that form a basis - a matrix projection to the basis (modulo the triangle relations) """ if root is None: root = next(iter(self._surface.edges())).positive() root = self._half_edge_to_face(root) t = {root: None} # face -> half edge to take to go to the root todo = [root] edges = [ ] # store edges in topological order to perform Gauss reduction while todo: f = todo.pop() for _ in range(3): f1 = -f g = self._half_edge_to_face(f1) if g not in t: t[g] = f1 todo.append(g) edges.append(f1) f = self._surface.nextInFace(f) # gauss reduction n = self._surface.size() proj = identity_matrix(ZZ, n) edges.reverse() for f1 in edges: v = [0] * n f2 = self._surface.nextInFace(f1) f3 = self._surface.nextInFace(f2) assert self._surface.nextInFace(f3) == f1 i1 = f1.index() s1 = -1 if i1 % 2 else 1 i2 = f2.index() s2 = -1 if i2 % 2 else 1 i3 = f3.index() s3 = -1 if i3 % 2 else 1 i1 = f1.edge().index() i2 = f2.edge().index() i3 = f3.edge().index() proj[i1] = -s1 * (s2 * proj[i2] + s3 * proj[i3]) for j in range(n): assert proj[j, i1] == 0 return (t, proj)
def involution_matrix(Pa, Pb, tol=1e-4): r"""Returns the transformation matrix `R` corresponding to the anti-holomorphic involution on the periods of the Riemann surface. Given an aritrary `2g x g` period matrix `[Pa, Pb]^T` of a genus `g` Riemann surface `X` the action of the anti-holomorphic involution on `X` of these periods is given by left-multiplication by a `2g x 2g` matrix `R`. That is, .. math:: [\tau P_a^T, \tau P_b^T]^T = R [P_a^T, P_b^T]^T 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 veryify integrality of transformation matrix. Dependent on precision of period matrices. Returns ------- R : complex matrix The anti-holomorphic involution matrix. Todo ---- For numerical stability, replace matrix inversion with linear system solves. """ g,g = Pa.dimensions() R_RDF = Matrix(RDF, 2*g, 2*g) Ig = identity_matrix(RDF, g) M = Im(Pb.T)*Re(Pa) - Im(Pa.T)*Re(Pb) Minv = M.inverse() R_RDF[:g,:g] = (2*Re(Pb)*Minv*Im(Pa.T) + Ig).T R_RDF[:g,g:] = -2*Re(Pa)*Minv*Im(Pa.T) R_RDF[g:,:g] = 2*Re(Pb)*Minv*Im(Pb.T) R_RDF[g:,g:] = -(2*Re(Pb)*Minv*Im(Pa.T) + Ig) R = R_RDF.round().change_ring(ZZ) # sanity check: make sure that R_RDF is close to integral. we perform this # test here since the matrix returned should be over ZZ error = (R_RDF.round() - R_RDF).norm() if error > tol: raise ValueError("The anti-holomorphic involution matrix is not " "integral. Try increasing the precision of the input " "period matrices.") return R
def topologically_evaluate_regular(self, datum): if not datum.is_regular(): raise ValueError('need a regular datum') euler_cap = {} torus_factor_dim = {} N = Set(range(len(datum.polynomials))) _, d, _ = split_off_torus([datum.initials[i].num for i in N]) min_dim = datum.ambient_dim - d if datum.RS.dim() < min_dim: logger.debug('Totally irrelevant datum') return yield for I in Subsets(N): F = [datum.initials[i].num for i in I] V = SubvarietyOfTorus(F, torus_dim=datum.ambient_dim) U,W = V.split_off_torus() torus_factor_dim[I] = W.torus_dim euler_cap[I] = U.khovanskii_characteristic() if U.is_nondegenerate() else U.euler_characteristic() assert torus_factor_dim[I] >= min_dim for I in Subsets(N): chi = sum((-1)**len(J) * euler_cap[I+J] for J in Subsets(N-I) if torus_factor_dim[I+J] == min_dim) if not chi: logger.debug('Vanishing Euler characteristic: I = %s' % I) continue I = list(I) polytopes = [] id = identity_matrix(ZZ, len(I)) def vectorise(k, vec): w = id[I.index(k)] if k in I else vector(ZZ,len(I)) return vector(ZZ, list(vec) + list(w)) assert len(datum._ideal2poly[0]) == len(datum.ideals[0].gens) polytopes = [Polyhedron(vertices=[vectorise(k, datum.ideals[0].initials[m].exponents()[0]) for m,k in enumerate(datum._ideal2poly[0])], ambient_dim=datum.ambient_dim+len(I))] extended_RS = datum.RS * RationalSet(StrictlyPositiveOrthant(len(I))) assert all(extended_RS.ambient_dim == P.ambient_dim() for P in polytopes) for surf in topologically_evaluate_monomial_integral(extended_RS, polytopes, [ (1,), (0,) ], dims=[min_dim + len(I)], ): yield SURF(scalar=chi*surf.scalar, rays=surf.rays)
def _compute_echelon(self): A = Matrix(self.parent(), self.A.rows()) # we create a copy of the matrix U = identity_matrix(self.parent(), A.nrows()) if (self.have_ideal): # we do simplifications A = self.simplify(A) ## Step 1: initialize r = 0 c = 0 # we look from the position (r,c) while (r < A.nrows() and c < A.ncols()): ir = self.__find_pivot(A, r, c) A = self.simplify(A) U = self.simplify(U) # we simplify in case relations pop up if (ir != None): # we found a pivot # We do the swapping (if needed) if (ir != r): A.swap_rows(r, ir) U.swap_rows(r, ir) # We do the bareiss step Arc = A[r][c] Arows = A.rows() Urows = U.rows() for i in range(r): # we create zeros on top of the pivot Aic = A[i][c] A.set_row(i, Arc * Arows[i] - Aic * Arows[r]) U.set_row(i, Arc * Urows[i] - Aic * Urows[r]) # We then leave the row r without change for i in range(r + 1, A.nrows()): # we create zeros below the pivot Aic = A[i][c] A.set_row(i, Aic * Arows[r] - Arc * Arows[i]) U.set_row(i, Aic * Urows[r] - Arc * Urows[i]) r += 1 c += 1 else: # no pivot then only advance in column c += 1 # We finish simplifying the gcds in each row gcds = [gcd(row) for row in A] T = diagonal_matrix([1 / el if el != 0 else 1 for el in gcds]) A = (T * A).change_ring(self.parent()) U = T * U return A, U
def dual_instance0(A): """ Generate dual attack basis. :param A: LWE matrix A """ q = A.base_ring().order() B0 = A.left_kernel().basis_matrix().change_ring(ZZ) m = B0.ncols() n = B0.nrows() r = m - n B1 = matrix(ZZ, r, n).augment(q * identity_matrix(ZZ, r)) B = B0.stack(B1) return B
def dual_instance0(A): """ Generate dual attack basis. :param A: LWE matrix A """ q = A.base_ring().order() B0 = A.left_kernel().basis_matrix().change_ring(ZZ) m = B0.ncols() n = B0.nrows() r = m-n B1 = matrix(ZZ, r, n).augment(q*identity_matrix(ZZ, r)) B = B0.stack(B1) return B
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
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
def padically_evaluate_regular(self, datum, extra_RS=None): if not datum.is_regular(): raise ValueError('need a regular datum') # The extra variable's valuation is in extra_RS. if extra_RS is None: extra_RS = RationalSet(StrictlyPositiveOrthant(1)) q = var('q') count_cap = {} N = Set(range(len(datum.polynomials))) for I in Subsets(N): F = [datum.initials[i].num for i in I] V = SubvarietyOfTorus(F, torus_dim=datum.ambient_dim) count_cap[I] = V.count() # BEGIN SANITY CHECK # q = var('q') # u, w = V.split_off_torus() # assert ((count_cap[I]/(q-1)**w.torus_dim).simplify_full())(q=1) == u.euler_characteristic() # END SANITY CHECK for I in Subsets(N): cnt = sum((-1)**len(J) * count_cap[I + J] for J in Subsets(N - I)) if not cnt: continue I = list(I) id = identity_matrix(ZZ, len(I)) def vectorise(first, k, vec): w = id[I.index(k)] if k in I else vector(ZZ, len(I)) return vector(ZZ, [first] + list(vec) + list(w)) polytopes = [] for (i, j) in self.pairs: vertices = [vectorise(0, k, datum.ideals[i].initials[m].exponents()[0]) for m, k in enumerate(datum._ideal2poly[i])] +\ [vectorise(1, k, datum.ideals[j].initials[m].exponents()[0]) for m, k in enumerate(datum._ideal2poly[j])] polytopes.append(Polyhedron(vertices=vertices, ambient_dim=1 + datum.ambient_dim + len(I))) extended_RS = extra_RS * datum.RS * RationalSet(StrictlyPositiveOrthant(len(I))) foo, ring = symbolic_to_ratfun(cnt * (q - 1)**(1 + len(I)) / q**(1 + datum.ambient_dim), [var('t'), var('q')]) corr_cnt = CyclotomicRationalFunction.from_laurent_polynomial(foo, ring) for z in padically_evaluate_monomial_integral(extended_RS, polytopes, self.integrand): yield corr_cnt * z
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
def _compute_solution(self): A = self.echelon_form() b = self.transformation_matrix()*self.inhomogeneous().change_ring(self.solution_parent()) ## We compute the solution equation by equation r = A.nrows()-1 while(all(self.is_zero(el) for el in A[r])): r-=1 ## A.row(r) is the first real equation solution = vector(self.solution_parent(), self.A.ncols()*[0]) syzygy = identity_matrix(self.solution_parent(), self.A.ncols()) while(r >= 0): M = Matrix(self.solution_parent(),[A.row(r)]).transpose() hs = HermiteSolver(self.solution_parent(), M, vector([b[r]]), self.__euclidean, self.__xgcd) ## We check the condition for having a solution g = hs.echelon_form()[0][0] quo,rem = self.__euclidean(b[r],g) if(rem != 0): raise NoSolutionError("There is no solution to equation %s = %s" %(M.transpose(), b[r])) U = hs.transformation_matrix() ## Solution to the particular equation (alpha + S*beta) alpha = quo*U.row(0) S = Matrix(self.solution_parent(), U.rows()[1:]).transpose() ##Update the general values solution += syzygy*alpha if(S.nrows() == 0): # the solution is unique if(self.A*solution != self.b): # the solution is not valid --> no solution to system raise NoSolutionError("There is no solution to the system") # otherwise, we found the solution, we break the loop syzygy = Matrix(self.solution_parent(), []) break else: syzygy *= S ## Update the system b -= A*alpha A *= S # We update the index of the equation while(r >= 0 and all(self.is_zero(el) for el in A[r])): r-=1 return self.__reduce_solution(solution, syzygy)
def balance(self): if self.is_balanced(): yield self return # If there are any, first get rid of parallel non-loops with # opposite signs. res = self._opposing_parallel_nonloop_edges() if res is not None: I = identity_matrix(self.nvertices) i, j = res for k, ell, P in zip([i, j], [j, i], dominating_cones( [self.weights[i], self.weights[j]])): # Now `k' dominates `ell'. cd = self.clone() cd.polyhedron &= P if cd.polyhedron.is_empty(): continue u, v = self.edges[k] assert (u, v) == self.edges[ell] cd.edges[ell] = make_edge(v, v) cd.weights[ell] += I[u] - I[v] yield cd return # Next, if our graph is social, do something about that. if not self.is_solitary(): for z in self.desocialise(): yield z return # Finally, deal with parallel edges that are loops or that # have the same sign. for z in self.deparallelise(): yield z return
def gen_instance(n, alpha, q, m, t=1): D = DiscreteGaussianDistributionIntegerSampler(alpha * q / sqrt(2 * pi)) lwe = LWE(n, q, D) Ac = [lwe() for _ in range(m)] A = matrix([a_ for a_, c_ in Ac]) c = vector(ZZ, [c_ for a_, c_ in Ac]) B = A.T.echelon_form() e = (c - A * lwe._LWE__s).change_ring(ZZ) def bm(x): return ZZ(x) if ZZ(x) < q // 2 else ZZ(x) - q e = vector(map(bm, e)) N = B.change_ring(ZZ) S = matrix(ZZ, m - n, n).augment(q * identity_matrix(ZZ, m - n)) L = (N.stack(S)).augment(matrix(ZZ, m, 1)) L = L.stack(matrix(c).augment(matrix(ZZ, 1, 1, [t]))) return L, e
def eigenvector_with_eigenvalue(self, lin_op, lm): '''Let lin_op(f, t) be an endomorphsim of self and assume it has a unique eigenvector (up to constant) with eigenvalue lm. This medhod returns an eigenvector. ''' basis = self.basis() dim = len(basis) if hasattr(lm, "parent"): K = lm.parent() if hasattr(K, "fraction_field"): K = K.fraction_field() else: K = QQ A = self.matrix_representaion(lin_op) S = PolynomialRing(K, names="x") x = S.gens()[0] f = S(A.charpoly()) g = S(f // (x - lm)) cffs_g = [g[y] for y in range(dim)] A_pws = [] C = identity_matrix(dim) for i in range(dim): A_pws.append(C) C = A * C for i in range(dim): clm_i = [a.columns()[i] for a in A_pws] w = sum((a * v for a, v in zip(cffs_g, clm_i))) if w != 0: egvec = w break res = sum([a * b for a, b in zip(egvec, basis)]) # TODO: Use a construction class to construct basis. if all(hasattr(b, "_construction") and b._construction is not None for b in basis): res._construction = sum([a * b._construction for a, b in zip(egvec, basis)]) if hasattr(res, 'set_parent_space'): res.set_parent_space(self) return res
def integer_kernel_basis(R): r"""Returns the Z-basis `[S1 \\ S2]` of the kernel of the anti-holomorphic involution matrix `R`. The `2g x g` matrix `[S1 \\ S2]` represents a Z-basis of the kernel space .. math:: K_\mathbb{Z} = \text{ker}(R^T - \mathbb{I}_{2g}) That is, the basis of the space of all vectors fixed by the anti-holomorphic involution `R`. Used as input in `N1_matrix`. Parameters ---------- R : integer matrix The anti-holomorphic involution matrix of a genus `g` Riemann surface. Returns ------- S : integer matrix A `2g x g` matrix where each column is a basis element of the fixed point space of `R`. """ twog, twog = R.dimensions() g = twog/2 K = R.T - identity_matrix(ZZ, twog) r = K.rank() # sanity check: the rank of the kernel should be the genus of the curve if r != g: raise ValueError("The rank of the integer kernel of K should be " "equal to the genus.") # compute the integer kernel from the Smith normal form of K D,U,V = K.smith_form() S = V[:,g:] return S
def integer_kernel_basis(R): r"""Returns the Z-basis `[S1 \\ S2]` of the kernel of the anti-holomorphic involution matrix `R`. The `2g x g` matrix `[S1 \\ S2]` represents a Z-basis of the kernel space .. math:: K_\mathbb{Z} = \text{ker}(R^T - \mathbb{I}_{2g}) That is, the basis of the space of all vectors fixed by the anti-holomorphic involution `R`. Used as input in `N1_matrix`. Parameters ---------- R : integer matrix The anti-holomorphic involution matrix of a genus `g` Riemann surface. Returns ------- S : integer matrix A `2g x g` matrix where each column is a basis element of the fixed point space of `R`. """ twog, twog = R.dimensions() g = twog / 2 K = R.T - identity_matrix(ZZ, twog) r = K.rank() # sanity check: the rank of the kernel should be the genus of the curve if r != g: raise ValueError("The rank of the integer kernel of K should be " "equal to the genus.") # compute the integer kernel from the Smith normal form of K D, U, V = K.smith_form() S = V[:, g:] return S
def padically_evaluate_regular(self, datum): A = self.A n = self.nvertices m = self.nedges RS = RationalSet(PositiveOrthant(n + 1)) polytopes = [Polyhedron(vertices=[vector(ZZ, n * [0] + [1])])] I = list(identity_matrix(ZZ, n + 1)) for j in range(m): vertices = [vector(ZZ, n * [0] + [1])] for i, a in enumerate(A.column(j)): if a == 1: vertices.append(I[i]) polytopes.append(Polyhedron(vertices=vertices)) for z in padically_evaluate_monomial_integral(RS, polytopes, [(1, ) + m * (0, ), (m + 1) * (1, )]): yield z
def MatrixCharpoly(coefficients): """ INPUT: - ``coefficients`` -- an array with n + 1, where the first entry is 1 OUTPUT: - a matrix A such that det(1 - t A) = R[](coefficients) EXAMPLES: sage: list(reversed(yellow.MatrixCharpoly([1,2,3]).characteristic_polynomial().list())) == [1,2,3] True TESTS: sage: test_pass = True sage: for i in range(10): ....: cf = [1] + [ZZ.random_element() for _ in range(randint(1,10))]; ....: test_pass = test_pass and (list(reversed(MatrixCharpoly(cf).characteristic_polynomial().list())) == cf) sage: print test_pass True """ assert coefficients[0] == 1 n = len(coefficients) - 1 M = Matrix(1, n - 1).stack(identity_matrix(n - 1, n - 1)) M = M.augment(-vector(reversed(coefficients[1:]))) return M
def padically_evaluate_regular(self, datum): if not datum.is_regular(): raise ValueError('need a regular datum') q = var('q') count_cap = {} N = Set(range(len(datum.polynomials))) for I in Subsets(N): F = [datum.initials[i].num for i in I] V = SubvarietyOfTorus(F, torus_dim=datum.ambient_dim) count_cap[I] = V.count() for I in Subsets(N): cnt = sum((-1)**len(J) * count_cap[I+J] for J in Subsets(N-I)) if not cnt: continue I = list(I) polytopes = [] id = identity_matrix(ZZ, len(I)) def vectorise(k, vec): w = id[I.index(k)] if k in I else vector(ZZ,len(I)) return vector(ZZ, list(vec) + list(w)) assert len(datum._ideal2poly[0]) == len(datum.ideals[0].gens) polytopes = [Polyhedron(vertices=[ vectorise(k, datum.ideals[0].initials[m].exponents()[0]) for m,k in enumerate(datum._ideal2poly[0]) ], ambient_dim=datum.ambient_dim+len(I))] extended_RS = datum.RS * RationalSet(StrictlyPositiveOrthant(len(I))) foo, ring = symbolic_to_ratfun(cnt * (q - 1)**len(I) / q**datum.ambient_dim, [var('t'), var('q')]) corr_cnt = CyclotomicRationalFunction.from_laurent_polynomial(foo, ring) assert all(extended_RS.ambient_dim == P.ambient_dim() for P in polytopes) for z in padically_evaluate_monomial_integral(extended_RS, polytopes, [ (1,), (0,) ]): yield corr_cnt * z
def __init__(self, fund_group): self.domain_gens = fund_group.generators() ab_words = [ abelianize_word(R, self.domain_gens) for R in fund_group.relators() ] if not ab_words: n = fund_group.num_generators() self.elementary_divisors = n * [ 0, ] self.U = identity_matrix(n) else: R = matrix(ZZ, ab_words).transpose() D, U, V = R.smith_form() m = U.nrows() assert m == D.nrows() d = min(D.nrows(), D.ncols()) diag = D.diagonal() num_ones = diag.count(1) self.elementary_divisors = diag[num_ones:] + [ 0, ] * (m - d) self.U = U[num_ones:] tor = [d for d in self.elementary_divisors if d != 0] free = [d for d in self.elementary_divisors if d == 0] names = [] if len(tor) == 1: names.append('u') else: names += ['u%d' % i for i in range(len(tor))] if len(free) == 1: names.append('t') else: names += ['t%d' % i for i in range(len(free))] self._range = AbelianGroup(self.elementary_divisors, names=names)
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
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
def perm_mat2(i, j, n): # (i, j) => (0, 1) l = identity_matrix(QQ, n).columns() rem = [a for a in range(n) if a not in (i, j)] l1 = [l[i], l[j]] + [l[a] for a in rem] return matrix(QQ, l1).transpose()
def padic_smith_form(M, transformation=True): r""" this uses a rank-1 reduction method see: https://uwspace.uwaterloo.ca/bitstream/handle/10012/12241/Elsheikh_Mustafa.pdf Chapter 4 and is very similar to the p-adic smith form implemented in sage with exact=False they find U and V in Z/p^prec such that st U*M*V = diag(elementary divisors) mod p^prec On the contrary, we are interested in keep track of loss of precision thus we compute U and V where some entries might have lower precision U*M*V = diag(elementary divisors) modp^(prec - v) where v is the highest valuation of the nonzero elementary divisors that we could detect some entries of U and V might have more precision that `prec-v` EXAMPLES:: sage: from crystalline_obstruction.main import padic_smith_form sage: entries = [0, 5664461354126771, 12212357361910300, 15947020959157478, 0, 16792952041597449, 9399124951373949, 4818530271686800, 0, 14690359073749623, 11237259451999884, 5117434014428142, 15157488677243483, 9004103062307752, 20761679499270441, 4817969886991856, 19925864281756441, 12021725322600663, 4620722392655416, 5445142895231681, 6605357538252496, 7608812697273777, 18542817615638637, 18194689690271501, 16298292917596268,5029914121037969, 9960884344083847, 0, 20341333098836812, 12117922812876054, 1270149214447437, 0, 10999401748338075, 9493559500408195, 10612080564946174, 0, 4620722392655416, 10891113386038365, 956055025271903, 2162842206467093, 18542817615638637, 1143972982339214, 336113117292612, 469148515686007, 9960884344083847, 13128267973348003, 15817056104759912, 20531311511260484, 13598045280630823, 7585782589268305, 14053895308766769, 3065047087418756, 15664512169571917, 913325863843049] sage: M = Matrix(ZpCA(43, prec=10, print_mode='val-unit'), 6, 9, entries) sage: S, U, V = padic_smith_form(M) sage: S.diagonal() [43 * 1 + O(43^10), 43 * 1 + O(43^10), 43^2 * 1 + O(43^10), 43^9 * 1 + O(43^10), O(43^10), O(43^10)] sage: (U*M*V).diagonal() [43 * 1 + O(43^10), 43 * 1 + O(43^10), 43^2 * 1 + O(43^10), O(43^9), O(43^2), O(43^2)] sage: sS, sU, sV = M.smith_form(exact=False) sage: (sS, sU, sV) == (S, U, V) True sage: V.column(4) (34 + O(43), 30 + O(43), 38 + O(43), 9 + O(43), 1 + O(43^10), O(43^10), O(43^10), O(43^10), O(43^10)) sage: sV.column(4) (13694996109475306 + O(43^10), 1917185461381533 + O(43^10), 113132459648579 + O(43^10), 9 + O(43^10), 1 + O(43^10), O(43^10), O(43^10), O(43^10), O(43^10)) """ n = M.nrows() m = M.ncols() if m > n: if transformation: S, U, V = padic_smith_form(M.transpose(), transformation) return S.transpose(), V.transpose(), U.transpose() else: return padic_smith_form(M.transpose(), transformation) R = M.base_ring() s = [R.zero()] * m S = copy(M) left = identity_matrix(R, n) right = identity_matrix(R, m) smith = M.parent()(0) val = -infinity def find_pivot(l): minval = infinity ans = None for i in range(l, n): for j in range(l, m): elt = S[i, j] if elt != 0 and elt.valuation() < minval: minval = elt.valuation() ans = minval, i, j if minval == val: # we can't get lower return ans return ans for l in range(n): pos = find_pivot(l) if pos: val, i, j = pos else: # the matrix is all zeros break s[l] = R.one() << val smith[l, l] = s[l] S.swap_rows(i, l) S.swap_columns(j, l) if transformation: left.swap_rows(i, l) right.swap_columns(j, l) w = (S[l, l] >> val).inverse_of_unit() # this corresponds to S = S - w*(M*x)*(y*M) # where x = ej, y =ei for i in range(l + 1, n): x = -w * (S[i, l] >> val ) # we know that has val is the current min valuation S.add_multiple_of_row(i, l, x, l + 1) if transformation: left.add_multiple_of_row(i, l, x) if transformation: left.rescale_row(l, w) for j in range(l + 1, m): right.add_multiple_of_column(j, l, -w * (S[l, j] >> val)) if transformation: return smith, left, right else: return s
def ad_bracket(A, p): if p == A.ncols(): return identity_matrix(A.base_ring(), 1) l = permutations_increasing(A.ncols(), p) return matrix([[_ad_bracket_coeffs(A, b, a) for b in l] for a in l])
def bracket_power(A, p): if p == 0: return identity_matrix(A.base_ring(), 1) l = permutations_increasing(A.ncols(), p) return matrix([[sub_mat(A, a, b).det() for b in l] for a in l])
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
def support(self, basis): # Input: a basis in H**0( D_0) for H**0((g+1)\infty - E), where E is an effective divisor of degree g/2 # Output: returns the support of E as a list of g points # Computing the intersection of # <1, x, x**2,..., x**g> with <basis> B = basis.augment( identity_matrix(self.g + 1).stack(Matrix(basis.nrows() - (self.g + 1), (self.g + 1)))) KB, upper, lower = Kernel(B, basis.ncols() + self.g ) if self.verbose: print "KB upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower)) maxlower = self.lower result = [None for _ in range(self.g)] # if dim of the intersection of <1, x, x**2,..., x**g> with <basis> is 1 if self.threshold_check(upper, lower): # we have the expected rank, all the roots are simple, unless E = 2*P # as in genus = 2 we can't have E = tau(P) + P maxlower = max(maxlower, lower); Rw = PolynomialRing(self.Rdoubleextraprec, "T") poly = Rw( KB.column(0)[-(self.g + 1):].list() ) if self.g == 2: a, b, c = list(poly) disc = (b**2 - 4*a*c).abs() #a2 = (a**2).abs() dpoly = poly.derivative() if self.threshold_check((a**2).abs(), disc): xcoordinates = dpoly.complex_roots() + dpoly.complex_roots() maxlower = max(maxlower, disc); else: xcoordinates = poly.complex_roots() else: xcoordinates = poly.complex_roots() for i, x in enumerate(xcoordinates): y0 = self.Rextraprec(sqrt(self.f(x))); x0 = self.Rextraprec(x) vp = vector(self.R, [x0**u * y0**v for u, v in self.Vexps[:basis.nrows()] ]); vn = vector(self.R, [x0**u * (-y0)**v for u, v in self.Vexps[:basis.nrows()] ]); np = norm( vp * basis); nn = norm( vn * basis); #is it a simple root? if dpoly(x).abs() < self.notzero: assert self.g == 2, "one needs to be extra careful for genus > 2" if self.threshold_check(np, nn) and not self.threshold_check(nn, np): #np > nn ~ 0 result[i] = (x0, -y0); maxlower = max(maxlower, nn); elif not self.threshold_check(np, nn) and self.threshold_check(nn, np): #nn > np ~ 0 result[i] = (x0, y0); maxlower = max(maxlower, np); else: print "sign for y is not clear: neg = %s, pos = %s,\ny = %s + %s * I = 0?" % tuple(vector(RealField(15), (nn, np, y0.real(), y0.imag()))); if nn > np: result[i] = (x0, y0); maxlower = max(maxlower, np); else: result[i] = (x0, -y0); maxlower = max(maxlower, nn); # else: # assert self.g == 2, "for now only genus 2" # # for g = 2, we can't have E = P + tau(P), as (x - x0) \in H**0((g+1)\infty - E) # # thus the rank of B should be at most basis.ncols() + 1 # for j, xj in enumerate(xcoordinates[i+1:]): # if (x0 - xj).abs() < self.notzero: # # we might have a double root, and at the moment this should only work for g == 2 # break; # #j is the other root # if self.threshold_check(np, nn) and not self.threshold_check(nn, np): # result[j] = result[i] = (x0, -y0); # elif not self.threshold_check(np, nn) and self.threshold_check(nn, np): # result[j] = result[i] = (x0, y0); # else: # #this covers the case that y0 ~ 0 # if self.f(x0) > self.almostzero: # print "sign for y is not clear: neg = %.2e, pos = %.2e,\nassuming y = %.2e + %.2e * I = 0" % (nn, np, y0.real(), y0.imag()); # result[j] = result[i] = (x0, 0); # # return result, maxlower; else: if self.verbose: print "there is at least a root at infinity, i.e. \inf_{+,-} \in supp E" print (RealField(35)(upper), RealField(35)(lower)) # there is at least a root at infinity, i.e. \inf_{+,-} \in supp E # recall that \inf_{+} + \inf_{-} ~ P + tau(P), and in this case we have booth roots at infinity assert self.g == 2, "for now only genus 2" Ebasis, upper, lower = EqnMatrix(basis, basis.ncols() ) assert self.threshold_check(upper, lower), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower)) maxlower = max(maxlower, lower); B = basis.augment( identity_matrix(self.g ).stack(Matrix(basis.nrows() - (self.g ), (self.g )))) KB, upper, lower = Kernel(B, basis.ncols() + self.g - 1 ) # 1 \in <basis> v0 = vector(self.R, [0] * basis.nrows()) v0[0] = 1 norm_one = norm(Ebasis * v0) if not self.threshold_check(upper, lower): # dim <1, x> cap <basis> = 2 #1 \in <basis> assert self.threshold_check(1, norm_one), "upper = %s lower = %s norm_one = %s " % (RealField(35)(upper), RealField(35)(lower), RealField(35)(norm_one)); maxlower = max(maxlower, norm_one); #x \in <basis> vx = vector(self.R, [0]*basis.nrows()) vx[1] = 1 lower = norm(Ebasis * vx) assert self.threshold_check(1, lower), "lower = %s" % (RealField(35)(lower),); maxlower = max(maxlower, lower); vx2 = vector(self.R, [0]*basis.nrows()) vx2[2] = 1 lower = norm(Ebasis * vx2) if self.threshold_check(1, lower): # E = \inf_{+} + \inf_{-} # <1, x, x^2> \in H**0((g+1)\infty - E) # x \in H^0 => 0 + 2 \infty - E >= 0 # x^2 \in H^0 => 4 * P_0 + \infty - E >= 0 for all P0 maxlower = max(maxlower, lower); return [+Infinity, -Infinity], maxlower # <1, x> \in H**0((g+1)\infty - E) # but not x^2 # supp(E) \subsetneq { \inf_{+}, \inf_{-} } if self.f.degree() % 2 == 0: # we need to figure out the sign at infinity Maug = Matrix(basis.nrows() - self.g - 1, self.g + 1).stack(identity_matrix(self.g + 1)) B = basis.augment( Maug ) KB, upper, lower = Kernel(B, basis.ncols() + self.g ) a, b, c = KB.column(0)[-(2 + 1):].list() assert self.threshold_check(upper, lower), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower)) tmp = (-b/c) / sqrt(self.f.list()[-1]); assert self.threshold_check( tmp.real(), tmp.imag()), "upper = %s lower = %s" % (RealField(35)(upper), RealField(35)(lower)) infsign = round(tmp.real()); assert infsign in [1, -1] return [infsign*Infinity, infsign*Infinity], maxlower return [+Infinity, +Infinity], maxlower else: maxlower = max(maxlower, lower); #1 \notin <basis> assert self.threshold_check(norm_one), "upper = %s lower = %s norm_one = %s " % (RealField(35)(upper), RealField(35)(lower), RealField(35)(norm_one)); Rw = PolynomialRing(self.Rdoubleextraprec, "T") xcoordinates = Rw(KB.column(0)[-(self.g):].list()).complex_roots() assert len(xcoordinates) == 1; x0 = xcoordinates[0]; y0 = self.Rextraprec(sqrt(self.f(x0))); # if dim <1, x, x**2> cap <basis> >= 2 # then dim <1, x> cap <basis> >= 1 # we must have <1, x> \subset <basis> # double check that (x - x0) and (x - x0)**2 are in <basis> # (x - x0) v1 = vector(self.R, [0]*basis.nrows()) v1[0] = -x0 v1[1] = 1 lower = norm(Ebasis * v1) assert self.threshold_check(1, lower), "lower = %s" % (RealField(35)(lower),); maxlower = max(maxlower, lower); # (x - x0)**2 v2 = vector(self.R, [0]*basis.nrows()) v2[0] = x0**2 v2[1] = - 2*x0 v2[2] = 1 lower = norm(Ebasis * v2) assert self.threshold_check(1, lower), "lower = %s" % (RealField(35)(lower),); maxlower = max(maxlower, lower); # (x - x0)**3 v3 = vector(self.R, [0]*basis.nrows()) v3[0] = -x0**3 v3[1] = 3*x0**2 v3[2] = -3*x0 v3[3] = 1 nc = norm(Ebasis * v3) vp = vector(self.R, [x0**i * y0**j for i,j in self.Vexps[:basis.nrows()]]); vn = vector(self.R, [x0**i * (-y0)**j for i,j in self.Vexps[:basis.nrows()]]); np = norm( vp * basis); nn = norm( vn * basis); # either E = P + \inf_{+/-} # or E = P + tau(P) with P != \inf_{*}, but in this case E ~ \inf_+ + \inf_- if self.threshold_check(np, nn) and not self.threshold_check(nn, np): #np > nn ~ 0 result[0] = (x0, -y0); maxlower = max(maxlower, nn); elif not self.threshold_check(np, nn) and self.threshold_check(nn, np): #nn > np ~ 0 result[0] = (x0, y0); maxlower = max(maxlower, np); else: if self.threshold_check(1,nc) and self.threshold_check(1,np) and self.threshold_check(1,nn): result[0] = (x0, y0) result[1] = (x0, -y0) maxlower = max(maxlower, nc, np, nn); # this is equivalent to: return result, maxlower return [+Infinity, -Infinity], maxlower if self.f(x0) > self.almostzero : print "sign for y is not clear: neg = %s, pos = %s,\nassuming y = %s + %s * I = 0" % tuple( vector( RealField(15), (nn, np, y0.real(), y0.imag()))); result[0] = (x0, 0); # E = P + \inf_{+/-} # P = result[0] x0, y0 = result[0] # Now figure out what infinity is in the supp of E # by checking if y - s*x**(g+1) - (y0 - s*x0**(g+1)) \in <basis> # for s = sign * sqrt(an) sqrtan = self.Rextraprec( sqrt( self.an) ); # vp -> no pole at inf_{+} -> inf_{+} \in supp E vp = vector(self.R, [0]*basis.nrows()) # vn -> no pole at inf_{-} -> inf_{-} \in supp E vn = vector(self.R, [0]*basis.nrows()) vp[0] = -(y0 - sqrtan*x0**(self.g + 1)) vn[0] = -(y0 + sqrtan*x0**(self.g + 1)) vp[self.g + 1] = -sqrtan vn[self.g + 1] = sqrtan vp[self.g + 2] = 1 vn[self.g + 2] = 1 np = norm( Ebasis * vp ); nn = norm( Ebasis * vn ); if self.threshold_check(np * nc, nn) and not self.threshold_check(nn * nc, np) and not self.threshold_check(nn * np, nc): #np * nc > nn ~ 0 maxlower = max(maxlower, nn); result[1] = -Infinity ; elif not self.threshold_check(np * nc, nn) and self.threshold_check(nn * nc, np) and not self.threshold_check(nn * np, nc): #nn * nc > np ~ 0 maxlower = max(maxlower, np); result[1] = +Infinity elif not self.threshold_check(np * nc, nn) and not self.threshold_check(nn * nc, np) and self.threshold_check(nn * np, nc): # np*nn > nc # this should have been rulled out before, but now it looks more likely to have P + tau(P) # instead of E = P + inf maxlower = max(maxlower, nc); #this is equivalent to: result[1] = (x0, -y0) result = [+Infinity, -Infinity] else: print "inf_{?} \in supp E not clear: neg = %s, pos = %s, conj = %s" % tuple(vector(RealField(15),(nn, np, nc))); mn = min(nn, np, nc) maxlower = max(maxlower, mn); if np == mn: result[1] = +Infinity; elif nn == mn: result[1] = -Infinity; elif nc == mn: #this is equivalent to: result[1] = (x0, -y0) result = [+Infinity, -Infinity] else: assert False, "something went wrong" return result, maxlower
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)
def topologically_evaluate_regular(self, datum): T = datum.toric_datum if not T.is_regular(): raise ValueError('Can only processed regular toric data') # All our polyhedra all really half-open cones (with a - 1 >=0 # being an imitation of a >= 0). C = conify_polyhedron(T.polyhedron) M = Set(range(T.length())) logger.debug('Dimension of polyhedron: %d' % T.polyhedron.dim()) # STEP 1: # Compute the Euler characteristcs of the subvarieties of # Torus^sth defined by some subsets of T.initials. # Afterwards, we'll combine those into Denef-style Euler characteristics # via inclusion-exclusion. logger.debug('STEP 1') alpha = {} tdim = {} for I in Subsets(M): logger.debug('Processing I = %s' % I) F = [T.initials[i] for i in I] V = SubvarietyOfTorus(F, torus_dim=T.ambient_dim) U, W = V.split_off_torus() # Keep track of the dimension of the torus factor for F == 0. tdim[I] = W.torus_dim if tdim[I] > C.dim(): # In this case, we will never need alpha[I]. logger.debug('Totally irrelevant intersection.') # alpha[I] = ZZ(0) else: # To ensure that the computation of Euler characteristics succeeds in case # of global non-degeneracy, we test this first. # The 'euler_characteristic' method may change generating sets, # possibly introducing degeneracies. alpha[I] = U.khovanskii_characteristic() if U.is_nondegenerate( ) else U.euler_characteristic() logger.debug( 'Essential Euler characteristic alpha[%s] = %d; dimension of torus factor = %d' % (I, alpha[I], tdim[I])) logger.debug( 'Done computing essential Euler characteristics of intersections: %s' % alpha) # STEP 2: # Compute the topological zeta functions of the extended cones. # That is, add extra variables, add variable constraints (here: just >= 0), # and add newly monomialised conditions. def cat(u, v): return vector(list(u) + list(v)) logger.debug('STEP 2') for I in Subsets(M): logger.debug('Current set: I = %s' % I) # P = C_0 x R_(>0)^I in the paper P = DirectProductOfPolyhedra(T.polyhedron, StrictlyPositiveOrthant(len(I))) it = iter(identity_matrix(ZZ, len(I)).rows()) ieqs = [] for i in M: # Turn lhs[i] | monomial of initials[i] * y[i] if in I, # lhs[i] | monomial of initials[i] otherwise # into honest cone conditions. ieqs.append( cat( vector(ZZ, (0, )), cat( vector(ZZ, T.initials[i].exponents()[0]) - vector(ZZ, T.lhs[i].exponents()[0]), next(it) if i in I else zero_vector(ZZ, len(I))))) if not ieqs: # For some reason, not providing any constraints yields the empty # polyhedron in Sage; it should be all of RR^whatever, IMO. ieqs = [vector(ZZ, (T.ambient_dim + len(I) + 1) * [0])] Q = Polyhedron(ieqs=ieqs, base_ring=QQ, ambient_dim=T.ambient_dim + len(I)) sigma = conify_polyhedron(P.intersection(Q)) logger.debug('Dimension of Hensel cone: %d' % sigma.dim()) # Obtain the desired Euler characteristic via inclusion-exclusion, # restricted to those terms contributing to the constant term mod q-1. chi = sum((-1)**len(J) * alpha[I + J] for J in Subsets(M - I) if tdim[I + J] + len(I) == sigma.dim()) if not chi: continue # NOTE: dim(P) = dim(sigma): choose any point omega in P # then a large point lambda in Pos^I will give (omega,lambda) in sigma. # Moreover, small perturbations of (omega,lambda) don't change that # so (omega,lambda) is an interior point of sigma inside P. surfs = (topologise_cone( sigma, matrix([ cat(T.integrand[0], zero_vector(ZZ, len(I))), cat(T.integrand[1], vector(ZZ, len(I) * [-1])) ]).transpose())) for S in surfs: yield SURF(scalar=chi * S.scalar, rays=S.rays)
def t1(self, n=5): """ Return choice of element t1 of the Hecke algebra mod 2, computed using the Hecke operator $T_n$, where n is self.n INPUT: - `n` -- integer (optional default=5) OUTPUT: - a mod 2 matrix EXAMPLES:: sage: from mdsage import * sage: C = KamiennyCriterion(29) sage: C.t1(n=3) 22 x 22 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries) sage: C.t1(n=3) == 1 True sage: C.t1() Traceback (most recent call last): ... ValueError: T_5 needs to be a generator of the hecke algebra sage: C = KamiennyCriterion(37) sage: C.t1()[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) """ T = self.S.hecke_matrix(n) f = T.charpoly() F = f.factor() if prod(i[1] for i in F) != 1: raise ValueError("T_%s needs to be a generator of the hecke algebra"%n) # Compute the iterators of T acting on the winding element. e = self.M([0, oo]).element().dense_vector() t = self.M.hecke_matrix(n).dense_matrix() g = t.charpoly() Z = t.iterates(e, t.nrows(), rows=True) # 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)): h, r = g.quo_rem(F[i][0] ** F[i][1]) assert r == 0 v = vector(QQ, h.padded_list(t.nrows())) if v * Z == 0: J.append(i) 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) g = prod(F[i][0].change_ring(GF(2)) ** F[i][1] for i in J) t1 = g(Tmod2) return t1
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
def mat_to_matlist(A): return [ matrix(QQ, [[a(list(e)) for a in rows] for rows in A]) for e in identity_matrix(QQ, A.base_ring().ngens()) ]
def test_vecor_valued_misc(self): prec = 5 M = vvld_smfs(2, 20, prec) m = matrix([M._to_vector(f).list() for f in M.basis()]) self.assertEqual(m, identity_matrix(QQ, M.dimension()))
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
def _gen_tau_atlRNE( do_varify, rbt, usemotordyn = True, varify_trig = True ): from copy import copy dof = rbt.dof Rdhi = copy(rbt.Rdhi) Rdhi.append( identity_matrix(SR,3) ) wfi = range(0,dof+1) dwfi = range(0,dof+1) ddpfi = range(0,dof+1) ddpci = range(0,dof+1) ffi = range(0,dof+2) nfi = range(0,dof+2) tau = matrix(SR,dof,1) wfi[0] = copy(zero_matrix(SR,3,1)) dwfi[0] = copy(zero_matrix(SR,3,1)) ddpfi[0] = copy(zero_matrix(SR,3,1)) ddpci[0] = copy(zero_matrix(SR,3,1)) ffi[dof+1] = copy(zero_matrix(SR,3,1)) nfi[dof+1] = copy(zero_matrix(SR,3,1)) if do_varify: def custom_simplify( expression ): # return trig_reduce(expression.expand()).simplify_rational() return expression.simplify_rational() def varify_func(exp,varpool,varrepr): if varify_trig : exp = exp.subs( LoP_to_D(rbt.LoP_trig_f2v) ) exp = custom_simplify( exp ) return m_varify(exp,varpool,condition_func=is_compound) #return v3R_varify(exp,varpool,varrepr) auxvars = [] else: def varify_func(exp,varpool,varrepr): return exp auxvars = () # Forward for i in range(1,dof+1): wfi[i] = Rdhi[i].transpose() * ( wfi[i-1] + rbt.dq[i-1,0] * rbt.zi[0] ) wfi[i] = varify_func( wfi[i] , auxvars , 'wf_'+str(i) ) dwfi[i] = Rdhi[i].transpose() * ( dwfi[i-1] + rbt.ddq[i-1,0] * rbt.zi[0] \ + cross_product( rbt.dq[i-1,0] * wfi[i-1] , rbt.zi[0] ) ) dwfi[i] = varify_func( dwfi[i] , auxvars , 'dwf_'+str(i) ) ddpfi[i] = Rdhi[i].transpose() * ddpfi[i-1] + cross_product( dwfi[i] , rbt.pdhfi[i] ) \ + cross_product( wfi[i] , cross_product( wfi[i] , rbt.pdhfi[i] ) ) ddpfi[i] = varify_func( ddpfi[i] , auxvars , 'ddpf_'+str(i) ) ddpci[i] = ddpfi[i] + cross_product( dwfi[i] , rbt.li[i] ) \ + cross_product( wfi[i] , cross_product( wfi[i] , rbt.li[i] ) ) ddpci[i] = varify_func( ddpci[i] , auxvars , 'ddpc_'+str(i) ) # Backward if usemotordyn: nfi_motor = [zero_matrix(3,1) for i in xrange(dof+1)] for m in rbt.motors: Im = m[0]; 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( wfi[l] , zm ) for i in range(dof,0,-1): ffi[i] = Rdhi[i+1] * ffi[i+1] + rbt.mi[i] * ( ddpci[i] - rbt.Ri[i].transpose()*rbt.grav ) ffi[i] = varify_func( ffi[i] , auxvars , 'ff_'+str(i) ) nfi[i] = cross_product( - ffi[i] , rbt.pdhfi[i] + rbt.li[i] ) + Rdhi[i+1] * nfi[i+1] + \ cross_product( Rdhi[i+1] * ffi[i+1] , rbt.li[i] ) + rbt.Ici[i] * dwfi[i] + \ cross_product( wfi[i] , rbt.Ici[i] * wfi[i] ) if usemotordyn: nfi[i] += nfi_motor[i] nfi[i] = varify_func( nfi[i] , auxvars , 'nf_'+str(i) ) for i in range(1,dof+1): tau[i-1,0] = ( nfi[i].transpose() * Rdhi[i].transpose() * rbt.zi[0] )[0,0] if usemotordyn: for m in rbt.motors: Im = m[0]; 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 * ( ( dwfi[l] + ddqm * zm + dqm * cross_product( wfi[l] , zm ) ).transpose() * zm )[0,0] if do_varify: if varify_trig : auxvars = rbt.LoP_trig_v2f + auxvars return auxvars,tau else: return tau
def gen_tau_RNE( do_varify, rbt, usemotordyn=True, varify_trig = True ): 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) if do_varify: auxvars = [] def custom_simplify( expression ): # return trig_reduce(expression.expand()).simplify_rational() return expression.simplify_rational() 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,condition_func=is_compound) #return v6R_varify(exp,auxvars,varrepr) else: def varify_func(exp,varrepr): return exp Vi, dVi = _forward_RNE( rbt, Si, varify_func ) tau = _backward_RNE( rbt, IIi, Si, Vi, dVi, usemotordyn, None, varify_func = varify_func ) if do_varify: if varify_trig : auxvars = rbt.LoP_trig_v2f + auxvars return auxvars,tau else: return tau
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,
def perm_mat(i, j, n): l = identity_matrix(QQ, n).columns() l[i], l[j] = l[j], l[i] return matrix(l)