def _evalf_(self, x, **kwds): """ TESTS: Check that :trac:`16587` is fixed:: sage: M = sgn(3/2, hold=True); M sgn(3/2) sage: M.n() 1 sage: h(x) = sgn(x) sage: h(pi).numerical_approx() 1.00000000000000 """ if hasattr(x,'sign'): # First check if x has a sign method return x.sign() if hasattr(x,'sgn'): # or a sgn method return x.sgn() approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return ZZ(0) # Now we have a non-zero real if bool((approx_x**(0.5)).imag() == 0): # Check: x > 0 return ZZ(1) else: return ZZ(-1) raise ValueError("Numeric evaluation of symbolic expression")
def _evalf_(self, x, **kwds): """ TESTS: Check that :trac:`16587` is fixed:: sage: M = sgn(3/2, hold=True); M sgn(3/2) sage: M.n() 1 sage: h(x) = sgn(x) sage: h(pi).numerical_approx() 1.00000000000000 """ if hasattr(x, 'sign'): # First check if x has a sign method return x.sign() if hasattr(x, 'sgn'): # or a sgn method return x.sgn() approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return ZZ(0) # Now we have a non-zero real if bool((approx_x**(0.5)).imag() == 0): # Check: x > 0 return ZZ(1) else: return ZZ(-1) raise ValueError("Numeric evaluation of symbolic expression")
def _eval_(self, x): """ INPUT: - ``x`` - a real number or a symbolic expression EXAMPLES:: sage: dirac_delta(1) 0 sage: dirac_delta(0) dirac_delta(0) sage: dirac_delta(x) dirac_delta(x) sage: dirac_delta(exp(-10000000000000000000)) 0 Evaluation test:: sage: dirac_delta(x).subs(x=1) 0 """ try: approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return None else: return 0 except StandardError: # x is symbolic pass return None
def _eval_(self, x): """ INPUT: - ``x`` - a real number or a symbolic expression EXAMPLES:: sage: dirac_delta(1) 0 sage: dirac_delta(0) dirac_delta(0) sage: dirac_delta(x) dirac_delta(x) sage: dirac_delta(exp(-10000000000000000000)) 0 Evaluation test:: sage: dirac_delta(x).subs(x=1) 0 """ try: approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return None else: return 0 except Exception: # x is symbolic pass return None
def _is_numerically_zero_CIF(x): from sage.rings.all import ComplexIntervalField try: approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0) and bool(approx_x.real() == 0): return True except: return False
def _eval_(self, x): """ EXAMPLES:: sage: sgn(-1) -1 sage: sgn(1) 1 sage: sgn(0) 0 sage: sgn(x) sgn(x) sage: sgn(-exp(-10000000000000000000)) -1 Evaluation test:: sage: sgn(x).subs(x=1) 1 sage: sgn(x).subs(x=0) 0 sage: sgn(x).subs(x=-1) -1 More tests:: sage: sign(RR(2)) 1 sage: sign(RDF(2)) 1 sage: sign(AA(-2)) -1 sage: sign(AA(0)) 0 """ if hasattr(x, 'sign'): # First check if x has a sign method return x.sign() if hasattr(x, 'sgn'): # or a sgn method return x.sgn() try: approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return ZZ(0) # Now we have a non-zero real if bool((approx_x**(0.5)).imag() == 0): # Check: x > 0 return ZZ(1) else: return ZZ(-1) except StandardError: # x is symbolic pass return None
def _eval_(self, x): """ EXAMPLES:: sage: sgn(-1) -1 sage: sgn(1) 1 sage: sgn(0) 0 sage: sgn(x) sgn(x) sage: sgn(-exp(-10000000000000000000)) -1 Evaluation test:: sage: sgn(x).subs(x=1) 1 sage: sgn(x).subs(x=0) 0 sage: sgn(x).subs(x=-1) -1 More tests:: sage: sign(RR(2)) 1 sage: sign(RDF(2)) 1 sage: sign(AA(-2)) -1 sage: sign(AA(0)) 0 """ if hasattr(x,'sign'): # First check if x has a sign method return x.sign() if hasattr(x,'sgn'): # or a sgn method return x.sgn() try: approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return ZZ(0) # Now we have a non-zero real if bool((approx_x**(0.5)).imag() == 0): # Check: x > 0 return ZZ(1) else: return ZZ(-1) except Exception: # x is symbolic pass return None
def _eval_(self, x): """ INPUT: - ``x`` - a real number or a symbolic expression EXAMPLES:: sage: heaviside(-1/2) 0 sage: heaviside(1) 1 sage: heaviside(0) heaviside(0) sage: heaviside(x) heaviside(x) sage: heaviside(exp(-1000000000000000000000)) 1 Evaluation test:: sage: heaviside(x).subs(x=1) 1 sage: heaviside(x).subs(x=-1) 0 :: sage: ex = heaviside(x)+1 sage: t = loads(dumps(ex)); t heaviside(x) + 1 sage: bool(t == ex) True sage: t.subs(x=1) 2 """ try: approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return None # Now we have a non-zero real if bool((approx_x**(0.5)).imag() == 0): # Check: x > 0 return 1 else: return 0 except Exception: # x is symbolic pass return None
def _eval_(self, x): """ INPUT: - ``x`` - a real number or a symbolic expression EXAMPLES:: sage: heaviside(-1/2) 0 sage: heaviside(1) 1 sage: heaviside(0) heaviside(0) sage: heaviside(x) heaviside(x) sage: heaviside(exp(-1000000000000000000000)) 1 Evaluation test:: sage: heaviside(x).subs(x=1) 1 sage: heaviside(x).subs(x=-1) 0 :: sage: ex = heaviside(x)+1 sage: t = loads(dumps(ex)); t heaviside(x) + 1 sage: bool(t == ex) True sage: t.subs(x=1) 2 """ try: approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return None # Now we have a non-zero real if bool((approx_x**(0.5)).imag() == 0): # Check: x > 0 return 1 else: return 0 except StandardError: # x is symbolic pass return None
def _evalf_(self, x, **kwds): """ TESTS:: sage: h(x) = dirac_delta(x) sage: h(pi).numerical_approx() 0.000000000000000 """ approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return None else: return 0 raise ValueError("Numeric evaluation of symbolic expression")
def _evalf_(self, x, **kwds): """ TESTS:: sage: h(x) = unit_step(x) sage: h(pi).numerical_approx() 1.00000000000000 """ approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return 1 # Now we have a non-zero real if bool((approx_x**(0.5)).imag() == 0): # Check: x > 0 return 1 else: return 0 raise ValueError("Numeric evaluation of symbolic expression")
def _evalf_(self, m, n, **kwds): """ TESTS:: sage: h(x) = kronecker_delta(3,x) sage: h(pi).numerical_approx() 0.000000000000000 """ if bool(repr(m) > repr(n)): return kronecker_delta(n, m) x = m - n approx_x = ComplexIntervalField()(x) if approx_x.imag() == 0: # x is real if approx_x.real() == 0: # x is zero return 1 else: return 0 return 0 # x is complex
def _eval_(self, m, n): """ The Kronecker delta function. EXAMPLES:: sage: kronecker_delta(1,2) 0 sage: kronecker_delta(1,1) 1 Kronecker delta is a symmetric function. We keep arguments sorted to ensure that k_d(m, n) - k_d(n, m) cancels automatically:: sage: x,y=var('x,y') sage: kronecker_delta(x, y) kronecker_delta(x, y) sage: kronecker_delta(y, x) kronecker_delta(x, y) sage: kronecker_delta(x,2*x) kronecker_delta(2*x, x) Evaluation test:: sage: kronecker_delta(1,x).subs(x=1) 1 """ if bool(repr(m) > repr(n)): return kronecker_delta(n, m) x = m - n try: approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return 1 else: return 0 else: return 0 # x is complex except Exception: # x is symbolic pass return None
def _eval_(self, m, n): """ The Kronecker delta function. EXAMPLES:: sage: kronecker_delta(1,2) 0 sage: kronecker_delta(1,1) 1 Kronecker delta is a symmetric function. We keep arguments sorted to ensure that (k_d(m, n) - k_d(n, m) cancels automatically:: sage: x,y=var('x,y') sage: kronecker_delta(x, y) kronecker_delta(x, y) sage: kronecker_delta(y, x) kronecker_delta(x, y) sage: kronecker_delta(x,2*x) kronecker_delta(2*x, x) Evaluation test:: sage: kronecker_delta(1,x).subs(x=1) 1 """ if bool(repr(m) > repr(n)): return kronecker_delta(n, m) x = m - n try: approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return 1 else: return 0 else: return 0 # x is complex except StandardError: # x is symbolic pass return None
def _evalf_(self, m, n, **kwds): """ TESTS:: sage: h(x) = kronecker_delta(3,x) sage: h(pi).numerical_approx() 0.000000000000000 """ if bool(repr(m) > repr(n)): return kronecker_delta(n, m) x = m - n approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return 1 else: return 0 else: return 0 # x is complex raise ValueError("Numeric evaluation of symbolic expression")
def _eval_(self, x): """ INPUT: - ``x`` - a real number or a symbolic expression EXAMPLES:: sage: unit_step(-1) 0 sage: unit_step(1) 1 sage: unit_step(0) 1 sage: unit_step(x) unit_step(x) sage: unit_step(-exp(-10000000000000000000)) 0 Evaluation test:: sage: unit_step(x).subs(x=1) 1 sage: unit_step(x).subs(x=0) 1 """ try: approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return 1 # Now we have a non-zero real if bool((approx_x**(0.5)).imag() == 0): # Check: x > 0 return 1 else: return 0 except Exception: # x is symbolic pass return None
def _eval_(self, x): """ INPUT: - ``x`` - a real number or a symbolic expression EXAMPLES:: sage: unit_step(-1) 0 sage: unit_step(1) 1 sage: unit_step(0) 1 sage: unit_step(x) unit_step(x) sage: unit_step(-exp(-10000000000000000000)) 0 Evaluation test:: sage: unit_step(x).subs(x=1) 1 sage: unit_step(x).subs(x=0) 1 """ try: approx_x = ComplexIntervalField()(x) if bool(approx_x.imag() == 0): # x is real if bool(approx_x.real() == 0): # x is zero return 1 # Now we have a non-zero real if bool((approx_x**(0.5)).imag() == 0): # Check: x > 0 return 1 else: return 0 except StandardError: # x is symbolic pass return None
def dimension__vector_valued(k, L, conjugate=False): r""" Compute the dimension of the space of weight `k` vector valued modular forms for the Weil representation (or its conjugate) attached to the lattice `L`. See [Borcherds, Borcherds - Reflection groups of Lorentzian lattices] for a proof of the formula that we use here. INPUT: - `k` -- A half-integer. - ``L`` -- An quadratic form. - ``conjugate`` -- A boolean; If ``True``, then compute the dimension for the conjugated Weil representation. OUTPUT: An integer. TESTS:: sage: dimension__vector_valued(3, QuadraticForm(-matrix(2, [2, 1, 1, 2]))) 1 sage: dimension__vector_valued(3, QuadraticForm(-matrix(2, [2, 0, 0, 2]))) 1 sage: dimension__vector_valued(3, QuadraticForm(-matrix(2, [2, 0, 0, 4]))) 1 """ if 2 * k not in ZZ: raise ValueError("Weight must be half-integral") if k <= 0: return 0 if k < 2: raise NotImplementedError("Weight <2 is not implemented.") if L.matrix().rank() != L.matrix().nrows(): raise ValueError( "The lattice (={0}) must be non-degenerate.".format(L)) L_dimension = L.matrix().nrows() if L_dimension % 2 != ZZ(2 * k) % 2: return 0 plus_basis = ZZ(L_dimension + 2 * k) % 4 == 0 ## The bilinear and the quadratic form attached to L quadratic = lambda x: L(x) // 2 bilinear = lambda x, y: L(x + y) - L(x) - L(y) ## A dual basis for L (elementary_divisors, dual_basis_pre, _) = L.matrix().smith_form() elementary_divisors = elementary_divisors.diagonal() dual_basis = map(operator.div, list(dual_basis_pre), elementary_divisors) L_level = ZZ(lcm([b.denominator() for b in dual_basis])) (elementary_divisors, _, discriminant_basis_pre) = ( L_level * matrix(dual_basis)).change_ring(ZZ).smith_form() elementary_divisors = filter(lambda d: d not in ZZ, (elementary_divisors / L_level).diagonal()) elementary_divisors_inv = map(ZZ, [ed**-1 for ed in elementary_divisors]) discriminant_basis = matrix( map(operator.mul, discriminant_basis_pre.inverse().rows()[:len(elementary_divisors)], elementary_divisors)).transpose() ## This is a form over QQ, so that we cannot use an instance of QuadraticForm discriminant_form = discriminant_basis.transpose() * L.matrix( ) * discriminant_basis if conjugate: discriminant_form = -discriminant_form if prod(elementary_divisors_inv) > 100: disc_den = discriminant_form.denominator() disc_bilinear_pre = \ cython_lambda( ', '.join( ['int a{0}'.format(i) for i in range(discriminant_form.nrows())] + ['int b{0}'.format(i) for i in range(discriminant_form.nrows())] ), ' + '.join('{0} * a{1} * b{2}'.format(disc_den * discriminant_form[i,j], i, j) for i in range(discriminant_form.nrows()) for j in range(discriminant_form.nrows())) ) disc_bilinear = lambda *a: disc_bilinear_pre(*a) / disc_den else: disc_bilinear = lambda *xy: vector(ZZ, xy[:discriminant_form.nrows( )]) * discriminant_form * vector(ZZ, xy[discriminant_form.nrows():]) disc_quadratic = lambda *a: disc_bilinear(*(2 * a)) / 2 ## red gives a normal form for elements in the discriminant group red = lambda x: map(operator.mod, x, elementary_divisors_inv) def is_singl(x): y = red(map(operator.neg, x)) for (e, f) in zip(x, y): if e < f: return -1 elif e > f: return 1 return 0 ## singls and pairs are elements of the discriminant group that are, respectively, ## fixed and not fixed by negation. singls = list() pairs = list() for x in mrange(elementary_divisors_inv): si = is_singl(x) if si == 0: singls.append(x) elif si == 1: pairs.append(x) if plus_basis: subspace_dimension = len(singls + pairs) else: subspace_dimension = len(pairs) ## 200 bits are, by far, sufficient to distinguish 12-th roots of unity ## by increasing the precision by 4 for each additional dimension, we ## compensate, by far, the errors introduced by the QR decomposition, ## which are of the size of (absolute error) * dimension CC = ComplexIntervalField(200 + subspace_dimension * 4) zeta_order = ZZ( lcm([8, 12] + map(lambda ed: 2 * ed, elementary_divisors_inv))) zeta = CC(exp(2 * pi * I / zeta_order)) sqrt2 = CC(sqrt(2)) drt = CC(sqrt(L.det())) Tmat = diagonal_matrix(CC, [ zeta**(zeta_order * disc_quadratic(*a)) for a in (singls + pairs if plus_basis else pairs) ]) if plus_basis: Smat = zeta**(zeta_order / 8 * L_dimension) / drt \ * matrix( CC, [ [zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) for delta in singls] + [sqrt2 * zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) for delta in pairs] for gamma in singls] \ + [ [sqrt2 * zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) for delta in singls] + [zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) + zeta**(-zeta_order * disc_bilinear(*(gamma + map(operator.neg, delta)))) for delta in pairs] for gamma in pairs] ) else: Smat = zeta**(zeta_order / 8 * L_dimension) / drt \ * matrix( CC, [ [zeta**(-zeta_order * disc_bilinear(*(gamma + delta))) - zeta**(-zeta_order * disc_bilinear(*(gamma + map(operator.neg,delta)))) for delta in pairs] for gamma in pairs ] ) STmat = Smat * Tmat ## This function overestimates the number of eigenvalues, if it is not correct def eigenvalue_multiplicity(mat, ev): mat = matrix(CC, mat - ev * identity_matrix(subspace_dimension)) return len( filter(lambda row: all(e.contains_zero() for e in row), _qr(mat).rows())) rti = CC(exp(2 * pi * I / 8)) S_ev_multiplicity = [ eigenvalue_multiplicity(Smat, rti**n) for n in range(8) ] ## Together with the fact that eigenvalue_multiplicity overestimates the multiplicities ## this asserts that the computed multiplicities are correct assert sum(S_ev_multiplicity) == subspace_dimension rho = CC(exp(2 * pi * I / 12)) ST_ev_multiplicity = [ eigenvalue_multiplicity(STmat, rho**n) for n in range(12) ] ## Together with the fact that eigenvalue_multiplicity overestimates the multiplicities ## this asserts that the computed multiplicities are correct assert sum(ST_ev_multiplicity) == subspace_dimension T_evs = [ ZZ((zeta_order * disc_quadratic(*a)) % zeta_order) / zeta_order for a in (singls + pairs if plus_basis else pairs) ] return subspace_dimension * (1 + QQ(k) / 12) \ - ZZ(sum( (ST_ev_multiplicity[n] * ((-2 * k - n) % 12)) for n in range(12) )) / 12 \ - ZZ(sum( (S_ev_multiplicity[n] * ((2 * k + n) % 8)) for n in range(8) )) / 8 \ - sum(T_evs)