def __init__(self, sides, i_angle, center, options): """ Initialize HyperbolicRegularPolygon. EXAMPLES:: sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon sage: print(HyperbolicRegularPolygon(5,pi/2,I, {})) Hyperbolic regular polygon (sides=5, i_angle=1/2*pi, center=1.00000000000000*I) """ self.center = CC(center) if self.center.imag() <= 0 : raise ValueError("center: %s is not a valid point in the upper half plane model of the hyperbolic plane"%(self.center)) if sides < 3 : raise ValueError("degenerated polygons (sides<=2) are not supported") if i_angle <=0 or i_angle >= pi: raise ValueError("interior angle %s must be in (0, pi) interval"%(i_angle)) if pi*(sides-2) - sides*i_angle <= 0 : raise ValueError("there exists no hyperbolic regular compact polygon, for sides=%s the interior angle must be less than %s"%(sides, pi * (sides-2) / sides)) self.sides = sides self.i_angle = i_angle beta = 2 * pi / self.sides # compute the rotation angle to be used ahead alpha = self.i_angle / Integer(2) I = CC(0, 1) # compute using cosine theorem the radius of the circumscribed circle # using the triangle formed by the radius and the three known angles r = arccosh(cot(alpha) * (1 + cos(beta)) / sin(beta)) # The first point will be always on the imaginary axis limited # to 8 digits for efficiency in the subsequent calculations. z_0 = [I*(e**r).n(digits=8)] # Compute the dilation isometry used to move the center # from I to the imaginary part of the given center. scale = self.center.imag() # Compute the parabolic isometry to move the center to the # real part of the given center. h_disp = self.center.real() d_z_k = [z_0[0]*scale + h_disp] #d_k has the points for the polygon in the given center z_k = z_0 #z_k has the Re(z)>0 vertices for the I centered polygon r_z_k = [] #r_z_k has the Re(z)<0 vertices if is_odd(self.sides): vert = (self.sides - 1) / 2 else: vert = self.sides / 2 - 1 for k in range(0, vert): # Compute with 8 digits to accelerate calculations new_z_k = self._i_rotation(z_k[-1], beta).n(digits=8) z_k = z_k + [new_z_k] d_z_k = d_z_k + [new_z_k * scale + h_disp] r_z_k=[-(new_z_k).conjugate() * scale + h_disp] + r_z_k if is_odd(self.sides): HyperbolicPolygon.__init__(self, d_z_k + r_z_k, options) else: z_opo = [I * (e**(-r)).n(digits=8) * scale + h_disp] HyperbolicPolygon.__init__(self, d_z_k + z_opo + r_z_k, options)
def disc(self): r""" Return the discriminant of the quadratic form, defined as - `(-1)^n {\rm det}(B)` for even dimension `2n` - `{\rm det}(B)/2` for odd dimension where `2Q(x) = x^t B x`. This agrees with the usual discriminant for binary and ternary quadratic forms. EXAMPLES:: sage: DiagonalQuadraticForm(ZZ, [1]).disc() 1 sage: DiagonalQuadraticForm(ZZ, [1,1]).disc() -4 sage: DiagonalQuadraticForm(ZZ, [1,1,1]).disc() 4 sage: DiagonalQuadraticForm(ZZ, [1,1,1,1]).disc() 16 """ if is_odd(self.dim()): return self.base_ring()(self.det() / 2) ## This is not so good for characteristic 2. else: return (-1)**(self.dim()//2) * self.det()
def disc(self): r""" Returns the discriminant of the quadratic form, defined as - `(-1)^n {\rm det}(B)` for even dimension `2n` - `{\rm det}(B)/2` for odd dimension where `2Q(x) = x^t B x`. This agrees with the usual discriminant for binary and ternary quadratic forms. EXAMPLES:: sage: DiagonalQuadraticForm(ZZ, [1]).disc() 1 sage: DiagonalQuadraticForm(ZZ, [1,1]).disc() -4 sage: DiagonalQuadraticForm(ZZ, [1,1,1]).disc() 4 sage: DiagonalQuadraticForm(ZZ, [1,1,1,1]).disc() 16 """ if is_odd(self.dim()): return self.base_ring()(self.det() / 2) ## This is not so good for characteristic 2. else: return (-1) ** (self.dim() // 2) * self.det()
def antiadjoint(self): """ This gives an (integral) form such that its adjoint is the given form. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.adjoint().antiadjoint() Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 0 -1 ] [ * 2 -1 ] [ * * 5 ] sage: Q.antiadjoint() Traceback (most recent call last): ... ValueError: not an adjoint """ try: n = self.dim() R = self.base_ring() d = R(self.disc()**(ZZ(1)/(n-1))) if is_odd(n): return self.adjoint().scale_by_factor( R(1) / 4 / d**(n-2) ) else: return self.adjoint().scale_by_factor( R(1) / d**(n-2) ) except TypeError: raise ValueError("not an adjoint")
def ev( self): """ Return a pair $alpha, L_{ev}$, where $L_{ev}$ is isomorphic to the kernel of $L\rightarrow \{\pm 1\}$, $x\mapsto e(\beta(x))$, and where $alpha$ is an embedding of $L_{ev}$ into $L$ whose image is this kernel. REMARK We have to find the kernel of the map $x\mapsto G[x] \equiv \sum_{j\in S}x_2 \bmod 2$. Here $S$ is the set of indices $i$ such that the $i$-diagonal element of $G$ is odd. A basis is given by $e_i$ ($i not\in S$) and $e_i + e_j$ ($i \in S$, $i\not=j$) and $2e_j$, where $j$ is any fixed index in $S$. """ if self.is_even(): return self.hom( self.basis(), self.module()), self D = self.gram_matrix().diagonal() S = [ i for i in range( len(D)) if is_odd(D[i])] j = min(S) e = self.basis() n = len(e) form = lambda i: e[i] if i not in S else 2*e[j] if i == j else e[i]+e[j] a = [ form(i) for i in range( n)] # A = matrix( a).transpose() # return A, Lattice_class( [ self.beta( a[i],a[j]) for i in range(n) for j in range(i,n)]) Lev = Lattice_class( [ self.beta( a[i],a[j]) for i in range(n) for j in range(i,n)]) alpha = Lev.hom( a, self.module()) return alpha, Lev
def adjoint(self): """ This gives the adjoint (integral) quadratic form associated to the given form, essentially defined by taking the adjoint of the matrix. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,2,5]) sage: Q.adjoint() Quadratic form in 2 variables over Integer Ring with coefficients: [ 5 -2 ] [ * 1 ] :: sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.adjoint() Quadratic form in 3 variables over Integer Ring with coefficients: [ 39 2 8 ] [ * 19 4 ] [ * * 8 ] """ if is_odd(self.dim()): return QuadraticForm(self.matrix().adjoint() * 2) else: return QuadraticForm(self.matrix().adjoint())
def adjoint(self): """ This gives the adjoint (integral) quadratic form associated to the given form, essentially defined by taking the adjoint of the matrix. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 2, [1,2,5]) sage: Q.adjoint() Quadratic form in 2 variables over Integer Ring with coefficients: [ 5 -2 ] [ * 1 ] :: sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.adjoint() Quadratic form in 3 variables over Integer Ring with coefficients: [ 39 2 8 ] [ * 19 4 ] [ * * 8 ] """ if is_odd(self.dim()): return QuadraticForm(self.matrix().adjoint()*2) else: return QuadraticForm(self.matrix().adjoint())
def antiadjoint(self): """ This gives an (integral) form such that its adjoint is the given form. EXAMPLES:: sage: Q = QuadraticForm(ZZ, 3, [1, 0, -1, 2, -1, 5]) sage: Q.adjoint().antiadjoint() Quadratic form in 3 variables over Integer Ring with coefficients: [ 1 0 -1 ] [ * 2 -1 ] [ * * 5 ] sage: Q.antiadjoint() Traceback (most recent call last): ... ValueError: not an adjoint """ try: n = self.dim() R = self.base_ring() d = R(self.disc() ** (ZZ(1) / (n - 1))) if is_odd(n): return self.adjoint().scale_by_factor(R(1) / 4 / d ** (n - 2)) else: return self.adjoint().scale_by_factor(R(1) / d ** (n - 2)) except TypeError: raise ValueError("not an adjoint")
def apply_simple_reflection_right(self, i): r""" Implements :meth:`CoxeterGroups.ElementMethods.apply_simple_reflection`. EXEMPLES:: sage: D5 = FiniteCoxeterGroups().example(5) sage: [i^2 for i in D5] [(), (), (1, 2, 1, 2), (), (2, 1), (), (), (2, 1, 2, 1), (), (1, 2)] sage: [i^5 for i in D5] [(), (1,), (), (1, 2, 1), (), (1, 2, 1, 2, 1), (2,), (), (2, 1, 2), ()] """ from copy import copy reduced_word = copy(self.value) n = self.parent().n if len(reduced_word) == n: if (i == 1 and is_odd(n)) or (i == 2 and is_even(n)): return self.parent()(reduced_word[:-1]) else: return self.parent()(reduced_word[1:]) elif (len(reduced_word) == n-1 and (not self.has_descent(i))) and (reduced_word[0] == 2): return self.parent()((1,)+reduced_word) else: if self.has_descent(i): return self.parent()(reduced_word[:-1]) else: return self.parent()(reduced_word+(i,))
def apply_simple_reflection_right(self, i): r""" Implements :meth:`CoxeterGroups.ElementMethods.apply_simple_reflection`. EXAMPLES:: sage: D5 = FiniteCoxeterGroups().example(5) sage: [i^2 for i in D5] # indirect doctest [(), (), (), (1, 2, 1, 2), (2, 1, 2, 1), (), (), (2, 1), (1, 2), ()] sage: [i^5 for i in D5] # indirect doctest [(), (1,), (2,), (), (), (1, 2, 1), (2, 1, 2), (), (), (1, 2, 1, 2, 1)] """ from copy import copy reduced_word = copy(self.value) n = self.parent().n if len(reduced_word) == n: if (i == 1 and is_odd(n)) or (i == 2 and is_even(n)): return self.parent()(reduced_word[:-1]) else: return self.parent()(reduced_word[1:]) elif (len(reduced_word) == n - 1 and (not self.has_descent(i))) and (reduced_word[0] == 2): return self.parent()((1, ) + reduced_word) else: if self.has_descent(i): return self.parent()(reduced_word[:-1]) else: return self.parent()(reduced_word + (i, ))
def dimension_table_Sp4Z_j(wt_range, j_range): result = {} for wt in wt_range: result[wt] = {} for j in j_range: if is_odd(j): for wt in wt_range: result[wt][j] = 0 else: _, olddim = dimension_Sp4Z_j(wt_range, j) for wt in wt_range: result[wt][j] = olddim[wt]['Total'] return result
def dimension_table_Sp4Z_j(wt_range, j_range): result = {} for wt in wt_range: result[wt] = {} for j in j_range: if is_odd(j): for wt in wt_range: result[wt][j] = 0 else: _, olddim = dimension_Sp4Z_j(wt_range, j) for wt in wt_range: result[wt][j] = olddim[wt]["Total"] return result
def _fntt_textbook(a, w, n = 0, axis = 0): n = len(a) if n == 1: return a if is_odd(n): return _ntt(a, w) else: Feven = _fntt_textbook([a[i] for i in xrange(0, n, 2)], w**2) Fodd = _fntt_textbook([a[i] for i in xrange(1, n, 2)], w**2) combined = [0] * n for m in xrange(n/2): combined[m] = Feven[m] + w**m * Fodd[m] combined[m + n/2] = Feven[m] + w**(n/2+m) * Fodd[m] return combined
def dimension_Gamma0_4_psi_4( wt_range): """ <ul> <li><span class="emph">Total</span>: The full spaces.</li> </ul> <p> Odd weights are not yet implemented.</p> """ headers = ['Total'] dct = dict() s = t = 0 # Here starts a 'hack' for k in wt_range: if is_odd(k): continue dims = _dimension_Gamma0_4_psi_4( k) dct[k] = dict( (headers[j],dims[j]) for j in range( len(headers))) return headers, dct
def dimension_Gamma0_4_psi_4(wt_range): """ <ul> <li><span class="emph">Total</span>: The full spaces.</li> </ul> <p> Odd weights are not yet implemented.</p> """ headers = ['Total'] dct = dict() s = t = 0 # Here starts a 'hack' for k in wt_range: if is_odd(k): continue dims = _dimension_Gamma0_4_psi_4(k) dct[k] = dict((headers[j], dims[j]) for j in range(len(headers))) return headers, dct
def trace_new_cusp_forms( k, m, l, n): r""" OUTPUT Rhe trace of $T(l) \circ W_n$ on $S_k^{\text{new}}(Gamma_0(m)$). INPUT l -- Hecke operator index (rel. prime to the level $m$) n -- Atkin-Lehner involution index (exact divisor of the level $m$) k -- weight m -- a level ($\ge 1$) """ k, m, l, n = __check( k, m, l, n) if is_odd(k) or k <= 0: return 0 return sum( _alpha( m//mp) * _sz_s( k//2+1, mp, l, n.gcd(mp)) \ for mp in m.divisors())
def _valid_index(self, w): r""" Return whether ``w`` is a valid index; no multiple powers in odd degrees. TESTS:: sage: A.<x,y,z> = GradedCommutativeAlgebra(QQ, degrees=(1,2,3), max_degree=8) sage: w1 = A._weighted_vectors([1,2,1]) sage: w2 = A._weighted_vectors([1,2,2]) sage: A._valid_index(w1) True sage: A._valid_index(w2) False """ return not any(i > 1 for i, d in zip(w, self._degrees) if is_odd(d))
def trace_special_cusp_forms( k, m, l, n): r""" OUTPUT The function $s_{k,m}(l,n)$, i.e.~the trace of $T(l) \circ W_n$ on the "certain" space $\mathcal{M}_{2k-2}^{\text{cusp}}(m)$ of modular forms as defined in [S-Z]. INPUT l -- index of the Hecke operator, rel. prime to the level $m$ n -- index of the Atkin-Lehner involution (exact divisor of $m$) k -- integer ($2k-2$ is the weight) m -- level """ k, m, l, n = __check( k, m, l, n) if is_odd(k) or k <= 0: return 0 return _sz_s( k//2+1, m, l, n)
def is_even( self): I = self.gram_matrix().diagonal() for a in I: if is_odd(a): return False return True
def _dimension_Gamma_2(wt_range, j, group="Gamma(2)"): """ Return the dict {(k-> partition -> [ d(k), e(k), c(k)] for k in wt_range]}, where d(k), e(k), c(k) are the dimensions of the $p$-canonical part of $M_{k,j}( \Gamma(2))$ and its subspaces of Non-cusp forms and Cusp forms. """ partitions = [u"6", u"51", u"42", u"411", u"33", u"321", u"311", u"222", u"2211", u"21111", u"111111"] if is_odd(j): dct = dict((k, dict((h, [0, 0, 0]) for h in partitions)) for k in wt_range) for k in dct: dct[k]["All"] = [0, 0, 0] partitions.insert(0, "All") return partitions, dct if "Sp4(Z)" == group and 2 == j and wt_range[0] < 4: wt_range1 = [k for k in wt_range if k < 4] wt_range2 = [k for k in wt_range if k >= 4] # print wt_range1, wt_range2 if wt_range2 != []: headers, dct = _dimension_Gamma_2(wt_range2, j, group) else: headers, dct = ["Total", "Non cusp", "Cusp"], {} for k in wt_range1: dct[k] = dict([(h, 0) for h in headers]) return headers, dct if j >= 2 and wt_range[0] < 4: raise NotImplementedError("Dimensions of \(M_{k,j}\) for \(k<4\) and even \(j\ge 2\) not implemented") query = {"sym_power": str(j), "group": "Gamma(2)", "space": "total"} db_total = fetch(query) assert db_total, "%s: Data not available" % query query["space"] = "cusp" db_cusp = fetch(query) assert db_cusp, "%s: Data not available" % query P = PowerSeriesRing(IntegerRing(), default_prec=wt_range[-1] + 1, names=("t",)) t = P.gen() total = dict() cusp = dict() for p in partitions: total[p] = eval(db_total[p]) cusp[p] = eval(db_cusp[p]) # total = dict( ( p, eval(db_total[p])) for p in partitions) # cusp = dict( ( p, eval(db_cusp[p])) for p in partitions) if "Gamma(2)" == group: dct = dict( (k, dict((p, [total[p][k], total[p][k] - cusp[p][k], cusp[p][k]]) for p in partitions)) for k in wt_range ) for k in dct: dct[k]["All"] = [sum(dct[k][p][j] for p in dct[k]) for j in range(3)] partitions.insert(0, "All") headers = partitions elif "Gamma1(2)" == group: ps = {"3": ["6", "42", "222"], "21": ["51", "42", "321"], "111": ["411", "33"]} dct = dict( ( k, dict( ( p, [ sum(total[q][k] for q in ps[p]), sum(total[q][k] - cusp[q][k] for q in ps[p]), sum(cusp[q][k] for q in ps[p]), ], ) for p in ps ), ) for k in wt_range ) for k in dct: dct[k]["All"] = [sum(dct[k][p][j] for p in dct[k]) for j in range(3)] headers = ps.keys() headers.sort(reverse=True) headers.insert(0, "All") elif "Gamma0(2)" == group: headers = ["Total", "Non cusp", "Cusp"] ps = ["6", "42", "222"] dct = dict( ( k, { "Total": sum(total[p][k] for p in ps), "Non cusp": sum(total[p][k] - cusp[p][k] for p in ps), "Cusp": sum(cusp[p][k] for p in ps), }, ) for k in wt_range ) elif "Sp4(Z)" == group: headers = ["Total", "Non cusp", "Cusp"] p = "6" dct = dict( (k, {"Total": total[p][k], "Non cusp": total[p][k] - cusp[p][k], "Cusp": cusp[p][k]}) for k in wt_range ) else: raise NotImplemetedError("Dimension for %s not implemented" % group) return headers, dct
def _dimension_Gamma_2(wt_range, j, group='Gamma(2)'): """ Return the dict {(k-> partition -> [ d(k), e(k), c(k)] for k in wt_range]}, where d(k), e(k), c(k) are the dimensions of the $p$-canonical part of $M_{k,j}( \Gamma(2))$ and its subspaces of Non-cusp forms and Cusp forms. """ partitions = [ u'6', u'51', u'42', u'411', u'33', u'321', u'311', u'222', u'2211', u'21111', u'111111' ] if is_odd(j): dct = dict( (k, dict((h, [0, 0, 0]) for h in partitions)) for k in wt_range) for k in dct: dct[k]['All'] = [0, 0, 0] partitions.insert(0, 'All') return partitions, dct if 'Sp4(Z)' == group and 2 == j and wt_range[0] < 4: wt_range1 = [k for k in wt_range if k < 4] wt_range2 = [k for k in wt_range if k >= 4] print wt_range1, wt_range2 if wt_range2 != []: headers, dct = _dimension_Gamma_2(wt_range2, j, group) else: headers, dct = ['Total', 'Non cusp', 'Cusp'], {} for k in wt_range1: dct[k] = dict([(h, 0) for h in headers]) return headers, dct if j >= 2 and wt_range[0] < 4: raise NotImplementedError( 'Dimensions of \(M_{k,j}\) for \(k<4\) and even \(j\ge 2\) not implemented' ) query = {'sym_power': str(j), 'group': 'Gamma(2)', 'space': 'total'} db_total = fetch(query) assert db_total, '%s: Data not available' % query query['space'] = 'cusp' db_cusp = fetch(query) assert db_cusp, '%s: Data not available' % query P = PowerSeriesRing(IntegerRing(), default_prec=wt_range[-1] + 1, names=('t', )) t = P.gen() total = dict() cusp = dict() for p in partitions: total[p] = eval(db_total[p]) cusp[p] = eval(db_cusp[p]) # total = dict( ( p, eval(db_total[p])) for p in partitions) # cusp = dict( ( p, eval(db_cusp[p])) for p in partitions) if 'Gamma(2)' == group: dct = dict( (k, dict((p, [total[p][k], total[p][k] - cusp[p][k], cusp[p][k]]) for p in partitions)) for k in wt_range) for k in dct: dct[k]['All'] = [ sum(dct[k][p][j] for p in dct[k]) for j in range(3) ] partitions.insert(0, 'All') headers = partitions elif 'Gamma1(2)' == group: ps = { '3': ['6', '42', '222'], '21': ['51', '42', '321'], '111': ['411', '33'] } dct = dict((k, dict((p, [ sum(total[q][k] for q in ps[p]), sum(total[q][k] - cusp[q][k] for q in ps[p]), sum(cusp[q][k] for q in ps[p]), ]) for p in ps)) for k in wt_range) for k in dct: dct[k]['All'] = [ sum(dct[k][p][j] for p in dct[k]) for j in range(3) ] headers = ps.keys() headers.sort(reverse=True) headers.insert(0, 'All') elif 'Gamma0(2)' == group: headers = ['Total', 'Non cusp', 'Cusp'] ps = ['6', '42', '222'] dct = dict((k, { 'Total': sum(total[p][k] for p in ps), 'Non cusp': sum(total[p][k] - cusp[p][k] for p in ps), 'Cusp': sum(cusp[p][k] for p in ps) }) for k in wt_range) elif 'Sp4(Z)' == group: headers = ['Total', 'Non cusp', 'Cusp'] p = '6' dct = dict((k, { 'Total': total[p][k], 'Non cusp': total[p][k] - cusp[p][k], 'Cusp': cusp[p][k] }) for k in wt_range) else: raise NotImplemetedError('Dimension for %s not implemented' % group) return headers, dct
def _dimension_Gamma_2( wt_range, j, group = 'Gamma(2)'): """ Return the dict {(k-> partition -> [ d(k), e(k), c(k)] for k in wt_range]}, where d(k), e(k), c(k) are the dimensions of the $p$-canonical part of $M_{k,j}( \Gamma(2))$ and its subspaces of Non-cusp forms and Cusp forms. """ partitions = [ u'6', u'51', u'42', u'411', u'33', u'321', u'311', u'222', u'2211', u'21111', u'111111'] if is_odd(j): dct = dict( (k,dict((h,[0,0,0]) for h in partitions)) for k in wt_range) for k in dct: dct[k]['All'] = [0,0,0] partitions.insert( 0,'All') return partitions, dct if j>=2 and wt_range[0] < 4: raise NotImplementedError( 'Dimensions of \(M_{k,j}\) for \(k<4\) and even \(j\ge 2\) not implemented') query = { 'sym_power': str(j), 'group' : 'Gamma(2)', 'space': 'total'} db_total = fetch( query) assert db_total, '%s: Data not available' % query query['space'] = 'cusp' db_cusp = fetch( query) assert db_cusp, '%s: Data not available' % query P = PowerSeriesRing( IntegerRing(), default_prec =wt_range[-1] + 1, names = ('t',)) t = P.gen() total = dict() cusp = dict() for p in partitions: total[p] = eval(db_total[p]) cusp[p] = eval(db_cusp[p]) # total = dict( ( p, eval(db_total[p])) for p in partitions) # cusp = dict( ( p, eval(db_cusp[p])) for p in partitions) if 'Gamma(2)' == group: dct = dict( (k, dict( (p, [total[p][k], total[p][k]-cusp[p][k], cusp[p][k]]) for p in partitions)) for k in wt_range) for k in dct: dct[k]['All'] = [sum( dct[k][p][j] for p in dct[k]) for j in range(3)] partitions.insert( 0,'All') headers = partitions elif 'Gamma1(2)' == group: ps = { '3': ['6', '42', '222'], '21': ['51', '42', '321'], '111': ['411', '33']} dct = dict( (k, dict( (p,[ sum( total[q][k] for q in ps[p]), sum( total[q][k]-cusp[q][k] for q in ps[p]), sum( cusp[q][k] for q in ps[p]), ]) for p in ps)) for k in wt_range) for k in dct: dct[k]['All'] = [sum( dct[k][p][j] for p in dct[k]) for j in range(3)] headers = ps.keys() headers.sort( reverse = True) headers.insert( 0,'All') elif 'Gamma0(2)' == group: headers = ['Total', 'Non cusp', 'Cusp'] ps = ['6', '42', '222'] dct = dict( (k, { 'Total': sum( total[p][k] for p in ps), 'Non cusp': sum( total[p][k]-cusp[p][k] for p in ps), 'Cusp': sum( cusp[p][k] for p in ps)}) for k in wt_range) elif 'Sp4(Z)' == group: headers = ['Total', 'Non cusp', 'Cusp'] p = '6' dct = dict( (k, { 'Total': total[p][k], 'Non cusp': total[p][k]-cusp[p][k], 'Cusp': cusp[p][k]}) for k in wt_range) else: raise NotImplemetedError( 'Dimension for %s not implemented' % group) return headers, dct
def is_odd( self): return is_odd( Integer(self.weight() - self.character()/2))