def complementary_subform_to_vector(self, v): """ Finds the `(n-1)`-dim'l quadratic form orthogonal to the vector `v`. Note: This is usually not a direct summand! Technical Notes: There is a minor difference in the cancellation code here (form the C++ version) since the notation Q `[i,j]` indexes coefficients of the quadratic polynomial here, not the symmetric matrix. Also, it produces a better splitting now, for the full lattice (as opposed to a sublattice in the C++ code) since we now extend `v` to a unimodular matrix. INPUT: `v` -- a list of self.dim() integers OUTPUT: a QuadraticForm over `ZZ` EXAMPLES:: sage: Q1 = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q1.complementary_subform_to_vector([1,0,0,0]) Quadratic form in 3 variables over Integer Ring with coefficients: [ 3 0 0 ] [ * 5 0 ] [ * * 7 ] :: sage: Q1.complementary_subform_to_vector([1,1,0,0]) Quadratic form in 3 variables over Integer Ring with coefficients: [ 12 0 0 ] [ * 5 0 ] [ * * 7 ] :: sage: Q1.complementary_subform_to_vector([1,1,1,1]) Quadratic form in 3 variables over Integer Ring with coefficients: [ 624 -480 -672 ] [ * 880 -1120 ] [ * * 1008 ] """ n = self.dim() ## Copy the quadratic form Q = deepcopy(self) ## Find the first non-zero component of v, and call it nz (Note: 0 <= nz < n) nz = 0 while (nz < n) and (v[nz] == 0): nz += 1 ## Abort if v is the zero vector if nz == n: raise TypeError("Oops, v cannot be the zero vector! =(") ## Make the change of basis matrix new_basis = extend_to_primitive(matrix(ZZ, n, 1, v)) ## Change Q (to Q1) to have v as its nz-th basis vector Q1 = Q(new_basis) ## Pick out the value Q(v) of the vector d = Q1[0, 0] ## For each row/column, perform elementary operations to cancel them out. for i in range(1, n): ## Check if the (i,0)-entry is divisible by d, ## and stretch its row/column if not. if Q1[i, 0] % d != 0: Q1 = Q1.multiply_variable(d / GCD(d, Q1[i, 0] // 2), i) ## Now perform the (symmetric) elementary operations to cancel out the (i,0) entries/ Q1 = Q1.add_symmetric(-(Q1[i, 0] / 2) / (GCD(d, Q1[i, 0] // 2)), i, 0) ## Check that we're done! done_flag = True for i in range(1, n): if Q1[0, i] != 0: done_flag = False if not done_flag: raise RuntimeError( "There is a problem cancelling out the matrix entries! =O") ## Return the complementary matrix return Q1.extract_variables(range(1, n))
def complementary_subform_to_vector(self, v): """ Finds the `(n-1)`-dim'l quadratic form orthogonal to the vector `v`. Note: This is usually not a direct summand! Technical Notes: There is a minor difference in the cancellation code here (form the C++ version) since the notation Q `[i,j]` indexes coefficients of the quadratic polynomial here, not the symmetric matrix. Also, it produces a better splitting now, for the full lattice (as opposed to a sublattice in the C++ code) since we now extend `v` to a unimodular matrix. INPUT: `v` -- a list of self.dim() integers OUTPUT: a QuadraticForm over `ZZ` EXAMPLES:: sage: Q1 = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q1.complementary_subform_to_vector([1,0,0,0]) Quadratic form in 3 variables over Integer Ring with coefficients: [ 3 0 0 ] [ * 5 0 ] [ * * 7 ] :: sage: Q1.complementary_subform_to_vector([1,1,0,0]) Quadratic form in 3 variables over Integer Ring with coefficients: [ 12 0 0 ] [ * 5 0 ] [ * * 7 ] :: sage: Q1.complementary_subform_to_vector([1,1,1,1]) Quadratic form in 3 variables over Integer Ring with coefficients: [ 624 -480 -672 ] [ * 880 -1120 ] [ * * 1008 ] """ n = self.dim() ## Copy the quadratic form Q = deepcopy(self) ## Find the first non-zero component of v, and call it nz (Note: 0 <= nz < n) nz = 0 while (nz < n) and (v[nz] == 0): nz += 1 ## Abort if v is the zero vector if nz == n: raise TypeError("Oops, v cannot be the zero vector! =(") ## Make the change of basis matrix new_basis = extend_to_primitive(matrix(ZZ,n,1,v)) ## Change Q (to Q1) to have v as its nz-th basis vector Q1 = Q(new_basis) ## Pick out the value Q(v) of the vector d = Q1[0, 0] #print Q1 ## For each row/column, perform elementary operations to cancel them out. for i in range(1,n): ## Check if the (i,0)-entry is divisible by d, ## and stretch its row/column if not. if Q1[i,0] % d != 0: Q1 = Q1.multiply_variable(d / GCD(d, Q1[i, 0]//2), i) #print "After scaling at i =", i #print Q1 ## Now perform the (symmetric) elementary operations to cancel out the (i,0) entries/ Q1 = Q1.add_symmetric(-(Q1[i,0]/2) / (GCD(d, Q1[i,0]//2)), i, 0) #print "After cancelling at i =", i #print Q1 ## Check that we're done! done_flag = True for i in range(1, n): if Q1[0,i] != 0: done_flag = False if done_flag == False: raise RuntimeError("There is a problem cancelling out the matrix entries! =O") ## Return the complementary matrix return Q1.extract_variables(range(1,n))
def find_p_neighbor_from_vec(self, p, v): """ Finds the `p`-neighbor of this quadratic form associated to a given vector `v` satisfying: #. `Q(v) = 0 \pmod p` #. `v` is a non-singular point of the conic `Q(v) = 0 \pmod p`. Reference: Gonzalo Tornaria's Thesis, Thrm 3.5, p34. EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ,[1,1,1,1]) sage: v = vector([0,2,1,1]) sage: X = Q.find_p_neighbor_from_vec(3,v); X Quadratic form in 4 variables over Integer Ring with coefficients: [ 3 10 0 -4 ] [ * 9 0 -6 ] [ * * 1 0 ] [ * * * 2 ] """ R = self.base_ring() n = self.dim() B2 = self.matrix() ## Find a (dual) vector w with B(v,w) != 0 (mod p) v_dual = B2 * vector(v) ## We want the dot product with this to not be divisible by 2*p. y_ind = 0 while ((y_ind < n) and (v_dual[y_ind] % p) == 0): ## Check the dot product for the std basis vectors! y_ind += 1 if y_ind == n: raise RuntimeError("Oops! One of the standard basis vectors should have worked.") w = vector([R(i == y_ind) for i in range(n)]) vw_prod = (v * self.matrix()).dot_product(w) ## DIAGNOSTIC #if vw_prod == 0: # print "v = ", v # print "v_dual = ", v_dual # print "v_dual[y_ind] = ", v_dual[y_ind] # print "(v_dual[y_ind] % p) = ", (v_dual[y_ind] % p) # print "w = ", w # print "p = ", p # print "vw_prod = ", vw_prod # raise RuntimeError, "ERROR: Why is vw_prod = 0?" ## DIAGNOSTIC #print "v = ", v #print "w = ", w #print "vw_prod = ", vw_prod ## Lift the vector v to a vector v1 s.t. Q(v1) = 0 (mod p^2) s = self(v) if (s % p**2 != 0): al = (-s / (p * vw_prod)) % p v1 = v + p * al * w v1w_prod = (v1 * self.matrix()).dot_product(w) else: v1 = v v1w_prod = vw_prod ## DIAGNOSTIC #if (s % p**2 != 0): # print "al = ", al #print "v1 = ", v1 #print "v1w_prod = ", v1w_prod ## Construct a special p-divisible basis to use for the p-neighbor switch good_basis = extend_to_primitive([v1, w]) for i in range(2,n): ith_prod = (good_basis[i] * self.matrix()).dot_product(v) c = (ith_prod / v1w_prod) % p good_basis[i] = good_basis[i] - c * w ## Ensures that this extension has <v_i, v> = 0 (mod p) ## DIAGNOSTIC #print "original good_basis = ", good_basis ## Perform the p-neighbor switch good_basis[0] = vector([x/p for x in good_basis[0]]) ## Divide v1 by p good_basis[1] = good_basis[1] * p ## Multiply w by p ## Return the associated quadratic form M = matrix(good_basis) new_Q = deepcopy(self) ## Note: This avoids a circular import of QuadraticForm! new_Q.__init__(R, M * self.matrix() * M.transpose()) return new_Q return QuadraticForm(R, M * self.matrix() * M.transpose())
def find_p_neighbor_from_vec(self, p, v): """ Finds the `p`-neighbor of this quadratic form associated to a given vector `v` satisfying: #. `Q(v) = 0 \pmod p` #. `v` is a non-singular point of the conic `Q(v) = 0 \pmod p`. Reference: Gonzalo Tornaria's Thesis, Thrm 3.5, p34. EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ,[1,1,1,1]) sage: v = vector([0,2,1,1]) sage: X = Q.find_p_neighbor_from_vec(3,v); X Quadratic form in 4 variables over Integer Ring with coefficients: [ 3 10 0 -4 ] [ * 9 0 -6 ] [ * * 1 0 ] [ * * * 2 ] """ R = self.base_ring() n = self.dim() B2 = self.matrix() ## Find a (dual) vector w with B(v,w) != 0 (mod p) v_dual = B2 * vector( v) ## We want the dot product with this to not be divisible by 2*p. y_ind = 0 while ((y_ind < n) and (v_dual[y_ind] % p) == 0): ## Check the dot product for the std basis vectors! y_ind += 1 if y_ind == n: raise RuntimeError( "Oops! One of the standard basis vectors should have worked.") w = vector([R(i == y_ind) for i in range(n)]) vw_prod = (v * self.matrix()).dot_product(w) ## DIAGNOSTIC #if vw_prod == 0: # print "v = ", v # print "v_dual = ", v_dual # print "v_dual[y_ind] = ", v_dual[y_ind] # print "(v_dual[y_ind] % p) = ", (v_dual[y_ind] % p) # print "w = ", w # print "p = ", p # print "vw_prod = ", vw_prod # raise RuntimeError, "ERROR: Why is vw_prod = 0?" ## DIAGNOSTIC #print "v = ", v #print "w = ", w #print "vw_prod = ", vw_prod ## Lift the vector v to a vector v1 s.t. Q(v1) = 0 (mod p^2) s = self(v) if (s % p**2 != 0): al = (-s / (p * vw_prod)) % p v1 = v + p * al * w v1w_prod = (v1 * self.matrix()).dot_product(w) else: v1 = v v1w_prod = vw_prod ## DIAGNOSTIC #if (s % p**2 != 0): # print "al = ", al #print "v1 = ", v1 #print "v1w_prod = ", v1w_prod ## Construct a special p-divisible basis to use for the p-neighbor switch good_basis = extend_to_primitive([v1, w]) for i in range(2, n): ith_prod = (good_basis[i] * self.matrix()).dot_product(v) c = (ith_prod / v1w_prod) % p good_basis[i] = good_basis[ i] - c * w ## Ensures that this extension has <v_i, v> = 0 (mod p) ## DIAGNOSTIC #print "original good_basis = ", good_basis ## Perform the p-neighbor switch good_basis[0] = vector([x / p for x in good_basis[0]]) ## Divide v1 by p good_basis[1] = good_basis[1] * p ## Multiply w by p ## Return the associated quadratic form M = matrix(good_basis) new_Q = deepcopy( self) ## Note: This avoids a circular import of QuadraticForm! new_Q.__init__(R, M * self.matrix() * M.transpose()) return new_Q return QuadraticForm(R, M * self.matrix() * M.transpose())
def find_p_neighbor_from_vec(self, p, v): r""" Find the `p`-neighbor of this quadratic form associated to a given vector `v` satisfying: #. `Q(v) = 0 \pmod p` #. `v` is a non-singular point of the conic `Q(v) = 0 \pmod p`. Reference: Gonzalo Tornaria's Thesis, Theorem 3.5, p34. EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ,[1,1,1,1]) sage: v = vector([0,2,1,1]) sage: X = Q.find_p_neighbor_from_vec(3,v); X Quadratic form in 4 variables over Integer Ring with coefficients: [ 3 10 0 -4 ] [ * 9 0 -6 ] [ * * 1 0 ] [ * * * 2 ] """ R = self.base_ring() n = self.dim() B2 = self.matrix() # Find a (dual) vector w with B(v,w) != 0 (mod p) # We want the dot product with this to not be divisible by 2*p. v_dual = B2 * vector(v) y_ind = 0 while ((y_ind < n) and (v_dual[y_ind] % p) == 0): # Check the dot product for the std basis vectors! y_ind += 1 if y_ind == n: raise RuntimeError("Oops! One of the standard basis vectors " "should have worked.") w = vector(R, [R(i == y_ind) for i in range(n)]) vw_prod = (v * self.matrix()).dot_product(w) # Lift the vector v to a vector v1 s.t. Q(v1) = 0 (mod p^2) s = self(v) if (s % p**2 != 0): al = (-s / (p * vw_prod)) % p v1 = v + p * al * w v1w_prod = (v1 * self.matrix()).dot_product(w) else: v1 = v v1w_prod = vw_prod # Construct a special p-divisible basis to use for the p-neighbor switch good_basis = extend_to_primitive([v1, w]) for i in range(2, n): ith_prod = (good_basis[i] * self.matrix()).dot_product(v) c = (ith_prod / v1w_prod) % p good_basis[i] = good_basis[i] - c * w # Ensures that this extension has <v_i, v> = 0 (mod p) # Perform the p-neighbor switch good_basis[0] = vector([x / p for x in good_basis[0]]) # Divide v1 by p good_basis[1] = good_basis[1] * p # Multiply w by p # Return the associated quadratic form M = matrix(good_basis) QF = self.parent() return QF(R, M * self.matrix() * M.transpose())