def level_ideal(self): """ Determines the level of the quadratic form (over R), which is the smallest ideal N of R such that N * (the matrix of 2*Q)^(-1) is in R with diagonal in 2*R. (Caveat: This always returns the principal ideal when working over a field!) WARNING: THIS ONLY WORKS OVER A PID RING OF INTEGERS FOR NOW! (Waiting for Sage fractional ideal support.) EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, range(1,4)) sage: Q.level_ideal() Principal ideal (8) of Integer Ring :: sage: Q1 = QuadraticForm(QQ, 2, range(1,4)) sage: Q1.level_ideal() Principal ideal (1) of Rational Field :: sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.level_ideal() Principal ideal (420) of Integer Ring """ ############################################################## ## To do this properly, the level should be the inverse of the ## fractional ideal (over R) generated by the entries whose ## denominators we take above. =) ############################################################## return ideal(self.base_ring()(self.level()))
def level(self): r""" Determines the level of the quadratic form over a PID, which is a generator for the smallest ideal `N` of `R` such that N * (the matrix of 2*Q)^(-1) is in R with diagonal in 2*R. Over `\ZZ` this returns a non-negative number. (Caveat: This always returns the unit ideal when working over a field!) EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, range(1,4)) sage: Q.level() 8 sage: Q1 = QuadraticForm(QQ, 2, range(1,4)) sage: Q1.level() # random UserWarning: Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!? 1 sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Q.level() 420 """ ## Try to return the cached level try: return self.__level except AttributeError: ## Check that the base ring is a PID if not is_PrincipalIdealDomain(self.base_ring()): raise TypeError("Oops! The level (as a number) is only defined over a Principal Ideal Domain. Try using level_ideal().") ## Warn the user if the form is defined over a field! if self.base_ring().is_field(): warn("Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!?") #raise RuntimeError, "Warning -- The level of a quadratic form over a field is always 1. Do you really want to do this?!?" ## Check invertibility and find the inverse try: mat_inv = self.matrix()**(-1) except ZeroDivisionError: raise TypeError("Oops! The quadratic form is degenerate (i.e. det = 0). =(") ## Compute the level inv_denoms = [] for i in range(self.dim()): for j in range(i, self.dim()): if (i == j): inv_denoms += [denominator(mat_inv[i,j] / 2)] else: inv_denoms += [denominator(mat_inv[i,j])] lvl = LCM(inv_denoms) lvl = ideal(self.base_ring()(lvl)).gen() ############################################################## ## To do this properly, the level should be the inverse of the ## fractional ideal (over R) generated by the entries whose ## denominators we take above. =) ############################################################## ## Normalize the result over ZZ if self.base_ring() == IntegerRing(): lvl = abs(lvl) ## Cache and return the level self.__level = lvl return lvl