def to_HNFRepresentation(self): """ Transform self to the corresponding ideal as HNF representation """ int_ring = self.number_field.integer_ring() n = self.number_field.degree polynomial = self.number_field.polynomial k = len(self.generator) # separate coeff and denom for generators and base gen_denom = reduce( gcd.lcm, (self.generator[j].denom for j in range(k)) ) gen_list = [gen_denom * self.generator[j] for j in range(k)] base_int, base_denom = _toIntegerMatrix(int_ring) base_alg = [BasicAlgNumber([base_int[j], 1], polynomial) for j in range(1, n + 1)] repr_mat_list = [] for gen in gen_list: for base in base_alg: new_gen = gen * base repr_mat_list.append( vector.Vector([new_gen.coeff[j] for j in range(n)])) mat_repr = matrix.RingMatrix(n, n * k, repr_mat_list) new_mat_repr, numer = _toIntegerMatrix(mat_repr, 2) denom = gen_denom * base_denom denom_gcd = gcd.gcd(numer, denom) if denom_gcd != 1: denom = ring.exact_division(denom, denom_gcd) numer = ring.exact_division(numer, denom_gcd) if numer != 1: new_mat_repr = numer * new_mat_repr else: new_mat_repr = mat_repr return Ideal([new_mat_repr, denom], self.number_field)
def change_base_module(self, other_base): """ change base_module to other_base_module (i.e. represent with respect to base_module) """ if self.base == other_base: return self n = self.number_field.degree if isinstance(other_base, list): other_base = matrix.FieldSquareMatrix(n, [vector.Vector(other_base[i]) for i in range(n)]) else: # matrix repr other_base = other_base.copy() tr_base_mat, tr_base_denom = _toIntegerMatrix( other_base.inverse(self.base)) denom = tr_base_denom * self.denominator mat_repr, numer = _toIntegerMatrix( tr_base_mat * self.mat_repr, 2) d = gcd.gcd(denom, numer) if d != 1: denom = ring.exact_division(denom, d) numer = ring.exact_division(numer, d) if numer != 1: mat_repr = numer * mat_repr return self.__class__([mat_repr, denom], self.number_field, other_base)
def intersect(self, other): """ return intersection of self and other """ # if self.number_field != other.number_field: # raise ValueError("based on different number field") if self.base != other.base: new_self = self.change_base_module(other.base) else: new_self = self.copy() new_denominator = gcd.lcm(new_self.denominator, other.denominator) if new_self.denominator != new_denominator: multiply_denom = ring.exact_division(new_denominator, new_self.denominator) new_self_mat_repr = multiply_denom * new_self.mat_repr else: new_self_mat_repr = new_self.mat_repr if other.denominator != new_denominator: multiply_denom = ring.exact_division(new_denominator, other.denominator) new_other_mat_repr = multiply_denom * other.mat_repr else: new_other_mat_repr = other.mat_repr new_mat_repr = Submodule.fromMatrix( new_self_mat_repr).intersectionOfSubmodules(new_other_mat_repr) new_module = self.__class__([new_mat_repr, new_denominator], self.number_field, other.base) new_module._simplify() return new_module
def intersect(self, other): """ return intersection of self and other """ # if self.number_field != other.number_field: # raise ValueError("based on different number field") if self.base != other.base: new_self = self.change_base_module(other.base) else: new_self = self.copy() new_denominator = gcd.lcm(new_self.denominator, other.denominator) if new_self.denominator != new_denominator: multiply_denom = ring.exact_division( new_denominator, new_self.denominator) new_self_mat_repr = multiply_denom * new_self.mat_repr else: new_self_mat_repr = new_self.mat_repr if other.denominator != new_denominator: multiply_denom = ring.exact_division( new_denominator, other.denominator) new_other_mat_repr = multiply_denom * other.mat_repr else: new_other_mat_repr = other.mat_repr new_mat_repr = Submodule.fromMatrix( new_self_mat_repr).intersectionOfSubmodules(new_other_mat_repr) new_module = self.__class__( [new_mat_repr, new_denominator], self.number_field, other.base) new_module._simplify() return new_module
def _simplify(self): """ simplify self.denominator """ mat_repr, numer = _toIntegerMatrix(self.mat_repr, 2) denom_gcd = gcd.gcd(numer, self.denominator) if denom_gcd != 1: self.denominator = ring.exact_division(self.denominator, denom_gcd) self.mat_repr = Submodule.fromMatrix( ring.exact_division(numer, denom_gcd) * mat_repr)
def _toIntegerMatrix(mat, option=0): """ transform a (including integral) rational matrix to some integral matrix as the following [option] 0: return integral-matrix, denominator (mat = 1/denominator * integral-matrix) 1: return integral-matrix, denominator, numerator (mat = numerator/denominator * reduced-int-matrix) 2: return integral-matrix, numerator (assuming mat is integral) (mat = numerator * numerator-reduced-rational-matrix) """ def getDenominator(ele): """ get the denominator of ele """ if rational.isIntegerObject(ele): return 1 else: # rational return ele.denominator def getNumerator(ele): """ get the numerator of ele """ if rational.isIntegerObject(ele): return ele else: # rational return ele.numerator if isinstance(mat, vector.Vector): mat = mat.toMatrix(True) if option <= 1: denom = mat.reduce( lambda x, y: gcd.lcm(x, getDenominator(y)), 1) new_mat = mat.map( lambda x: getNumerator(x) * ring.exact_division( denom, getDenominator(x))) if option == 0: return Submodule.fromMatrix(new_mat), denom else: new_mat = mat numer = new_mat.reduce( lambda x, y: gcd.gcd(x, getNumerator(y))) if numer != 0: new_mat2 = new_mat.map( lambda x: ring.exact_division(getNumerator(x), numer)) else: new_mat2 = new_mat if option == 1: return Submodule.fromMatrix(new_mat2), denom, numer else: return Submodule.fromMatrix(new_mat2), numer
def __contains__(self, other): """ Check whether other is an element of self or not """ #if not(other in self.number_field): # return False if isinstance(other, (tuple, vector.Vector)): #vector repr other_int, other_denom = _toIntegerMatrix(vector.Vector(other)) elif isinstance(other, list): if isinstance(other[0], (tuple, vector.Vector)): other_int = vector.Vector(other[0]) other_denom = other[1] else: raise ValueError("input [vector, denominator]!") else: # field element if not isinstance(other, BasicAlgNumber): other_copy = other.ch_basic() else: other_copy = other other_base_repr = self.base.inverse(vector.Vector( other_copy.coeff)) other_int, other_int_denom = _toIntegerMatrix(other_base_repr) other_denom = other_int_denom * other_copy.denom if isinstance(other_int, matrix.Matrix): other_int = other_int[1] try: numer = ring.exact_division(self.denominator, other_denom) except ValueError: # division is not exact return False if numer != 1: other_vect = numer * other_int else: other_vect = other_int return not isinstance(self.mat_repr.represent_element(other_vect), bool)
def __contains__(self, other): """ Check whether other is an element of self or not """ #if not(other in self.number_field): # return False if isinstance(other, (tuple, vector.Vector)): #vector repr other_int, other_denom = _toIntegerMatrix(vector.Vector(other)) elif isinstance(other, list): if isinstance(other[0], (tuple, vector.Vector)): other_int = vector.Vector(other[0]) other_denom = other[1] else: raise ValueError("input [vector, denominator]!") else: # field element if not isinstance(other, BasicAlgNumber): other_copy = other.ch_basic() else: other_copy = other other_base_repr = self.base.inverse( vector.Vector(other_copy.coeff)) other_int, other_int_denom = _toIntegerMatrix(other_base_repr) other_denom = other_int_denom * other_copy.denom if isinstance(other_int, matrix.Matrix): other_int = other_int[1] try: numer = ring.exact_division(self.denominator, other_denom) except ValueError: # division is not exact return False if numer != 1: other_vect = numer * other_int else: other_vect = other_int return not isinstance( self.mat_repr.represent_element(other_vect), bool)
def twoElementRepresentation(self): # refer to [Poh-Zas] # Algorithm 4.7.10 and Exercise 29 in CCANT """ Reduce the number of generator to only two elements Warning: If self is not a prime ideal, this method is not efficient """ k = len(self.generator) gen_denom = reduce( gcd.lcm, (self.generator[j].denom for j in range(k)) ) gen_list = [gen_denom * self.generator[j] for j in range(k)] int_I = Ideal_with_generator(gen_list) R = 1 norm_I = int_I.norm() l_I = int_I.smallest_rational() if l_I.denominator > 1: raise ValueError, "input an integral ideal" else: l_I = l_I.numerator while True: lmda = [R for i in range(k)] while lmda[0] > 0: alpha = lmda[0] * gen_list[0] for i in range(1, k): alpha += lmda[i] * gen_list[i] if gcd.gcd( norm_I, ring.exact_division( alpha.norm(), norm_I) ) == 1 or gcd.gcd( norm_I, ring.exact_division( (alpha + l_I).norm(), norm_I)) == 1: l_I_ori = BasicAlgNumber( [[l_I] + [0] * (self.number_field.degree - 1), gen_denom], self.number_field.polynomial) alpha_ori = BasicAlgNumber([alpha.coeff, gen_denom], self.number_field.polynomial) return Ideal_with_generator([l_I_ori, alpha_ori]) for j in range(k)[::-1]: if lmda[j] != -R: lmda[j] -= 1 break else: lmda[j] = R R += 1
def twoElementRepresentation(self): # refer to [Poh-Zas] # Algorithm 4.7.10 and Exercise 29 in CCANT """ Reduce the number of generator to only two elements Warning: If self is not a prime ideal, this method is not efficient """ k = len(self.generator) gen_denom = reduce(gcd.lcm, (self.generator[j].denom for j in range(k))) gen_list = [gen_denom * self.generator[j] for j in range(k)] int_I = Ideal_with_generator(gen_list) R = 1 norm_I = int_I.norm() l_I = int_I.smallest_rational() if l_I.denominator > 1: raise ValueError, "input an integral ideal" else: l_I = l_I.numerator while True: lmda = [R for i in range(k)] while lmda[0] > 0: alpha = lmda[0] * gen_list[0] for i in range(1, k): alpha += lmda[i] * gen_list[i] if gcd.gcd(norm_I, ring.exact_division( alpha.norm(), norm_I)) == 1 or gcd.gcd( norm_I, ring.exact_division( (alpha + l_I).norm(), norm_I)) == 1: l_I_ori = BasicAlgNumber( [[l_I] + [0] * (self.number_field.degree - 1), gen_denom], self.number_field.polynomial) alpha_ori = BasicAlgNumber([alpha.coeff, gen_denom], self.number_field.polynomial) return Ideal_with_generator([l_I_ori, alpha_ori]) for j in range(k)[::-1]: if lmda[j] != -R: lmda[j] -= 1 break else: lmda[j] = R R += 1
def _scalar_mul(self, other): """ return other * self, assuming other is a scalar (i.e. an element of self.number_field) """ # use other is an element of higher or lower degree number field ? #if other.getRing() != self.number_field: # raise NotImplementedError( # "other is not a element of number field") if not isinstance(other, BasicAlgNumber): try: other = other.ch_basic() except: raise NotImplementedError( "other is not an element of a number field") # represent other with respect to self.base other_repr, pseudo_other_denom = _toIntegerMatrix( self.base.inverse(vector.Vector(other.coeff))) other_repr = other_repr[1] # compute mul using self.base's multiplication base_mul = self._base_multiplication() n = self.number_field.degree mat_repr = [] for k in range(1, self.mat_repr.column + 1): mat_repr_ele = vector.Vector([0] * n) for i1 in range(1, n + 1): for i2 in range(1, n + 1): mat_repr_ele += self.mat_repr[ i1, k] * other_repr[i2] * _symmetric_element( i1, i2, base_mul) mat_repr.append(mat_repr_ele) mat_repr, denom, numer = _toIntegerMatrix( matrix.FieldMatrix(n, len(mat_repr), mat_repr), 1) denom = self.denominator * pseudo_other_denom * other.denom * denom gcds = gcd.gcd(denom, numer) if gcds != 1: denom = ring.exact_division(denom, gcds) numer = ring.exact_division(numer, gcds) if numer != 1: mat_repr = numer * mat_repr else: mat_repr = mat_repr return self.__class__([mat_repr, denom], self.number_field, self.base)
def _scalar_mul(self, other): """ return other * self, assuming other is a scalar (i.e. an element of self.number_field) """ # use other is an element of higher or lower degree number field ? #if other.getRing() != self.number_field: # raise NotImplementedError( # "other is not a element of number field") if not isinstance(other, BasicAlgNumber): try: other = other.ch_basic() except: raise NotImplementedError( "other is not an element of a number field") # represent other with respect to self.base other_repr, pseudo_other_denom = _toIntegerMatrix( self.base.inverse(vector.Vector(other.coeff))) other_repr = other_repr[1] # compute mul using self.base's multiplication base_mul = self._base_multiplication() n = self.number_field.degree mat_repr = [] for k in range(1, self.mat_repr.column +1): mat_repr_ele = vector.Vector([0] * n) for i1 in range(1, n + 1): for i2 in range(1, n + 1): mat_repr_ele += self.mat_repr[i1, k] * other_repr[ i2] * _symmetric_element(i1, i2, base_mul) mat_repr.append(mat_repr_ele) mat_repr, denom, numer = _toIntegerMatrix( matrix.FieldMatrix(n, len(mat_repr), mat_repr), 1) denom = self.denominator * pseudo_other_denom * other.denom * denom gcds = gcd.gcd(denom, numer) if gcds != 1: denom = ring.exact_division(denom, gcds) numer = ring.exact_division(numer, gcds) if numer != 1: mat_repr = numer * mat_repr else: mat_repr = mat_repr return self.__class__([mat_repr, denom], self.number_field, self.base)
def inverse(self): """ Return the inverse ideal of self """ # Algorithm 4.8.21 in CCANT field = self.number_field # step 1 (Note that det(T)T^-1=(adjugate matrix of T)) T = Ideal._precompute_for_different(field) d = int(T.determinant()) inv_different = Ideal([T.adjugateMatrix(), 1], field, field.integer_ring()) # step 2 inv_I = self * inv_different # already base is taken for integer_ring inv_I.toHNF() # step 3 inv_mat, denom = _toIntegerMatrix( (inv_I.mat_repr.transpose() * T).inverse(), 0) numer = d * inv_I.denominator gcd_denom = gcd.gcd(denom, numer) if gcd_denom != 1: denom = ring.exact_division(denom, gcd_denom) numer = ring.exact_division(numer, gcd_denom) return Ideal([numer * inv_mat, denom], field, field.integer_ring())
def _module_mul(self, other): """ return self * other as the multiplication of modules """ #if self.number_field != other.number_field: # raise NotImplementedError if self.base != other.base: new_self = self.change_base_module(other.base) else: new_self = self.copy() base_mul = other._base_multiplication() n = self.number_field.degree new_mat_repr = [] for k1 in range(1, new_self.mat_repr.column + 1): for k2 in range(1, other.mat_repr.column + 1): new_mat_repr_ele = vector.Vector([0] * n) for i1 in range(1, n + 1): for i2 in range(1, n + 1): new_mat_repr_ele += new_self.mat_repr[ i1, k1] * other.mat_repr[i2, k2] * _symmetric_element( i1, i2, base_mul) new_mat_repr.append(new_mat_repr_ele) new_mat_repr, denom, numer = _toIntegerMatrix( matrix.FieldMatrix(n, len(new_mat_repr), new_mat_repr), 1) denom = new_self.denominator * other.denominator * denom gcds = gcd.gcd(denom, numer) if gcds != 1: denom = ring.exact_division(denom, gcds) numer = ring.exact_division(numer, gcds) if numer != 1: mat_repr = numer * new_mat_repr else: mat_repr = new_mat_repr sol = self.__class__([mat_repr, denom], self.number_field, other.base) sol.toHNF() return sol
def _module_mul(self, other): """ return self * other as the multiplication of modules """ #if self.number_field != other.number_field: # raise NotImplementedError if self.base != other.base: new_self = self.change_base_module(other.base) else: new_self = self.copy() base_mul = other._base_multiplication() n = self.number_field.degree new_mat_repr = [] for k1 in range(1, new_self.mat_repr.column + 1): for k2 in range(1, other.mat_repr.column + 1): new_mat_repr_ele = vector.Vector([0] * n) for i1 in range(1, n + 1): for i2 in range(1, n + 1): new_mat_repr_ele += new_self.mat_repr[ i1, k1] * other.mat_repr[i2, k2 ] * _symmetric_element(i1, i2, base_mul) new_mat_repr.append(new_mat_repr_ele) new_mat_repr, denom, numer = _toIntegerMatrix( matrix.FieldMatrix(n, len(new_mat_repr), new_mat_repr), 1) denom = new_self.denominator * other.denominator * denom gcds = gcd.gcd(denom, numer) if gcds != 1: denom = ring.exact_division(denom, gcds) numer = ring.exact_division(numer, gcds) if numer != 1: mat_repr = numer * new_mat_repr else: mat_repr = new_mat_repr sol = self.__class__( [mat_repr, denom], self.number_field, other.base) sol.toHNF() return sol
def _HNF_solve(self, other): """ return X over coeff_ring s.t. self * X = other, where self is HNF, other is vector """ if self.row != len(other): raise vector.VectorSizeError() n = self.column zero = self.coeff_ring.zero X = vector.Vector([zero] * n) # search non-zero entry for i in range(1, self.row + 1)[::-1]: if self[i, n] != zero: break if other[i] != zero: return False else: return X # solve HNF system (only integral solution) for j in range(1, n + 1)[::-1]: sum_i = other[i] for k in range(j + 1, n + 1): sum_i -= X[k] * self[i, k] try: X[j] = ring.exact_division(sum_i, self[i, j]) except ValueError: # division is not exact return False ii = i i -= 1 for i in range(1, ii)[::-1]: if j != 1 and self[i, j - 1] != zero: break sum_i = X[j] * self[i, j] for k in range(j + 1, n + 1): sum_i += X[k] * self[i, k] if sum_i != other[i]: return False if i == 0: break return X
def _rational_mul(self, other): """ return other * self, assuming other is a rational element """ if rational.isIntegerObject(other): other_numerator = rational.Integer(other) other_denominator = rational.Integer(1) else: other_numerator = other.numerator other_denominator = other.denominator denom_gcd = gcd.gcd(self.denominator, other_numerator) if denom_gcd != 1: new_denominator = ring.exact_division( self.denominator, denom_gcd) * other_denominator multiply_num = other_numerator.exact_division(denom_gcd) else: new_denominator = self.denominator * other_denominator multiply_num = other_numerator new_module = self.__class__( [self.mat_repr * multiply_num, new_denominator], self.number_field, self.base, self.mat_repr.ishnf) new_module._simplify() return new_module
def represent_element(self, other): """ represent other as a linear combination with generators of self if other not in self, return False Note that we do not assume self.mat_repr is HNF """ #if other not in self.number_field: # return False theta_repr = (self.base * self.mat_repr) theta_repr.toFieldMatrix() pseudo_vect_repr = theta_repr.inverseImage( vector.Vector(other.coeff)) pseudo_vect_repr = pseudo_vect_repr[1] gcd_self_other = gcd.gcd(self.denominator, other.denom) multiply_numerator = self.denominator // gcd_self_other multiply_denominator = other.denom // gcd_self_other def getNumerator_and_Denominator(ele): """ get the pair of numerator and denominator of ele """ if rational.isIntegerObject(ele): return (ele, 1) else: # rational return (ele.numerator, ele.denominator) list_repr = [] for j in range(1, len(pseudo_vect_repr) + 1): try: numer, denom = getNumerator_and_Denominator( pseudo_vect_repr[j]) list_repr_ele = ring.exact_division( numer * multiply_numerator, denom * multiply_denominator) list_repr.append(list_repr_ele) except ValueError: # division is not exact return False return list_repr