def cardinality(self): """ Returns the number of Lyndon words with the evaluation e. EXAMPLES:: sage: LyndonWords([]).cardinality() 0 sage: LyndonWords([2,2]).cardinality() 1 sage: LyndonWords([2,3,2]).cardinality() 30 Check to make sure that the count matches up with the number of Lyndon words generated. :: sage: comps = [[],[2,2],[3,2,7],[4,2]]+Compositions(4).list() sage: lws = [ LyndonWords(comp) for comp in comps] sage: all( [ lw.cardinality() == len(lw.list()) for lw in lws] ) True """ evaluation = self.e le = __builtin__.list(evaluation) if len(evaluation) == 0: return 0 n = sum(evaluation) return sum([moebius(j)*factorial(n/j) / prod([factorial(ni/j) for ni in evaluation]) for j in divisors(gcd(le))])/n
def cardinality(self): r""" Return the cardinality of ``self``. The number of ordered set partitions of a set of length `k` with composition shape `\mu` is equal to .. MATH:: \frac{k!}{\prod_{\mu_i \neq 0} \mu_i!}. EXAMPLES:: sage: OrderedSetPartitions(5,[2,3]).cardinality() 10 sage: OrderedSetPartitions(0, []).cardinality() 1 sage: OrderedSetPartitions(0, [0]).cardinality() 1 sage: OrderedSetPartitions(0, [0,0]).cardinality() 1 sage: OrderedSetPartitions(5, [2,0,3]).cardinality() 10 """ return factorial(len(self._set)) / prod([factorial(i) for i in self.c])
def cardinality(self): """ Returns the number of integer necklaces with the evaluation e. EXAMPLES:: sage: Necklaces([]).cardinality() 0 sage: Necklaces([2,2]).cardinality() 2 sage: Necklaces([2,3,2]).cardinality() 30 Check to make sure that the count matches up with the number of Lyndon words generated. :: sage: comps = [[],[2,2],[3,2,7],[4,2]]+Compositions(4).list() sage: ns = [ Necklaces(comp) for comp in comps] sage: all( [ n.cardinality() == len(n.list()) for n in ns] ) True """ evaluation = self.e le = list(evaluation) if len(le) == 0: return 0 n = sum(le) return sum([euler_phi(j)*factorial(n/j) / prod([factorial(ni/j) for ni in evaluation]) for j in divisors(gcd(le))])/n
def cardinality(self): """ Returns the number of Lyndon words with the evaluation e. EXAMPLES:: sage: LyndonWords([]).cardinality() 0 sage: LyndonWords([2,2]).cardinality() 1 sage: LyndonWords([2,3,2]).cardinality() 30 Check to make sure that the count matches up with the number of Lyndon words generated. :: sage: comps = [[],[2,2],[3,2,7],[4,2]]+Compositions(4).list() sage: lws = [ LyndonWords(comp) for comp in comps] sage: all( [ lw.cardinality() == len(lw.list()) for lw in lws] ) True """ evaluation = self.e le = __builtin__.list(evaluation) if len(evaluation) == 0: return 0 n = sum(evaluation) return sum([ moebius(j) * factorial(n / j) / prod([factorial(ni / j) for ni in evaluation]) for j in divisors(gcd(le)) ]) / n
def cardinality(self): r""" Return the cardinality of ``self``. The number of ordered set partitions of a set of length `k` with composition shape `\mu` is equal to .. MATH:: \frac{k!}{\prod_{\mu_i \neq 0} \mu_i!}. EXAMPLES:: sage: OrderedSetPartitions(5,[2,3]).cardinality() 10 sage: OrderedSetPartitions(0, []).cardinality() 1 sage: OrderedSetPartitions(0, [0]).cardinality() 1 sage: OrderedSetPartitions(0, [0,0]).cardinality() 1 sage: OrderedSetPartitions(5, [2,0,3]).cardinality() 10 """ return factorial(len(self._set))/prod([factorial(i) for i in self.c])
def zero_eigenvectors(self, tg, flags): if self._use_symmetry: return self.symm_zero_eigenvectors(tg, flags) cn = self._graph.n s = tg.n k = flags[0].n # assume all flags the same order rows = [] for tv in Tuples(range(1, cn + 1), s): it = self._graph.degenerate_induced_subgraph(tv) using_phantom_edge = False phantom_edge = None if hasattr(self, "_phantom_edge") and it.ne == tg.ne - 1: extra_edges = [e for e in tg if not e in it] if len(extra_edges) == 1: phantom_edge = extra_edges[0] if all(tv[phantom_edge[i] - 1] == self._phantom_edge[i] for i in range(tg.r)): it.add_edge(phantom_edge) using_phantom_edge = True if not (using_phantom_edge or it.is_labelled_isomorphic(tg)): continue total = Integer(0) row = [0] * len(flags) for ov in UnorderedTuples(range(1, cn + 1), k - s): factor = factorial(k - s) for i in range(1, cn + 1): factor /= factorial(ov.count(i)) if self._weights: for v in ov: factor *= self._weights[v - 1] ig = self._graph.degenerate_induced_subgraph(tv + ov) if using_phantom_edge: ig.add_edge(phantom_edge) ig.t = s ig.make_minimal_isomorph() for j in range(len(flags)): if ig.is_labelled_isomorphic(flags[j]): row[j] += factor total += factor break for j in range(len(flags)): row[j] /= total rows.append(row) return matrix_of_independent_rows(self._field, rows, len(flags))
def by_taylor_expansion(self, fs, k, is_integral=False): r""" We combine the theta decomposition and the heat operator as in [Sko]. This yields a bijections of Jacobi forms of weight `k` and `M_k \times S_{k+2} \times .. \times S_{k+2m}`. """ ## we introduce an abbreviations if is_integral: PS = self.integral_power_series_ring() else: PS = self.power_series_ring() if not len(fs) == self.__precision.jacobi_index() + 1: raise ValueError( "fs must be a list of m + 1 elliptic modular forms or their fourier expansion" ) qexp_prec = self._qexp_precision() if qexp_prec is None: # there are no forms below the precision return dict() f_divs = dict() for (i, f) in enumerate(fs): f_divs[(i, 0)] = PS(f(qexp_prec), qexp_prec) if self.__precision.jacobi_index() == 1: return self._by_taylor_expansion_m1(f_divs, k, is_integral) for i in xrange(self.__precision.jacobi_index() + 1): for j in xrange(1, self.__precision.jacobi_index() - i + 1): f_divs[(i, j)] = f_divs[(i, j - 1)].derivative().shift(1) phi_divs = list() for i in xrange(self.__precision.jacobi_index() + 1): ## This is the formula in Skoruppas thesis. He uses d/ d tau instead of d / dz which yields ## a factor 4 m phi_divs.append( sum(f_divs[(j, i - j)] * (4 * self.__precision.jacobi_index())**i * binomial(i, j) / 2**i #2**(self.__precision.jacobi_index() - i + 1) * prod(2 * (i - l) + 1 for l in xrange(1, i)) / factorial(i + k + j - 1) * factorial(2 * self.__precision.jacobi_index() + k - 1) for j in xrange(i + 1))) phi_coeffs = dict() for r in xrange(self.__precision.jacobi_index() + 1): series = sum(map(operator.mul, self._theta_factors()[r], phi_divs)) series = self._eta_factor() * series for n in xrange(qexp_prec): phi_coeffs[(n, r)] = series[n] return phi_coeffs
def cardinality(self): r""" Returns the number of subwords of w of length k. EXAMPLES:: sage: Subwords([1,2,3], 2).cardinality() 3 """ w = self.w k = self.k return factorial(len(w))/(factorial(k)*factorial(len(w)-k))
def volume_hamming(n,q,r): r""" Returns number of elements in a Hamming ball of radius r in `\GF{q}^n`. Agrees with Guava's SphereContent(n,r,GF(q)). EXAMPLES:: sage: volume_hamming(10,2,3) 176 """ ans=sum([factorial(n)/(factorial(i)*factorial(n-i))*(q-1)**i for i in range(r+1)]) return ans
def cardinality(self): r""" Returns the number of subwords of w of length k. EXAMPLES:: sage: Subwords([1,2,3], 2).cardinality() 3 """ w = self.w k = self.k return factorial(len(w)) / (factorial(k) * factorial(len(w) - k))
def by_taylor_expansion(self, fs, k, is_integral=False) : r""" We combine the theta decomposition and the heat operator as in [Sko]. This yields a bijections of Jacobi forms of weight `k` and `M_k \times S_{k+2} \times .. \times S_{k+2m}`. """ ## we introduce an abbreviations if is_integral : PS = self.integral_power_series_ring() else : PS = self.power_series_ring() if not len(fs) == self.__precision.jacobi_index() + 1 : raise ValueError("fs must be a list of m + 1 elliptic modular forms or their fourier expansion") qexp_prec = self._qexp_precision() if qexp_prec is None : # there are no forms below the precision return dict() f_divs = dict() for (i, f) in enumerate(fs) : f_divs[(i, 0)] = PS(f(qexp_prec), qexp_prec) if self.__precision.jacobi_index() == 1 : return self._by_taylor_expansion_m1(f_divs, k, is_integral) for i in xrange(self.__precision.jacobi_index() + 1) : for j in xrange(1, self.__precision.jacobi_index() - i + 1) : f_divs[(i,j)] = f_divs[(i, j - 1)].derivative().shift(1) phi_divs = list() for i in xrange(self.__precision.jacobi_index() + 1) : ## This is the formula in Skoruppas thesis. He uses d/ d tau instead of d / dz which yields ## a factor 4 m phi_divs.append( sum( f_divs[(j, i - j)] * (4 * self.__precision.jacobi_index())**i * binomial(i,j) / 2**i#2**(self.__precision.jacobi_index() - i + 1) * prod(2*(i - l) + 1 for l in xrange(1, i)) / factorial(i + k + j - 1) * factorial(2*self.__precision.jacobi_index() + k - 1) for j in xrange(i + 1) ) ) phi_coeffs = dict() for r in xrange(self.__precision.jacobi_index() + 1) : series = sum( map(operator.mul, self._theta_factors()[r], phi_divs) ) series = self._eta_factor() * series for n in xrange(qexp_prec) : phi_coeffs[(n, r)] = series[n] return phi_coeffs
def cardinality(self): """ Returns the number of permutations of k things from a list of n things. EXAMPLES:: sage: from sage.combinat.permutation_nk import PermutationsNK sage: PermutationsNK(3,2).cardinality() 6 sage: PermutationsNK(5,4).cardinality() 120 """ n, k = self._n, self._k return factorial(n) / factorial(n - k)
def cardinality(self): """ Returns the number of permutations of k things from a list of n things. EXAMPLES:: sage: from sage.combinat.permutation_nk import PermutationsNK sage: PermutationsNK(3,2).cardinality() 6 sage: PermutationsNK(5,4).cardinality() 120 """ n, k = self._n, self._k return factorial(n)/factorial(n-k)
def subgraph_densities(self, n): if n < 0: raise ValueError if self._use_symmetry: return self.symm_subgraph_densities(n) cn = self._graph.n total = Integer(0) sharp_graph_counts = {} sharp_graphs = [] for P in UnorderedTuples(range(1, cn + 1), n): factor = factorial(n) for i in range(1, cn + 1): factor /= factorial(P.count(i)) if self._weights: for v in P: factor *= self._weights[v - 1] ig = self._graph.degenerate_induced_subgraph(P) igc = copy(ig) # copy for phantom edge ig.make_minimal_isomorph() ghash = hash(ig) if ghash in sharp_graph_counts: sharp_graph_counts[ghash] += factor else: sharp_graphs.append(ig) sharp_graph_counts[ghash] = factor total += factor if hasattr(self, "_phantom_edge") and all( x in P for x in self._phantom_edge): phantom_edge = [P.index(x) + 1 for x in self._phantom_edge] igc.add_edge(phantom_edge) igc.make_minimal_isomorph() ghash = hash(igc) if not ghash in sharp_graph_counts: sharp_graphs.append(igc) sharp_graph_counts[ghash] = Integer(0) return [(g, sharp_graph_counts[hash(g)] / total) for g in sharp_graphs]
def _test__jacobi_corrected_taylor_expansions(nu, phi, weight): r""" Return the ``2 nu``-th corrected Taylor coefficient. INPUT: - ``nu`` -- An integer. - ``phi`` -- A Fourier expansion of a Jacobi form. - ``weight`` -- An integer. OUTPUT: - A power series in `q`. ..TODO: Implement this for all Taylor coefficients. TESTS:: sage: from psage.modform.jacobiforms.jacobiformd1nn_fegenerators import * sage: from psage.modform.jacobiforms.jacobiformd1nn_types import * sage: nu_bound = 10 sage: precision = 100 sage: weight = 10; index = 7 sage: phis = [jacobi_form_by_taylor_expansion(i, JacobiFormD1NNFilter(precision, index), weight) for i in range(JacobiFormD1NN_Gamma(weight, index)._rank(QQ))] sage: fss = [ [JacobiFormD1NNFactory_class._test__jacobi_corrected_taylor_expansions(nu, phi, weight) for phi in phis] for nu in range(nu_bound) ] sage: fss_vec = [ [vector(f.padded_list(precision)) for f in fs] for fs in fss ] sage: mf_spans = [ span([vector(b.qexp(precision).padded_list(precision)) for b in ModularForms(1, weight + 2 * nu).basis()]) for nu in range(nu_bound) ] sage: all(f_vec in mf_span for (fs_vec, mf_span) in zip(fss_vec, mf_spans) for f_vec in fs_vec) True """ ## We use EZ85, p.29 (3), the factorial in one of the factors is missing factors = [(-1)**mu * factorial(2 * nu) * factorial(weight + 2 * nu - mu - 2) / ZZ( factorial(mu) * factorial(2 * nu - 2 * mu) * factorial(weight + nu - 2)) for mu in range(nu + 1)] gegenbauer = lambda n, r: sum(f * r**(2 * nu - 2 * mu) * n**mu for (mu, f) in enumerate(factors)) ch = JacobiFormD1WeightCharacter(weight) jacobi_index = phi.precision().jacobi_index() coeffs = dict((n, QQ(0)) for n in range(phi.precision().index())) for (n, r) in phi.precision().monoid_filter(): coeffs[n] += gegenbauer(jacobi_index * n, r) * phi[(ch, (n, r))] return PowerSeriesRing(QQ, 'q')(coeffs)
def cardinality(self): """ EXAMPLES:: sage: OrderedSetPartitions(5,[2,3]).cardinality() 10 sage: OrderedSetPartitions(0, []).cardinality() 1 sage: OrderedSetPartitions(0, [0]).cardinality() 1 sage: OrderedSetPartitions(0, [0,0]).cardinality() 1 sage: OrderedSetPartitions(5, [2,0,3]).cardinality() 10 """ return factorial(len(self.s))/prod([factorial(i) for i in self.c])
def subgraph_densities(self, n): if n < 0: raise ValueError if self._use_symmetry: return self.symm_subgraph_densities(n) cn = self._graph.n total = Integer(0) sharp_graph_counts = {} sharp_graphs = [] for P in UnorderedTuples(range(1, cn + 1), n): factor = factorial(n) for i in range(1, cn + 1): factor /= factorial(P.count(i)) if self._weights: for v in P: factor *= self._weights[v - 1] ig = self._graph.degenerate_induced_subgraph(P) igc = copy(ig) # copy for phantom edge ig.make_minimal_isomorph() ghash = hash(ig) if ghash in sharp_graph_counts: sharp_graph_counts[ghash] += factor else: sharp_graphs.append(ig) sharp_graph_counts[ghash] = factor total += factor if hasattr(self, "_phantom_edge") and all(x in P for x in self._phantom_edge): phantom_edge = [P.index(x) + 1 for x in self._phantom_edge] igc.add_edge(phantom_edge) igc.make_minimal_isomorph() ghash = hash(igc) if not ghash in sharp_graph_counts: sharp_graphs.append(igc) sharp_graph_counts[ghash] = Integer(0) return [(g, sharp_graph_counts[hash(g)] / total) for g in sharp_graphs]
def cardinality(self): r""" Return the number of integer necklaces with the evaluation ``content``. The formula for the number of necklaces of content `\alpha` a composition of `n` is: .. MATH:: \sum_{d|gcd(\alpha)} \phi(d) \binom{n/d}{\alpha_1/d, \ldots, \alpha_\ell/d}, where `\phi(d)` is the Euler `\phi` function. EXAMPLES:: sage: Necklaces([]).cardinality() 0 sage: Necklaces([2,2]).cardinality() 2 sage: Necklaces([2,3,2]).cardinality() 30 sage: Necklaces([0,3,2]).cardinality() 2 Check to make sure that the count matches up with the number of necklace words generated. :: sage: comps = [[],[2,2],[3,2,7],[4,2],[0,4,2],[2,0,4]]+Compositions(4).list() sage: ns = [ Necklaces(comp) for comp in comps] sage: all( [ n.cardinality() == len(n.list()) for n in ns] ) True """ evaluation = self._content le = list(evaluation) if not le: return 0 n = sum(le) return sum( euler_phi(j) * factorial(n / j) / prod(factorial(ni / j) for ni in evaluation) for j in divisors(gcd(le))) / n
def _test__jacobi_corrected_taylor_expansions(nu, phi, weight) : r""" Return the ``2 nu``-th corrected Taylor coefficient. INPUT: - ``nu`` -- An integer. - ``phi`` -- A Fourier expansion of a Jacobi form. - ``weight`` -- An integer. OUTPUT: - A power series in `q`. ..TODO: Implement this for all Taylor coefficients. TESTS:: sage: from psage.modform.jacobiforms.jacobiformd1nn_fegenerators import * sage: from psage.modform.jacobiforms.jacobiformd1nn_types import * sage: nu_bound = 10 sage: precision = 100 sage: weight = 10; index = 7 sage: phis = [jacobi_form_by_taylor_expansion(i, JacobiFormD1NNFilter(precision, index), weight) for i in range(JacobiFormD1NN_Gamma(weight, index)._rank(QQ))] sage: fss = [ [JacobiFormD1NNFactory_class._test__jacobi_corrected_taylor_expansions(nu, phi, weight) for phi in phis] for nu in range(nu_bound) ] sage: fss_vec = [ [vector(f.padded_list(precision)) for f in fs] for fs in fss ] sage: mf_spans = [ span([vector(b.qexp(precision).padded_list(precision)) for b in ModularForms(1, weight + 2 * nu).basis()]) for nu in range(nu_bound) ] sage: all(f_vec in mf_span for (fs_vec, mf_span) in zip(fss_vec, mf_spans) for f_vec in fs_vec) True """ ## We use EZ85, p.29 (3), the factorial in one of the factors is missing factors = [ (-1)**mu * factorial(2 * nu) * factorial(weight + 2 * nu - mu - 2) / ZZ(factorial(mu) * factorial(2 * nu - 2 * mu) * factorial(weight + nu - 2)) for mu in range(nu + 1) ] gegenbauer = lambda n, r: sum( f * r**(2 * nu - 2 * mu) * n**mu for (mu,f) in enumerate(factors) ) ch = JacobiFormD1WeightCharacter(weight) jacobi_index = phi.precision().jacobi_index() coeffs = dict( (n, QQ(0)) for n in range(phi.precision().index()) ) for (n, r) in phi.precision().monoid_filter() : coeffs[n] += gegenbauer(jacobi_index * n, r) * phi[(ch, (n,r))] return PowerSeriesRing(QQ, 'q')(coeffs)
def zeta__exact(n): r""" Returns the exact value of the Riemann Zeta function The argument must be a critical value, namely either positive even or negative odd. See for example [Iwasawa]_, p13, Special value of `\zeta(2k)` EXAMPLES: Let us test the accuracy for negative special values:: sage: RR = RealField(100) sage: for i in range(1,10): ... print "zeta(" + str(1-2*i) + "): ", RR(zeta__exact(1-2*i)) - zeta(RR(1-2*i)) zeta(-1): 0.00000000000000000000000000000 zeta(-3): 0.00000000000000000000000000000 zeta(-5): 0.00000000000000000000000000000 zeta(-7): 0.00000000000000000000000000000 zeta(-9): 0.00000000000000000000000000000 zeta(-11): 0.00000000000000000000000000000 zeta(-13): 0.00000000000000000000000000000 zeta(-15): 0.00000000000000000000000000000 zeta(-17): 0.00000000000000000000000000000 Let us test the accuracy for positive special values:: sage: all(abs(RR(zeta__exact(2*i))-zeta(RR(2*i))) < 10**(-28) for i in range(1,10)) True TESTS:: sage: zeta__exact(5) Traceback (most recent call last): ... TypeError: n must be a critical value (i.e. even > 0 or odd < 0) REFERENCES: .. [Iwasawa] Iwasawa, *Lectures on p-adic L-functions* .. [IreRos] Ireland and Rosen, *A Classical Introduction to Modern Number Theory* .. [WashCyc] Washington, *Cyclotomic Fields* """ if n < 0: return bernoulli(1 - n) / (n - 1) elif n > 1: if (n % 2 == 0): return ZZ(-1)**(n / 2 + 1) * ZZ(2)**( n - 1) * pi**n * bernoulli(n) / factorial(n) else: raise TypeError( "n must be a critical value (i.e. even > 0 or odd < 0)") elif n == 1: return infinity elif n == 0: return -1 / 2
def gamma__exact(n): """ Evaluates the exact value of the gamma function at an integer or half-integer argument. EXAMPLES:: sage: gamma__exact(4) 6 sage: gamma__exact(3) 2 sage: gamma__exact(2) 1 sage: gamma__exact(1) 1 sage: gamma__exact(1/2) sqrt(pi) sage: gamma__exact(3/2) 1/2*sqrt(pi) sage: gamma__exact(5/2) 3/4*sqrt(pi) sage: gamma__exact(7/2) 15/8*sqrt(pi) sage: gamma__exact(-1/2) -2*sqrt(pi) sage: gamma__exact(-3/2) 4/3*sqrt(pi) sage: gamma__exact(-5/2) -8/15*sqrt(pi) sage: gamma__exact(-7/2) 16/105*sqrt(pi) """ from sage.all import sqrt ## SANITY CHECK if (not n in QQ) or (denominator(n) > 2): raise TypeError, "Oops! You much give an integer or half-integer argument." if (denominator(n) == 1): if n <= 0: return infinity if n > 0: return factorial(n - 1) else: ans = QQ(1) while (n != QQ(1) / 2): if (n < 0): ans *= QQ(1) / n n = n + 1 elif (n > 0): n = n - 1 ans *= n ans *= sqrt(pi) return ans
def gamma__exact(n): """ Evaluates the exact value of the gamma function at an integer or half-integer argument. EXAMPLES:: sage: gamma__exact(4) 6 sage: gamma__exact(3) 2 sage: gamma__exact(2) 1 sage: gamma__exact(1) 1 sage: gamma__exact(1/2) sqrt(pi) sage: gamma__exact(3/2) 1/2*sqrt(pi) sage: gamma__exact(5/2) 3/4*sqrt(pi) sage: gamma__exact(7/2) 15/8*sqrt(pi) sage: gamma__exact(-1/2) -2*sqrt(pi) sage: gamma__exact(-3/2) 4/3*sqrt(pi) sage: gamma__exact(-5/2) -8/15*sqrt(pi) sage: gamma__exact(-7/2) 16/105*sqrt(pi) """ from sage.all import sqrt ## SANITY CHECK if (not n in QQ) or (denominator(n) > 2): raise TypeError, "Oops! You much give an integer or half-integer argument." if (denominator(n) == 1): if n <= 0: return infinity if n > 0: return factorial(n-1) else: ans = QQ(1) while (n != QQ(1)/2): if (n<0): ans *= QQ(1)/n n = n + 1 elif (n>0): n = n - 1 ans *= n ans *= sqrt(pi) return ans
def cardinality(self): r""" Return the cardinality of ``self``. The number of fully packed loops on `n \times n` grid .. MATH:: \prod_{k=0}^{n-1} \frac{(3k+1)!}{(n+k)!} = \frac{1! 4! 7! 10! \cdots (3n-2)!}{n! (n+1)! (n+2)! (n+3)! \cdots (2n-1)!}. EXAMPLES:: sage: [AlternatingSignMatrices(n).cardinality() for n in range(0, 11)] [1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460, 129534272700] """ return Integer(prod( [ factorial(3*k+1)/factorial(self._n+k) for k in range(self._n)] ))
def quadratic_L_function__exact(n, d): r""" Returns the exact value of a quadratic twist of the Riemann Zeta function by `\chi_d(x) = \left(\frac{d}{x}\right)`. The input `n` must be a critical value. EXAMPLES:: sage: quadratic_L_function__exact(1, -4) 1/4*pi sage: quadratic_L_function__exact(-4, -4) 5/2 TESTS:: sage: quadratic_L_function__exact(2, -4) Traceback (most recent call last): ... TypeError: n must be a critical value (i.e. odd > 0 or even <= 0) REFERENCES: - [Iwasawa]_, pp 16-17, Special values of `L(1-n, \chi)` and `L(n, \chi)` - [IreRos]_ - [WashCyc]_ """ from sage.all import SR, sqrt if n <= 0: return QuadraticBernoulliNumber(1 - n, d) / (n - 1) elif n >= 1: # Compute the kind of critical values (p10) if kronecker_symbol(fundamental_discriminant(d), -1) == 1: delta = 0 else: delta = 1 # Compute the positive special values (p17) if ((n - delta) % 2 == 0): f = abs(fundamental_discriminant(d)) if delta == 0: GS = sqrt(f) else: GS = I * sqrt(f) ans = SR(ZZ(-1)**(1 + (n - delta) / 2)) ans *= (2 * pi / f)**n ans *= GS # Evaluate the Gauss sum here! =0 ans *= 1 / (2 * I**delta) ans *= QuadraticBernoulliNumber(n, d) / factorial(n) return ans else: if delta == 0: raise TypeError( "n must be a critical value (i.e. even > 0 or odd < 0)") if delta == 1: raise TypeError( "n must be a critical value (i.e. odd > 0 or even <= 0)")
def cardinality(self): r""" Return the number of integer necklaces with the evaluation ``content``. The formula for the number of necklaces of content `\alpha` a composition of `n` is: .. MATH:: \sum_{d|gcd(\alpha)} \phi(d) \binom{n/d}{\alpha_1/d, \ldots, \alpha_\ell/d}, where `\phi(d)` is the Euler `\phi` function. EXAMPLES:: sage: Necklaces([]).cardinality() 0 sage: Necklaces([2,2]).cardinality() 2 sage: Necklaces([2,3,2]).cardinality() 30 sage: Necklaces([0,3,2]).cardinality() 2 Check to make sure that the count matches up with the number of necklace words generated. :: sage: comps = [[],[2,2],[3,2,7],[4,2],[0,4,2],[2,0,4]]+Compositions(4).list() sage: ns = [ Necklaces(comp) for comp in comps] sage: all( [ n.cardinality() == len(n.list()) for n in ns] ) True """ evaluation = self._content le = list(evaluation) if not le: return 0 n = sum(le) return sum(euler_phi(j)*factorial(n/j) / prod(factorial(ni/j) for ni in evaluation) for j in divisors(gcd(le))) / n
def quadratic_L_function__exact(n, d): r""" Returns the exact value of a quadratic twist of the Riemann Zeta function by `\chi_d(x) = \left(\frac{d}{x}\right)`. The input `n` must be a critical value. EXAMPLES:: sage: quadratic_L_function__exact(1, -4) 1/4*pi sage: quadratic_L_function__exact(-4, -4) 5/2 TESTS:: sage: quadratic_L_function__exact(2, -4) Traceback (most recent call last): ... TypeError: n must be a critical value (i.e. odd > 0 or even <= 0) REFERENCES: - [Iwasawa]_, pp 16-17, Special values of `L(1-n, \chi)` and `L(n, \chi)` - [IreRos]_ - [WashCyc]_ """ from sage.all import SR, sqrt if n <= 0: return QuadraticBernoulliNumber(1 - n, d) / (n - 1) elif n >= 1: # Compute the kind of critical values (p10) if kronecker_symbol(fundamental_discriminant(d), -1) == 1: delta = 0 else: delta = 1 # Compute the positive special values (p17) if (n - delta) % 2 == 0: f = abs(fundamental_discriminant(d)) if delta == 0: GS = sqrt(f) else: GS = I * sqrt(f) ans = SR(ZZ(-1) ** (1 + (n - delta) / 2)) ans *= (2 * pi / f) ** n ans *= GS # Evaluate the Gauss sum here! =0 ans *= 1 / (2 * I ** delta) ans *= QuadraticBernoulliNumber(n, d) / factorial(n) return ans else: if delta == 0: raise TypeError("n must be a critical value (i.e. even > 0 or odd < 0)") if delta == 1: raise TypeError("n must be a critical value (i.e. odd > 0 or even <= 0)")
def zeta__exact(n): r""" Returns the exact value of the Riemann Zeta function The argument must be a critical value, namely either positive even or negative odd. See for example [Iwasawa]_, p13, Special value of `\zeta(2k)` EXAMPLES: Let us test the accuracy for negative special values:: sage: RR = RealField(100) sage: for i in range(1,10): ... print "zeta(" + str(1-2*i) + "): ", RR(zeta__exact(1-2*i)) - zeta(RR(1-2*i)) zeta(-1): 0.00000000000000000000000000000 zeta(-3): 0.00000000000000000000000000000 zeta(-5): 0.00000000000000000000000000000 zeta(-7): 0.00000000000000000000000000000 zeta(-9): 0.00000000000000000000000000000 zeta(-11): 0.00000000000000000000000000000 zeta(-13): 0.00000000000000000000000000000 zeta(-15): 0.00000000000000000000000000000 zeta(-17): 0.00000000000000000000000000000 Let us test the accuracy for positive special values:: sage: all(abs(RR(zeta__exact(2*i))-zeta(RR(2*i))) < 10**(-28) for i in range(1,10)) True TESTS:: sage: zeta__exact(5) Traceback (most recent call last): ... TypeError: n must be a critical value (i.e. even > 0 or odd < 0) REFERENCES: .. [Iwasawa] Iwasawa, *Lectures on p-adic L-functions* .. [IreRos] Ireland and Rosen, *A Classical Introduction to Modern Number Theory* .. [WashCyc] Washington, *Cyclotomic Fields* """ if n < 0: return bernoulli(1-n)/(n-1) elif n > 1: if (n % 2 == 0): return ZZ(-1)**(n/2 + 1) * ZZ(2)**(n-1) * pi**n * bernoulli(n) / factorial(n) else: raise TypeError("n must be a critical value (i.e. even > 0 or odd < 0)") elif n==1: return infinity elif n==0: return -1/2
def cardinality(self): r""" Return the cardinality of ``self``. The number of fully packed loops on `n \times n` grid .. MATH:: \prod_{k=0}^{n-1} \frac{(3k+1)!}{(n+k)!} = \frac{1! 4! 7! 10! \cdots (3n-2)!}{n! (n+1)! (n+2)! (n+3)! \cdots (2n-1)!}. EXAMPLES:: sage: [AlternatingSignMatrices(n).cardinality() for n in range(0, 11)] [1, 1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460, 129534272700] """ return Integer( prod([ factorial(3 * k + 1) / factorial(self._n + k) for k in range(self._n) ]))
def cardinality(self): """ EXAMPLES:: sage: OrderedSetPartitions(4,2).cardinality() 14 sage: OrderedSetPartitions(4,1).cardinality() 1 """ set = self.s n = self.n return factorial(n)*stirling_number2(len(set),n)
def zeta__exact(n): r""" Returns the exact value of the Riemann Zeta function References: - Iwasawa's "Lectures on p-adic L-functions", p13, "Special value of `\zeta(2k)`" - Ireland and Rosen's "A Classical Introduction to Modern Number Theory" - Washington's "Cyclotomic Fields" EXAMPLES:: sage: ## Testing the accuracy of the negative special values sage: RR = RealField(100) sage: for i in range(1,10): ... print "zeta(" + str(1-2*i) + "): ", RR(zeta__exact(1-2*i)) - zeta(RR(1-2*i)) zeta(-1): 0.00000000000000000000000000000 zeta(-3): 0.00000000000000000000000000000 zeta(-5): 0.00000000000000000000000000000 zeta(-7): 0.00000000000000000000000000000 zeta(-9): 0.00000000000000000000000000000 zeta(-11): 0.00000000000000000000000000000 zeta(-13): 0.00000000000000000000000000000 zeta(-15): 0.00000000000000000000000000000 zeta(-17): 0.00000000000000000000000000000 sage: RR = RealField(100) sage: for i in range(1,10): ... print "zeta(" + str(1-2*i) + "): ", RR(zeta__exact(1-2*i)) - zeta(RR(1-2*i)) zeta(-1): 0.00000000000000000000000000000 zeta(-3): 0.00000000000000000000000000000 zeta(-5): 0.00000000000000000000000000000 zeta(-7): 0.00000000000000000000000000000 zeta(-9): 0.00000000000000000000000000000 zeta(-11): 0.00000000000000000000000000000 zeta(-13): 0.00000000000000000000000000000 zeta(-15): 0.00000000000000000000000000000 zeta(-17): 0.00000000000000000000000000000 """ if n < 0: k = 1 - n return -bernoulli(k) / k elif n > 1: if (n % 2 == 0): return ZZ(-1)**(n / 2 + 1) * ZZ(2)**( n - 1) * pi**n * bernoulli(n) / factorial(n) else: raise TypeError, "n must be a critical value! (I.e. even > 0 or odd < 0.)" elif n == 1: return infinity elif n == 0: return -1 / 2
def zeta__exact(n): r""" Returns the exact value of the Riemann Zeta function References: - Iwasawa's "Lectures on p-adic L-functions", p13, "Special value of `\zeta(2k)`" - Ireland and Rosen's "A Classical Introduction to Modern Number Theory" - Washington's "Cyclotomic Fields" EXAMPLES:: sage: ## Testing the accuracy of the negative special values sage: RR = RealField(100) sage: for i in range(1,10): ... print "zeta(" + str(1-2*i) + "): ", RR(zeta__exact(1-2*i)) - zeta(RR(1-2*i)) zeta(-1): 0.00000000000000000000000000000 zeta(-3): 0.00000000000000000000000000000 zeta(-5): 0.00000000000000000000000000000 zeta(-7): 0.00000000000000000000000000000 zeta(-9): 0.00000000000000000000000000000 zeta(-11): 0.00000000000000000000000000000 zeta(-13): 0.00000000000000000000000000000 zeta(-15): 0.00000000000000000000000000000 zeta(-17): 0.00000000000000000000000000000 sage: RR = RealField(100) sage: for i in range(1,10): ... print "zeta(" + str(1-2*i) + "): ", RR(zeta__exact(1-2*i)) - zeta(RR(1-2*i)) zeta(-1): 0.00000000000000000000000000000 zeta(-3): 0.00000000000000000000000000000 zeta(-5): 0.00000000000000000000000000000 zeta(-7): 0.00000000000000000000000000000 zeta(-9): 0.00000000000000000000000000000 zeta(-11): 0.00000000000000000000000000000 zeta(-13): 0.00000000000000000000000000000 zeta(-15): 0.00000000000000000000000000000 zeta(-17): 0.00000000000000000000000000000 """ if n<0: k = 1-n return -bernoulli(k)/k elif n>1: if (n % 2 == 0): return ZZ(-1)**(n/2 + 1) * ZZ(2)**(n-1) * pi**n * bernoulli(n) / factorial(n) else: raise TypeError, "n must be a critical value! (I.e. even > 0 or odd < 0.)" elif n==1: return infinity elif n==0: return -1/2
def cardinality(self): """ Return the cardinality of ``self``. The number of ordered partitions of a set of size `n` into `k` parts is equal to `k! S(n,k)` where `S(n,k)` denotes the Stirling number of the second kind. EXAMPLES:: sage: OrderedSetPartitions(4,2).cardinality() 14 sage: OrderedSetPartitions(4,1).cardinality() 1 """ return factorial(self.n)*stirling_number2(len(self._set), self.n)
def cardinality(self): """ Return the cardinality of ``self``. The number of ordered partitions of a set of length `k` into `n` parts is equal to `n! S(n,k)` where `S(n,k)` denotes the Stirling number of the second kind. EXAMPLES:: sage: OrderedSetPartitions(4,2).cardinality() 14 sage: OrderedSetPartitions(4,1).cardinality() 1 """ return factorial(self.n) * stirling_number2(len(self._set), self.n)
def quadratic_L_function__exact(n, d): r""" Returns the exact value of a quadratic twist of the Riemann Zeta function by `\chi_d(x) = \left(\frac{d}{x}\right)`. References: - Iwasawa's "Lectures on p-adic L-functions", p16-17, "Special values of `L(1-n, \chi)` and `L(n, \chi)` - Ireland and Rosen's "A Classical Introduction to Modern Number Theory" - Washington's "Cyclotomic Fields" EXAMPLES:: sage: bool(quadratic_L_function__exact(1, -4) == pi/4) True """ from sage.all import SR, sqrt if n <= 0: k = 1 - n return -QuadraticBernoulliNumber(k, d) / k elif n >= 1: ## Compute the kind of critical values (p10) if kronecker_symbol(fundamental_discriminant(d), -1) == 1: delta = 0 else: delta = 1 ## Compute the positive special values (p17) if ((n - delta) % 2 == 0): f = abs(fundamental_discriminant(d)) if delta == 0: GS = sqrt(f) else: GS = I * sqrt(f) ans = SR(ZZ(-1)**(1 + (n - delta) / 2)) ans *= (2 * pi / f)**n ans *= GS ## Evaluate the Gauss sum here! =0 ans *= 1 / (2 * I**delta) ans *= QuadraticBernoulliNumber(n, d) / factorial(n) return ans else: if delta == 0: raise TypeError, "n must be a critical value!\n" + "(I.e. even > 0 or odd < 0.)" if delta == 1: raise TypeError, "n must be a critical value!\n" + "(I.e. odd > 0 or even <= 0.)"
def quadratic_L_function__exact(n, d): r""" Returns the exact value of a quadratic twist of the Riemann Zeta function by `\chi_d(x) = \left(\frac{d}{x}\right)`. References: - Iwasawa's "Lectures on p-adic L-functions", p16-17, "Special values of `L(1-n, \chi)` and `L(n, \chi)` - Ireland and Rosen's "A Classical Introduction to Modern Number Theory" - Washington's "Cyclotomic Fields" EXAMPLES:: sage: bool(quadratic_L_function__exact(1, -4) == pi/4) True """ from sage.all import SR, sqrt if n<=0: k = 1-n return -QuadraticBernoulliNumber(k,d)/k elif n>=1: ## Compute the kind of critical values (p10) if kronecker_symbol(fundamental_discriminant(d), -1) == 1: delta = 0 else: delta = 1 ## Compute the positive special values (p17) if ((n - delta) % 2 == 0): f = abs(fundamental_discriminant(d)) if delta == 0: GS = sqrt(f) else: GS = I * sqrt(f) ans = SR(ZZ(-1)**(1+(n-delta)/2)) ans *= (2*pi/f)**n ans *= GS ## Evaluate the Gauss sum here! =0 ans *= 1/(2 * I**delta) ans *= QuadraticBernoulliNumber(n,d)/factorial(n) return ans else: if delta == 0: raise TypeError, "n must be a critical value!\n" + "(I.e. even > 0 or odd < 0.)" if delta == 1: raise TypeError, "n must be a critical value!\n" + "(I.e. odd > 0 or even <= 0.)"
def cardinality(self): """ EXAMPLES:: sage: OrderedSetPartitions(0).cardinality() 1 sage: OrderedSetPartitions(1).cardinality() 1 sage: OrderedSetPartitions(2).cardinality() 3 sage: OrderedSetPartitions(3).cardinality() 13 sage: OrderedSetPartitions([1,2,3]).cardinality() 13 sage: OrderedSetPartitions(4).cardinality() 75 sage: OrderedSetPartitions(5).cardinality() 541 """ return sum([factorial(k)*stirling_number2(len(self._set),k) for k in range(len(self._set)+1)])
def __init__(self,b,N,iprec=512,u=None,x0=0): """ x0 is the development point for the Carleman matrix for the slog u is the initial value such that slog(u)=0 or equivalently sexp(0)=u if no u is specified we have slog(x0)=0 """ bsym = b self.bsym = bsym self.N = N self.iprec = iprec x0sym = x0 self.x0sym = x0sym self.prec = None bname = repr(bsym).strip('0').replace('.',',') if bsym == sqrt(2): bname = "sqrt2" if bsym == e**(1/e): bname = "eta" x0name = repr(x0sym) if x0name.find('.') > -1: if x0.is_real(): x0name = repr(float(x0sym)).strip('0').replace('.',',') else: x0name = repr(complex(x0sym)).strip('0').replace('.',',') # by some reason save does not work with additional . inside the path self.path = "savings/itet_%s"%bname + "_N%04d"%N + "_iprec%05d"%iprec + "_a%s"%x0name if iprec != None: b = num(bsym,iprec) self.b = b x0 = num(x0sym,iprec) if x0.is_real(): R = RealField(iprec) else: R = ComplexField(iprec) self.x0 = x0 else: if b == e and x0 == 0: R = QQ else: R = SR self.R = R #Carleman matrix if x0 == 0: #C = Matrix([[ m**n*log(b)**n/factorial(n) for n in range(N)] for m in range(N)]) coeffs = [ln(b)**n/factorial(n) for n in xrange(N)] else: #too slow #C = Matrix([ [ln(b)**n/factorial(n)*sum([binomial(m,k)*k**n*(b**x0)**k*(-x0)**(m-k) for k in range(m+1)]) for n in range(N)] for m in range(N)]) coeffs = [b**x0-x0]+[b**x0*ln(b)**n/factorial(n) for n in xrange(1,N)] def psmul(A,B): N = len(B) return [sum([A[k]*B[n-k] for k in xrange(n+1)]) for n in xrange(N)] C = Matrix(R,N) row = vector(R,[1]+(N-1)*[0]) C[0] = row for m in xrange(1,N): row = psmul(row,coeffs) C[m] = row A = (C - identity_matrix(N)).submatrix(1,0,N-1,N-1) self.A = A print "A computed." if iprec != None: A = num(A,iprec) row = A.solve_left(vector([1] + (N-2)*[0])) print "A solved." self.slog0coeffs = [0]+[row[n] for n in range(N-1)] self.slog0poly = PolynomialRing(R,'x')(self.slog0coeffs[:int(N)/2]) slog0ps = FormalPowerSeriesRing(R)(self.slog0coeffs) sexp0ps = slog0ps.inv() #print self.slog0ps | self.sexp0ps self.sexp0coeffs = sexp0ps[:N] self.sexp0poly = PolynomialRing(R,'x')(self.sexp0coeffs[:int(N)/2]) self.slog_raw0 = lambda z: self.slog0poly(z-self.x0) print "slog reversed." #the primary or the upper fixed point pfp = exp_fixpoint(b,1,prec=iprec) self.pfp = pfp r = abs(x0-pfp) #lower fixed point lfp = None if b <= R(e**(1/e)): lfp = exp_fixpoint(b,0,prec=iprec) r = min(r,abs(x0-lfp)) self.lfp = lfp self.r = r self.c = 0 if not u == None: self.c = - self.slog(u)
def _closed_form(hyp): a, b, z = hyp.operands() a, b = a.operands(), b.operands() p, q = len(a), len(b) if z == 0: return Integer(1) if p == q == 0: return exp(z) if p == 1 and q == 0: return (1 - z)**(-a[0]) if p == 0 and q == 1: # TODO: make this require only linear time def _0f1(b, z): F12 = cosh(2 * sqrt(z)) F32 = sinh(2 * sqrt(z)) / (2 * sqrt(z)) if 2 * b == 1: return F12 if 2 * b == 3: return F32 if 2 * b > 3: return ((b - 2) * (b - 1) / z * (_0f1(b - 2, z) - _0f1(b - 1, z))) if 2 * b < 1: return (_0f1(b + 1, z) + z / (b * (b + 1)) * _0f1(b + 2, z)) raise ValueError # Can evaluate 0F1 in terms of elementary functions when # the parameter is a half-integer if 2 * b[0] in ZZ and b[0] not in ZZ: return _0f1(b[0], z) # Confluent hypergeometric function if p == 1 and q == 1: aa, bb = a[0], b[0] if aa * 2 == 1 and bb * 2 == 3: t = sqrt(-z) return sqrt(pi) / 2 * erf(t) / t if a == 1 and b == 2: return (exp(z) - 1) / z n, m = aa, bb if n in ZZ and m in ZZ and m > 0 and n > 0: rf = rising_factorial if m <= n: return (exp(z) * sum( rf(m - n, k) * (-z)**k / factorial(k) / rf(m, k) for k in xrange(n - m + 1))) else: T = sum( rf(n - m + 1, k) * z**k / (factorial(k) * rf(2 - m, k)) for k in xrange(m - n)) U = sum( rf(1 - n, k) * (-z)**k / (factorial(k) * rf(2 - m, k)) for k in xrange(n)) return (factorial(m - 2) * rf(1 - m, n) * z**(1 - m) / factorial(n - 1) * (T - exp(z) * U)) if p == 2 and q == 1: R12 = QQ('1/2') R32 = QQ('3/2') def _2f1(a, b, c, z): """ Evaluation of 2F1(a, b, c, z), assuming a, b, c positive integers or half-integers """ if b == c: return (1 - z)**(-a) if a == c: return (1 - z)**(-b) if a == 0 or b == 0: return Integer(1) if a > b: a, b = b, a if b >= 2: F1 = _2f1(a, b - 1, c, z) F2 = _2f1(a, b - 2, c, z) q = (b - 1) * (z - 1) return (((c - 2 * b + 2 + (b - a - 1) * z) * F1 + (b - c - 1) * F2) / q) if c > 2: # how to handle this case? if a - c + 1 == 0 or b - c + 1 == 0: raise NotImplementedError F1 = _2f1(a, b, c - 1, z) F2 = _2f1(a, b, c - 2, z) r1 = (c - 1) * (2 - c - (a + b - 2 * c + 3) * z) r2 = (c - 1) * (c - 2) * (1 - z) q = (a - c + 1) * (b - c + 1) * z return (r1 * F1 + r2 * F2) / q if (a, b, c) == (R12, 1, 2): return (2 - 2 * sqrt(1 - z)) / z if (a, b, c) == (1, 1, 2): return -log(1 - z) / z if (a, b, c) == (1, R32, R12): return (1 + z) / (1 - z)**2 if (a, b, c) == (1, R32, 2): return 2 * (1 / sqrt(1 - z) - 1) / z if (a, b, c) == (R32, 2, R12): return (1 + 3 * z) / (1 - z)**3 if (a, b, c) == (R32, 2, 1): return (2 + z) / (2 * (sqrt(1 - z) * (1 - z)**2)) if (a, b, c) == (2, 2, 1): return (1 + z) / (1 - z)**3 raise NotImplementedError aa, bb = a cc, = b if z == 1: return (gamma(cc) * gamma(cc - aa - bb) / gamma(cc - aa) / gamma(cc - bb)) if ((aa * 2) in ZZ and (bb * 2) in ZZ and (cc * 2) in ZZ and aa > 0 and bb > 0 and cc > 0): try: return _2f1(aa, bb, cc, z) except NotImplementedError: pass return hyp
def f(n): return diff(expr,var,n).substitute({var:at})/factorial(n)
def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=None, simplify=True, simplify_all=False): """ Compute the splitting field of a given polynomial, defined over a number field. INPUT: - ``poly`` -- a monic polynomial over a number field - ``name`` -- a variable name for the number field - ``map`` -- (default: ``False``) also return an embedding of ``poly`` into the resulting field. Note that computing this embedding might be expensive. - ``degree_multiple`` -- a multiple of the absolute degree of the splitting field. If ``degree_multiple`` equals the actual degree, this can enormously speed up the computation. - ``abort_degree`` -- abort by raising a :class:`SplittingFieldAbort` if it can be determined that the absolute degree of the splitting field is strictly larger than ``abort_degree``. - ``simplify`` -- (default: ``True``) during the algorithm, try to find a simpler defining polynomial for the intermediate number fields using PARI's ``polred()``. This usually speeds up the computation but can also considerably slow it down. Try and see what works best in the given situation. - ``simplify_all`` -- (default: ``False``) If ``True``, simplify intermediate fields and also the resulting number field. OUTPUT: If ``map`` is ``False``, the splitting field as an absolute number field. If ``map`` is ``True``, a tuple ``(K, phi)`` where ``phi`` is an embedding of the base field in ``K``. EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = (x^3 + 2).splitting_field(); K Number Field in a with defining polynomial x^6 + 3*x^5 + 6*x^4 + 11*x^3 + 12*x^2 - 3*x + 1 sage: K.<a> = (x^3 - 3*x + 1).splitting_field(); K Number Field in a with defining polynomial x^3 - 3*x + 1 The ``simplify`` and ``simplify_all`` flags usually yield fields defined by polynomials with smaller coefficients. By default, ``simplify`` is True and ``simplify_all`` is False. :: sage: (x^4 - x + 1).splitting_field('a', simplify=False) Number Field in a with defining polynomial x^24 - 2780*x^22 + 2*x^21 + 3527512*x^20 - 2876*x^19 - 2701391985*x^18 + 945948*x^17 + 1390511639677*x^16 + 736757420*x^15 - 506816498313560*x^14 - 822702898220*x^13 + 134120588299548463*x^12 + 362240696528256*x^11 - 25964582366880639486*x^10 - 91743672243419990*x^9 + 3649429473447308439427*x^8 + 14310332927134072336*x^7 - 363192569823568746892571*x^6 - 1353403793640477725898*x^5 + 24293393281774560140427565*x^4 + 70673814899934142357628*x^3 - 980621447508959243128437933*x^2 - 1539841440617805445432660*x + 18065914012013502602456565991 sage: (x^4 - x + 1).splitting_field('a', simplify=True) Number Field in a with defining polynomial x^24 + 8*x^23 - 32*x^22 - 310*x^21 + 540*x^20 + 4688*x^19 - 6813*x^18 - 32380*x^17 + 49525*x^16 + 102460*x^15 - 129944*x^14 - 287884*x^13 + 372727*x^12 + 150624*x^11 - 110530*x^10 - 566926*x^9 + 1062759*x^8 - 779940*x^7 + 863493*x^6 - 1623578*x^5 + 1759513*x^4 - 955624*x^3 + 459975*x^2 - 141948*x + 53919 sage: (x^4 - x + 1).splitting_field('a', simplify_all=True) Number Field in a with defining polynomial x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + 32*x^18 - 35*x^17 - 92*x^16 + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + 163*x^10 + 49*x^9 - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 Reducible polynomials also work:: sage: pol = (x^4 - 1)*(x^2 + 1/2)*(x^2 + 1/3) sage: pol.splitting_field('a', simplify_all=True) Number Field in a with defining polynomial x^8 - x^4 + 1 Relative situation:: sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(x^3 + 2) sage: S.<t> = PolynomialRing(K) sage: L.<b> = (t^2 - a).splitting_field() sage: L Number Field in b with defining polynomial t^6 + 2 With ``map=True``, we also get the embedding of the base field into the splitting field:: sage: L.<b>, phi = (t^2 - a).splitting_field(map=True) sage: phi Ring morphism: From: Number Field in a with defining polynomial x^3 + 2 To: Number Field in b with defining polynomial t^6 + 2 Defn: a |--> b^2 sage: (x^4 - x + 1).splitting_field('a', simplify_all=True, map=True)[1] Ring morphism: From: Rational Field To: Number Field in a with defining polynomial x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + 32*x^18 - 35*x^17 - 92*x^16 + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + 163*x^10 + 49*x^9 - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 Defn: 1 |--> 1 We can enable verbose messages:: sage: set_verbose(2) sage: K.<a> = (x^3 - x + 1).splitting_field() verbose 1 (...: splitting_field.py, splitting_field) Starting field: y verbose 1 (...: splitting_field.py, splitting_field) SplittingData to factor: [(3, 0)] verbose 2 (...: splitting_field.py, splitting_field) Done factoring (time = ...) verbose 1 (...: splitting_field.py, splitting_field) SplittingData to handle: [(2, 2), (3, 3)] verbose 1 (...: splitting_field.py, splitting_field) Bounds for absolute degree: [6, 6] verbose 2 (...: splitting_field.py, splitting_field) Handling polynomial x^2 + 23 verbose 1 (...: splitting_field.py, splitting_field) New field before simplifying: x^2 + 23 (time = ...) verbose 1 (...: splitting_field.py, splitting_field) New field: y^2 - y + 6 (time = ...) verbose 2 (...: splitting_field.py, splitting_field) Converted polynomials to new field (time = ...) verbose 1 (...: splitting_field.py, splitting_field) SplittingData to factor: [] verbose 2 (...: splitting_field.py, splitting_field) Done factoring (time = ...) verbose 1 (...: splitting_field.py, splitting_field) SplittingData to handle: [(3, 3)] verbose 1 (...: splitting_field.py, splitting_field) Bounds for absolute degree: [6, 6] verbose 2 (...: splitting_field.py, splitting_field) Handling polynomial x^3 - x + 1 verbose 1 (...: splitting_field.py, splitting_field) New field: y^6 + 3*y^5 + 19*y^4 + 35*y^3 + 127*y^2 + 73*y + 271 (time = ...) sage: set_verbose(0) Try all Galois groups in degree 4. We use a quadratic base field such that ``polgalois()`` cannot be used:: sage: R.<x> = PolynomialRing(QuadraticField(-11)) sage: C2C2pol = x^4 - 10*x^2 + 1 sage: C2C2pol.splitting_field('x') Number Field in x with defining polynomial x^8 + 24*x^6 + 608*x^4 + 9792*x^2 + 53824 sage: C4pol = x^4 + x^3 + x^2 + x + 1 sage: C4pol.splitting_field('x') Number Field in x with defining polynomial x^8 - x^7 - 2*x^6 + 5*x^5 + x^4 + 15*x^3 - 18*x^2 - 27*x + 81 sage: D8pol = x^4 - 2 sage: D8pol.splitting_field('x') Number Field in x with defining polynomial x^16 + 8*x^15 + 68*x^14 + 336*x^13 + 1514*x^12 + 5080*x^11 + 14912*x^10 + 35048*x^9 + 64959*x^8 + 93416*x^7 + 88216*x^6 + 41608*x^5 - 25586*x^4 - 60048*x^3 - 16628*x^2 + 12008*x + 34961 sage: A4pol = x^4 - 4*x^3 + 14*x^2 - 28*x + 21 sage: A4pol.splitting_field('x') Number Field in x with defining polynomial x^24 - 20*x^23 + 290*x^22 - 3048*x^21 + 26147*x^20 - 186132*x^19 + 1130626*x^18 - 5913784*x^17 + 26899345*x^16 - 106792132*x^15 + 371066538*x^14 - 1127792656*x^13 + 2991524876*x^12 - 6888328132*x^11 + 13655960064*x^10 - 23000783036*x^9 + 32244796382*x^8 - 36347834476*x^7 + 30850889884*x^6 - 16707053128*x^5 + 1896946429*x^4 + 4832907884*x^3 - 3038258802*x^2 - 200383596*x + 593179173 sage: S4pol = x^4 + x + 1 sage: S4pol.splitting_field('x') Number Field in x with defining polynomial x^48 ... Some bigger examples:: sage: R.<x> = PolynomialRing(QQ) sage: pol15 = chebyshev_T(31, x) - 1 # 2^30*(x-1)*minpoly(cos(2*pi/31))^2 sage: pol15.splitting_field('a') Number Field in a with defining polynomial x^15 - x^14 - 14*x^13 + 13*x^12 + 78*x^11 - 66*x^10 - 220*x^9 + 165*x^8 + 330*x^7 - 210*x^6 - 252*x^5 + 126*x^4 + 84*x^3 - 28*x^2 - 8*x + 1 sage: pol48 = x^6 - 4*x^4 + 12*x^2 - 12 sage: pol48.splitting_field('a') Number Field in a with defining polynomial x^48 ... If you somehow know the degree of the field in advance, you should add a ``degree_multiple`` argument. This can speed up the computation, in particular for polynomials of degree >= 12 or for relative extensions:: sage: pol15.splitting_field('a', degree_multiple=15) Number Field in a with defining polynomial x^15 + x^14 - 14*x^13 - 13*x^12 + 78*x^11 + 66*x^10 - 220*x^9 - 165*x^8 + 330*x^7 + 210*x^6 - 252*x^5 - 126*x^4 + 84*x^3 + 28*x^2 - 8*x - 1 A value for ``degree_multiple`` which isn't actually a multiple of the absolute degree of the splitting field can either result in a wrong answer or the following exception:: sage: pol48.splitting_field('a', degree_multiple=20) Traceback (most recent call last): ... ValueError: inconsistent degree_multiple in splitting_field() Compute the Galois closure as the splitting field of the defining polynomial:: sage: R.<x> = PolynomialRing(QQ) sage: pol48 = x^6 - 4*x^4 + 12*x^2 - 12 sage: K.<a> = NumberField(pol48) sage: L.<b> = pol48.change_ring(K).splitting_field() sage: L Number Field in b with defining polynomial x^48 ... Try all Galois groups over `\QQ` in degree 5 except for `S_5` (the latter is infeasible with the current implementation):: sage: C5pol = x^5 + x^4 - 4*x^3 - 3*x^2 + 3*x + 1 sage: C5pol.splitting_field('x') Number Field in x with defining polynomial x^5 + x^4 - 4*x^3 - 3*x^2 + 3*x + 1 sage: D10pol = x^5 - x^4 - 5*x^3 + 4*x^2 + 3*x - 1 sage: D10pol.splitting_field('x') Number Field in x with defining polynomial x^10 - 28*x^8 + 216*x^6 - 681*x^4 + 902*x^2 - 401 sage: AGL_1_5pol = x^5 - 2 sage: AGL_1_5pol.splitting_field('x') Number Field in x with defining polynomial x^20 + 10*x^19 + 55*x^18 + 210*x^17 + 595*x^16 + 1300*x^15 + 2250*x^14 + 3130*x^13 + 3585*x^12 + 3500*x^11 + 2965*x^10 + 2250*x^9 + 1625*x^8 + 1150*x^7 + 750*x^6 + 400*x^5 + 275*x^4 + 100*x^3 + 75*x^2 + 25 sage: A5pol = x^5 - x^4 + 2*x^2 - 2*x + 2 sage: A5pol.splitting_field('x') Number Field in x with defining polynomial x^60 ... We can use the ``abort_degree`` option if we don't want to compute fields of too large degree (this can be used to check whether the splitting field has small degree):: sage: (x^5+x+3).splitting_field('b', abort_degree=119) Traceback (most recent call last): ... SplittingFieldAbort: degree of splitting field equals 120 sage: (x^10+x+3).splitting_field('b', abort_degree=60) # long time (10s on sage.math, 2014) Traceback (most recent call last): ... SplittingFieldAbort: degree of splitting field is a multiple of 180 Use the ``degree_divisor`` attribute to recover the divisor of the degree of the splitting field or ``degree_multiple`` to recover a multiple:: sage: from sage.rings.number_field.splitting_field import SplittingFieldAbort sage: try: # long time (4s on sage.math, 2014) ....: (x^8+x+1).splitting_field('b', abort_degree=60, simplify=False) ....: except SplittingFieldAbort as e: ....: print e.degree_divisor ....: print e.degree_multiple 120 1440 TESTS:: sage: from sage.rings.number_field.splitting_field import splitting_field sage: splitting_field(polygen(QQ), name='x', map=True, simplify_all=True) (Number Field in x with defining polynomial x, Ring morphism: From: Rational Field To: Number Field in x with defining polynomial x Defn: 1 |--> 1) """ from sage.misc.all import verbose, cputime degree_multiple = Integer(degree_multiple or 0) abort_degree = Integer(abort_degree or 0) # Kpol = PARI polynomial in y defining the extension found so far F = poly.base_ring() if is_RationalField(F): Kpol = pari("'y") else: Kpol = F.pari_polynomial("y") # Fgen = the generator of F as element of Q[y]/Kpol # (only needed if map=True) if map: Fgen = F.gen()._pari_() verbose("Starting field: %s"%Kpol) # L and Lred are lists of SplittingData. # L contains polynomials which are irreducible over K, # Lred contains polynomials which need to be factored. L = [] Lred = [SplittingData(poly._pari_with_name(), degree_multiple)] # Main loop, handle polynomials one by one while True: # Absolute degree of current field K absolute_degree = Integer(Kpol.poldegree()) # Compute minimum relative degree of splitting field rel_degree_divisor = Integer(1) for splitting in L: rel_degree_divisor = rel_degree_divisor.lcm(splitting.poldegree()) # Check for early aborts abort_rel_degree = abort_degree//absolute_degree if abort_rel_degree and rel_degree_divisor > abort_rel_degree: raise SplittingFieldAbort(absolute_degree * rel_degree_divisor, degree_multiple) # First, factor polynomials in Lred and store the result in L verbose("SplittingData to factor: %s"%[s._repr_tuple() for s in Lred]) t = cputime() for splitting in Lred: m = splitting.dm.gcd(degree_multiple).gcd(factorial(splitting.poldegree())) if m == 1: continue factors = Kpol.nffactor(splitting.pol)[0] for q in factors: d = q.poldegree() fac = factorial(d) # Multiple of the degree of the splitting field of q, # note that the degree equals fac iff the Galois group is S_n. mq = m.gcd(fac) if mq == 1: continue # Multiple of the degree of the splitting field of q # over the field defined by adding square root of the # discriminant. # If the Galois group is contained in A_n, then mq_alt is # also the degree multiple over the current field K. # Here, we have equality if the Galois group is A_n. mq_alt = mq.gcd(fac//2) # If we are over Q, then use PARI's polgalois() to compute # these degrees exactly. if absolute_degree == 1: try: G = q.polgalois() except PariError: pass else: mq = Integer(G[0]) mq_alt = mq//2 if (G[1] == -1) else mq # In degree 4, use the cubic resolvent to refine the # degree bounds. if d == 4 and mq >= 12: # mq equals 12 or 24 # Compute cubic resolvent a0, a1, a2, a3, a4 = (q/q.pollead()).Vecrev() assert a4 == 1 cubicpol = pari([4*a0*a2 - a1*a1 -a0*a3*a3, a1*a3 - 4*a0, -a2, 1]).Polrev() cubicfactors = Kpol.nffactor(cubicpol)[0] if len(cubicfactors) == 1: # A4 or S4 # After adding a root of the cubic resolvent, # the degree of the extension defined by q # is a factor 3 smaller. L.append(SplittingData(cubicpol, 3)) rel_degree_divisor = rel_degree_divisor.lcm(3) mq = mq//3 # 4 or 8 mq_alt = 4 elif len(cubicfactors) == 2: # C4 or D8 # The irreducible degree 2 factor is # equivalent to x^2 - q.poldisc(). discpol = cubicfactors[1] L.append(SplittingData(discpol, 2)) mq = mq_alt = 4 else: # C2 x C2 mq = mq_alt = 4 if mq > mq_alt >= 3: # Add quadratic resolvent x^2 - D to decrease # the degree multiple by a factor 2. discpol = pari([-q.poldisc(), 0, 1]).Polrev() discfactors = Kpol.nffactor(discpol)[0] if len(discfactors) == 1: # Discriminant is not a square L.append(SplittingData(discpol, 2)) rel_degree_divisor = rel_degree_divisor.lcm(2) mq = mq_alt L.append(SplittingData(q, mq)) rel_degree_divisor = rel_degree_divisor.lcm(q.poldegree()) if abort_rel_degree and rel_degree_divisor > abort_rel_degree: raise SplittingFieldAbort(absolute_degree * rel_degree_divisor, degree_multiple) verbose("Done factoring", t, level=2) if len(L) == 0: # Nothing left to do break # Recompute absolute degree multiple new_degree_multiple = absolute_degree for splitting in L: new_degree_multiple *= splitting.dm degree_multiple = new_degree_multiple.gcd(degree_multiple) # Absolute degree divisor degree_divisor = rel_degree_divisor * absolute_degree # Sort according to degree to handle low degrees first L.sort() verbose("SplittingData to handle: %s"%[s._repr_tuple() for s in L]) verbose("Bounds for absolute degree: [%s, %s]"%(degree_divisor,degree_multiple)) # Check consistency if degree_multiple % degree_divisor != 0: raise ValueError("inconsistent degree_multiple in splitting_field()") for splitting in L: # The degree of the splitting field must be a multiple of # the degree of the polynomial. Only do this check for # SplittingData with minimal dm, because the higher dm are # defined as relative degree over the splitting field of # the polynomials with lesser dm. if splitting.dm > L[0].dm: break if splitting.dm % splitting.poldegree() != 0: raise ValueError("inconsistent degree_multiple in splitting_field()") # Add a root of f = L[0] to construct the field N = K[x]/f(x) splitting = L[0] f = splitting.pol verbose("Handling polynomial %s"%(f.lift()), level=2) t = cputime() Npol, KtoN, k = Kpol.rnfequation(f, flag=1) # Make Npol monic integral primitive, store in Mpol # (after this, we don't need Npol anymore, only Mpol) Mdiv = pari(1) Mpol = Npol while True: denom = Integer(Mpol.pollead()) if denom == 1: break denom = pari(denom.factor().radical_value()) Mpol = (Mpol*(denom**Mpol.poldegree())).subst("x", pari([0,1/denom]).Polrev("x")) Mpol /= Mpol.content() Mdiv *= denom # We are finished for sure if we hit the degree bound finished = (Mpol.poldegree() >= degree_multiple) if simplify_all or (simplify and not finished): # Find a simpler defining polynomial Lpol for Mpol verbose("New field before simplifying: %s"%Mpol, t) t = cputime() M = Mpol.polred(flag=3) n = len(M[0])-1 Lpol = M[1][n].change_variable_name("y") LtoM = M[0][n].change_variable_name("y").Mod(Mpol.change_variable_name("y")) MtoL = LtoM.modreverse() else: # Lpol = Mpol Lpol = Mpol.change_variable_name("y") MtoL = pari("'y") NtoL = MtoL/Mdiv KtoL = KtoN.lift().subst("x", NtoL).Mod(Lpol) Kpol = Lpol # New Kpol (for next iteration) verbose("New field: %s"%Kpol, t) if map: t = cputime() Fgen = Fgen.lift().subst("y", KtoL) verbose("Computed generator of F in K", t, level=2) if finished: break t = cputime() # Convert f and elements of L from K to L and store in L # (if the polynomial is certain to remain irreducible) or Lred. Lold = L[1:] L = [] Lred = [] # First add f divided by the linear factor we obtained, # mg is the new degree multiple. mg = splitting.dm//f.poldegree() if mg > 1: g = [c.subst("y", KtoL).Mod(Lpol) for c in f.Vecrev().lift()] g = pari(g).Polrev() g /= pari([k*KtoL - NtoL, 1]).Polrev() # divide linear factor Lred.append(SplittingData(g, mg)) for splitting in Lold: g = [c.subst("y", KtoL) for c in splitting.pol.Vecrev().lift()] g = pari(g).Polrev() mg = splitting.dm if Integer(g.poldegree()).gcd(f.poldegree()) == 1: # linearly disjoint fields L.append(SplittingData(g, mg)) else: Lred.append(SplittingData(g, mg)) verbose("Converted polynomials to new field", t, level=2) # Convert Kpol to Sage and construct the absolute number field Kpol = PolynomialRing(RationalField(), name=poly.variable_name())(Kpol/Kpol.pollead()) K = NumberField(Kpol, name) if map: return K, F.hom(Fgen, K) else: return K
def tuple_orbit_reps(self, k, prefix=None): if prefix is None: prefix = [] s = len(prefix) tp = tuple(prefix) if s > k: raise ValueError if k == 0: return 1, {(): 1} gens = self._graph.automorphism_group_gens() # Pass generators to GAP to create a group for us. gen_str = ",".join("(" + "".join(str(cy) for cy in cys) + ")" for cys in gens) gap.eval("g := Group(%s);" % gen_str) if len(prefix) > 0: gap.eval("g := Stabilizer(g, %s, OnTuples);" % list(set(prefix))) S = [] for i in range(1, k - s + 1): S.extend([tuple(sorted(list(x))) for x in Subsets(self._graph.n, i)]) set_orb_reps = {} # sys.stdout.write("Calculating orbits") while len(S) > 0: rep = list(S[0]) o = gap.new("Orbit(g, %s, OnSets);" % (rep,)).sage() o = list(set([tuple(sorted(t)) for t in o])) ot = o[0] set_orb_reps[ot] = len(o) for t in o: S.remove(t) # sys.stdout.write(".") # sys.stdout.flush() # sys.stdout.write("\n") combs = [tuple(c) for c in Compositions(k - s)] factors = [] for c in combs: factor = factorial(k - s) for x in c: factor /= factorial(x) factors.append(factor) orb_reps = {} total = 0 for ot, length in set_orb_reps.iteritems(): ne = len(ot) for ci in range(len(combs)): c = combs[ci] if len(c) == ne: t = tp for i in range(ne): t += c[i] * (ot[i],) weight = factors[ci] * length orb_reps[t] = weight total += weight return total, orb_reps
def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=None, simplify=True, simplify_all=False): """ Compute the splitting field of a given polynomial, defined over a number field. INPUT: - ``poly`` -- a monic polynomial over a number field - ``name`` -- a variable name for the number field - ``map`` -- (default: ``False``) also return an embedding of ``poly`` into the resulting field. Note that computing this embedding might be expensive. - ``degree_multiple`` -- a multiple of the absolute degree of the splitting field. If ``degree_multiple`` equals the actual degree, this can enormously speed up the computation. - ``abort_degree`` -- abort by raising a :class:`SplittingFieldAbort` if it can be determined that the absolute degree of the splitting field is strictly larger than ``abort_degree``. - ``simplify`` -- (default: ``True``) during the algorithm, try to find a simpler defining polynomial for the intermediate number fields using PARI's ``polred()``. This usually speeds up the computation but can also considerably slow it down. Try and see what works best in the given situation. - ``simplify_all`` -- (default: ``False``) If ``True``, simplify intermediate fields and also the resulting number field. OUTPUT: If ``map`` is ``False``, the splitting field as an absolute number field. If ``map`` is ``True``, a tuple ``(K, phi)`` where ``phi`` is an embedding of the base field in ``K``. EXAMPLES:: sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = (x^3 + 2).splitting_field(); K Number Field in a with defining polynomial x^6 + 3*x^5 + 6*x^4 + 11*x^3 + 12*x^2 - 3*x + 1 sage: K.<a> = (x^3 - 3*x + 1).splitting_field(); K Number Field in a with defining polynomial x^3 - 3*x + 1 The ``simplify`` and ``simplify_all`` flags usually yield fields defined by polynomials with smaller coefficients. By default, ``simplify`` is True and ``simplify_all`` is False. :: sage: (x^4 - x + 1).splitting_field('a', simplify=False) Number Field in a with defining polynomial x^24 - 2780*x^22 + 2*x^21 + 3527512*x^20 - 2876*x^19 - 2701391985*x^18 + 945948*x^17 + 1390511639677*x^16 + 736757420*x^15 - 506816498313560*x^14 - 822702898220*x^13 + 134120588299548463*x^12 + 362240696528256*x^11 - 25964582366880639486*x^10 - 91743672243419990*x^9 + 3649429473447308439427*x^8 + 14310332927134072336*x^7 - 363192569823568746892571*x^6 - 1353403793640477725898*x^5 + 24293393281774560140427565*x^4 + 70673814899934142357628*x^3 - 980621447508959243128437933*x^2 - 1539841440617805445432660*x + 18065914012013502602456565991 sage: (x^4 - x + 1).splitting_field('a', simplify=True) Number Field in a with defining polynomial x^24 + 8*x^23 - 32*x^22 - 310*x^21 + 540*x^20 + 4688*x^19 - 6813*x^18 - 32380*x^17 + 49525*x^16 + 102460*x^15 - 129944*x^14 - 287884*x^13 + 372727*x^12 + 150624*x^11 - 110530*x^10 - 566926*x^9 + 1062759*x^8 - 779940*x^7 + 863493*x^6 - 1623578*x^5 + 1759513*x^4 - 955624*x^3 + 459975*x^2 - 141948*x + 53919 sage: (x^4 - x + 1).splitting_field('a', simplify_all=True) Number Field in a with defining polynomial x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + 32*x^18 - 35*x^17 - 92*x^16 + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + 163*x^10 + 49*x^9 - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 Reducible polynomials also work:: sage: pol = (x^4 - 1)*(x^2 + 1/2)*(x^2 + 1/3) sage: pol.splitting_field('a', simplify_all=True) Number Field in a with defining polynomial x^8 - x^4 + 1 Relative situation:: sage: R.<x> = PolynomialRing(QQ) sage: K.<a> = NumberField(x^3 + 2) sage: S.<t> = PolynomialRing(K) sage: L.<b> = (t^2 - a).splitting_field() sage: L Number Field in b with defining polynomial t^6 + 2 With ``map=True``, we also get the embedding of the base field into the splitting field:: sage: L.<b>, phi = (t^2 - a).splitting_field(map=True) sage: phi Ring morphism: From: Number Field in a with defining polynomial x^3 + 2 To: Number Field in b with defining polynomial t^6 + 2 Defn: a |--> b^2 sage: (x^4 - x + 1).splitting_field('a', simplify_all=True, map=True)[1] Ring morphism: From: Rational Field To: Number Field in a with defining polynomial x^24 - 3*x^23 + 2*x^22 - x^20 + 4*x^19 + 32*x^18 - 35*x^17 - 92*x^16 + 49*x^15 + 163*x^14 - 15*x^13 - 194*x^12 - 15*x^11 + 163*x^10 + 49*x^9 - 92*x^8 - 35*x^7 + 32*x^6 + 4*x^5 - x^4 + 2*x^2 - 3*x + 1 Defn: 1 |--> 1 We can enable verbose messages:: sage: set_verbose(2) sage: K.<a> = (x^3 - x + 1).splitting_field() verbose 1 (...: splitting_field.py, splitting_field) Starting field: y verbose 1 (...: splitting_field.py, splitting_field) SplittingData to factor: [(3, 0)] verbose 2 (...: splitting_field.py, splitting_field) Done factoring (time = ...) verbose 1 (...: splitting_field.py, splitting_field) SplittingData to handle: [(2, 2), (3, 3)] verbose 1 (...: splitting_field.py, splitting_field) Bounds for absolute degree: [6, 6] verbose 2 (...: splitting_field.py, splitting_field) Handling polynomial x^2 + 23 verbose 1 (...: splitting_field.py, splitting_field) New field before simplifying: x^2 + 23 (time = ...) verbose 1 (...: splitting_field.py, splitting_field) New field: y^2 - y + 6 (time = ...) verbose 2 (...: splitting_field.py, splitting_field) Converted polynomials to new field (time = ...) verbose 1 (...: splitting_field.py, splitting_field) SplittingData to factor: [] verbose 2 (...: splitting_field.py, splitting_field) Done factoring (time = ...) verbose 1 (...: splitting_field.py, splitting_field) SplittingData to handle: [(3, 3)] verbose 1 (...: splitting_field.py, splitting_field) Bounds for absolute degree: [6, 6] verbose 2 (...: splitting_field.py, splitting_field) Handling polynomial x^3 - x + 1 verbose 1 (...: splitting_field.py, splitting_field) New field: y^6 + 3*y^5 + 19*y^4 + 35*y^3 + 127*y^2 + 73*y + 271 (time = ...) sage: set_verbose(0) Try all Galois groups in degree 4. We use a quadratic base field such that ``polgalois()`` cannot be used:: sage: R.<x> = PolynomialRing(QuadraticField(-11)) sage: C2C2pol = x^4 - 10*x^2 + 1 sage: C2C2pol.splitting_field('x') Number Field in x with defining polynomial x^8 + 24*x^6 + 608*x^4 + 9792*x^2 + 53824 sage: C4pol = x^4 + x^3 + x^2 + x + 1 sage: C4pol.splitting_field('x') Number Field in x with defining polynomial x^8 - x^7 - 2*x^6 + 5*x^5 + x^4 + 15*x^3 - 18*x^2 - 27*x + 81 sage: D8pol = x^4 - 2 sage: D8pol.splitting_field('x') Number Field in x with defining polynomial x^16 + 8*x^15 + 68*x^14 + 336*x^13 + 1514*x^12 + 5080*x^11 + 14912*x^10 + 35048*x^9 + 64959*x^8 + 93416*x^7 + 88216*x^6 + 41608*x^5 - 25586*x^4 - 60048*x^3 - 16628*x^2 + 12008*x + 34961 sage: A4pol = x^4 - 4*x^3 + 14*x^2 - 28*x + 21 sage: A4pol.splitting_field('x') Number Field in x with defining polynomial x^24 - 20*x^23 + 290*x^22 - 3048*x^21 + 26147*x^20 - 186132*x^19 + 1130626*x^18 - 5913784*x^17 + 26899345*x^16 - 106792132*x^15 + 371066538*x^14 - 1127792656*x^13 + 2991524876*x^12 - 6888328132*x^11 + 13655960064*x^10 - 23000783036*x^9 + 32244796382*x^8 - 36347834476*x^7 + 30850889884*x^6 - 16707053128*x^5 + 1896946429*x^4 + 4832907884*x^3 - 3038258802*x^2 - 200383596*x + 593179173 sage: S4pol = x^4 + x + 1 sage: S4pol.splitting_field('x') Number Field in x with defining polynomial x^48 ... Some bigger examples:: sage: R.<x> = PolynomialRing(QQ) sage: pol15 = chebyshev_T(31, x) - 1 # 2^30*(x-1)*minpoly(cos(2*pi/31))^2 sage: pol15.splitting_field('a') Number Field in a with defining polynomial x^15 - x^14 - 14*x^13 + 13*x^12 + 78*x^11 - 66*x^10 - 220*x^9 + 165*x^8 + 330*x^7 - 210*x^6 - 252*x^5 + 126*x^4 + 84*x^3 - 28*x^2 - 8*x + 1 sage: pol48 = x^6 - 4*x^4 + 12*x^2 - 12 sage: pol48.splitting_field('a') Number Field in a with defining polynomial x^48 ... If you somehow know the degree of the field in advance, you should add a ``degree_multiple`` argument. This can speed up the computation, in particular for polynomials of degree >= 12 or for relative extensions:: sage: pol15.splitting_field('a', degree_multiple=15) Number Field in a with defining polynomial x^15 + x^14 - 14*x^13 - 13*x^12 + 78*x^11 + 66*x^10 - 220*x^9 - 165*x^8 + 330*x^7 + 210*x^6 - 252*x^5 - 126*x^4 + 84*x^3 + 28*x^2 - 8*x - 1 A value for ``degree_multiple`` which isn't actually a multiple of the absolute degree of the splitting field can either result in a wrong answer or the following exception:: sage: pol48.splitting_field('a', degree_multiple=20) Traceback (most recent call last): ... ValueError: inconsistent degree_multiple in splitting_field() Compute the Galois closure as the splitting field of the defining polynomial:: sage: R.<x> = PolynomialRing(QQ) sage: pol48 = x^6 - 4*x^4 + 12*x^2 - 12 sage: K.<a> = NumberField(pol48) sage: L.<b> = pol48.change_ring(K).splitting_field() sage: L Number Field in b with defining polynomial x^48 ... Try all Galois groups over `\QQ` in degree 5 except for `S_5` (the latter is infeasible with the current implementation):: sage: C5pol = x^5 + x^4 - 4*x^3 - 3*x^2 + 3*x + 1 sage: C5pol.splitting_field('x') Number Field in x with defining polynomial x^5 + x^4 - 4*x^3 - 3*x^2 + 3*x + 1 sage: D10pol = x^5 - x^4 - 5*x^3 + 4*x^2 + 3*x - 1 sage: D10pol.splitting_field('x') Number Field in x with defining polynomial x^10 - 28*x^8 + 216*x^6 - 681*x^4 + 902*x^2 - 401 sage: AGL_1_5pol = x^5 - 2 sage: AGL_1_5pol.splitting_field('x') Number Field in x with defining polynomial x^20 + 10*x^19 + 55*x^18 + 210*x^17 + 595*x^16 + 1300*x^15 + 2250*x^14 + 3130*x^13 + 3585*x^12 + 3500*x^11 + 2965*x^10 + 2250*x^9 + 1625*x^8 + 1150*x^7 + 750*x^6 + 400*x^5 + 275*x^4 + 100*x^3 + 75*x^2 + 25 sage: A5pol = x^5 - x^4 + 2*x^2 - 2*x + 2 sage: A5pol.splitting_field('x') Number Field in x with defining polynomial x^60 ... We can use the ``abort_degree`` option if we don't want to compute fields of too large degree (this can be used to check whether the splitting field has small degree):: sage: (x^5+x+3).splitting_field('b', abort_degree=119) Traceback (most recent call last): ... SplittingFieldAbort: degree of splitting field equals 120 sage: (x^10+x+3).splitting_field('b', abort_degree=60) # long time (10s on sage.math, 2014) Traceback (most recent call last): ... SplittingFieldAbort: degree of splitting field is a multiple of 180 Use the ``degree_divisor`` attribute to recover the divisor of the degree of the splitting field or ``degree_multiple`` to recover a multiple:: sage: from sage.rings.number_field.splitting_field import SplittingFieldAbort sage: try: # long time (4s on sage.math, 2014) ....: (x^8+x+1).splitting_field('b', abort_degree=60, simplify=False) ....: except SplittingFieldAbort as e: ....: print e.degree_divisor ....: print e.degree_multiple 120 1440 TESTS:: sage: from sage.rings.number_field.splitting_field import splitting_field sage: splitting_field(polygen(QQ), name='x', map=True, simplify_all=True) (Number Field in x with defining polynomial x, Ring morphism: From: Rational Field To: Number Field in x with defining polynomial x Defn: 1 |--> 1) """ from sage.misc.all import verbose, cputime degree_multiple = Integer(degree_multiple or 0) abort_degree = Integer(abort_degree or 0) # Kpol = PARI polynomial in y defining the extension found so far F = poly.base_ring() if is_RationalField(F): Kpol = pari("'y") else: Kpol = F.pari_polynomial("y") # Fgen = the generator of F as element of Q[y]/Kpol # (only needed if map=True) if map: Fgen = F.gen()._pari_() verbose("Starting field: %s" % Kpol) # L and Lred are lists of SplittingData. # L contains polynomials which are irreducible over K, # Lred contains polynomials which need to be factored. L = [] Lred = [SplittingData(poly._pari_with_name(), degree_multiple)] # Main loop, handle polynomials one by one while True: # Absolute degree of current field K absolute_degree = Integer(Kpol.poldegree()) # Compute minimum relative degree of splitting field rel_degree_divisor = Integer(1) for splitting in L: rel_degree_divisor = rel_degree_divisor.lcm(splitting.poldegree()) # Check for early aborts abort_rel_degree = abort_degree // absolute_degree if abort_rel_degree and rel_degree_divisor > abort_rel_degree: raise SplittingFieldAbort(absolute_degree * rel_degree_divisor, degree_multiple) # First, factor polynomials in Lred and store the result in L verbose("SplittingData to factor: %s" % [s._repr_tuple() for s in Lred]) t = cputime() for splitting in Lred: m = splitting.dm.gcd(degree_multiple).gcd( factorial(splitting.poldegree())) if m == 1: continue factors = Kpol.nffactor(splitting.pol)[0] for q in factors: d = q.poldegree() fac = factorial(d) # Multiple of the degree of the splitting field of q, # note that the degree equals fac iff the Galois group is S_n. mq = m.gcd(fac) if mq == 1: continue # Multiple of the degree of the splitting field of q # over the field defined by adding square root of the # discriminant. # If the Galois group is contained in A_n, then mq_alt is # also the degree multiple over the current field K. # Here, we have equality if the Galois group is A_n. mq_alt = mq.gcd(fac // 2) # If we are over Q, then use PARI's polgalois() to compute # these degrees exactly. if absolute_degree == 1: try: G = q.polgalois() except PariError: pass else: mq = Integer(G[0]) mq_alt = mq // 2 if (G[1] == -1) else mq # In degree 4, use the cubic resolvent to refine the # degree bounds. if d == 4 and mq >= 12: # mq equals 12 or 24 # Compute cubic resolvent a0, a1, a2, a3, a4 = (q / q.pollead()).Vecrev() assert a4 == 1 cubicpol = pari([ 4 * a0 * a2 - a1 * a1 - a0 * a3 * a3, a1 * a3 - 4 * a0, -a2, 1 ]).Polrev() cubicfactors = Kpol.nffactor(cubicpol)[0] if len(cubicfactors) == 1: # A4 or S4 # After adding a root of the cubic resolvent, # the degree of the extension defined by q # is a factor 3 smaller. L.append(SplittingData(cubicpol, 3)) rel_degree_divisor = rel_degree_divisor.lcm(3) mq = mq // 3 # 4 or 8 mq_alt = 4 elif len(cubicfactors) == 2: # C4 or D8 # The irreducible degree 2 factor is # equivalent to x^2 - q.poldisc(). discpol = cubicfactors[1] L.append(SplittingData(discpol, 2)) mq = mq_alt = 4 else: # C2 x C2 mq = mq_alt = 4 if mq > mq_alt >= 3: # Add quadratic resolvent x^2 - D to decrease # the degree multiple by a factor 2. discpol = pari([-q.poldisc(), 0, 1]).Polrev() discfactors = Kpol.nffactor(discpol)[0] if len(discfactors) == 1: # Discriminant is not a square L.append(SplittingData(discpol, 2)) rel_degree_divisor = rel_degree_divisor.lcm(2) mq = mq_alt L.append(SplittingData(q, mq)) rel_degree_divisor = rel_degree_divisor.lcm(q.poldegree()) if abort_rel_degree and rel_degree_divisor > abort_rel_degree: raise SplittingFieldAbort( absolute_degree * rel_degree_divisor, degree_multiple) verbose("Done factoring", t, level=2) if len(L) == 0: # Nothing left to do break # Recompute absolute degree multiple new_degree_multiple = absolute_degree for splitting in L: new_degree_multiple *= splitting.dm degree_multiple = new_degree_multiple.gcd(degree_multiple) # Absolute degree divisor degree_divisor = rel_degree_divisor * absolute_degree # Sort according to degree to handle low degrees first L.sort(key=lambda x: x.key()) verbose("SplittingData to handle: %s" % [s._repr_tuple() for s in L]) verbose("Bounds for absolute degree: [%s, %s]" % (degree_divisor, degree_multiple)) # Check consistency if degree_multiple % degree_divisor != 0: raise ValueError( "inconsistent degree_multiple in splitting_field()") for splitting in L: # The degree of the splitting field must be a multiple of # the degree of the polynomial. Only do this check for # SplittingData with minimal dm, because the higher dm are # defined as relative degree over the splitting field of # the polynomials with lesser dm. if splitting.dm > L[0].dm: break if splitting.dm % splitting.poldegree() != 0: raise ValueError( "inconsistent degree_multiple in splitting_field()") # Add a root of f = L[0] to construct the field N = K[x]/f(x) splitting = L[0] f = splitting.pol verbose("Handling polynomial %s" % (f.lift()), level=2) t = cputime() Npol, KtoN, k = Kpol.rnfequation(f, flag=1) # Make Npol monic integral primitive, store in Mpol # (after this, we don't need Npol anymore, only Mpol) Mdiv = pari(1) Mpol = Npol while True: denom = Integer(Mpol.pollead()) if denom == 1: break denom = pari(denom.factor().radical_value()) Mpol = (Mpol * (denom**Mpol.poldegree())).subst( "x", pari([0, 1 / denom]).Polrev("x")) Mpol /= Mpol.content() Mdiv *= denom # We are finished for sure if we hit the degree bound finished = (Mpol.poldegree() >= degree_multiple) if simplify_all or (simplify and not finished): # Find a simpler defining polynomial Lpol for Mpol verbose("New field before simplifying: %s" % Mpol, t) t = cputime() M = Mpol.polred(flag=3) n = len(M[0]) - 1 Lpol = M[1][n].change_variable_name("y") LtoM = M[0][n].change_variable_name("y").Mod( Mpol.change_variable_name("y")) MtoL = LtoM.modreverse() else: # Lpol = Mpol Lpol = Mpol.change_variable_name("y") MtoL = pari("'y") NtoL = MtoL / Mdiv KtoL = KtoN.lift().subst("x", NtoL).Mod(Lpol) Kpol = Lpol # New Kpol (for next iteration) verbose("New field: %s" % Kpol, t) if map: t = cputime() Fgen = Fgen.lift().subst("y", KtoL) verbose("Computed generator of F in K", t, level=2) if finished: break t = cputime() # Convert f and elements of L from K to L and store in L # (if the polynomial is certain to remain irreducible) or Lred. Lold = L[1:] L = [] Lred = [] # First add f divided by the linear factor we obtained, # mg is the new degree multiple. mg = splitting.dm // f.poldegree() if mg > 1: g = [c.subst("y", KtoL).Mod(Lpol) for c in f.Vecrev().lift()] g = pari(g).Polrev() g /= pari([k * KtoL - NtoL, 1]).Polrev() # divide linear factor Lred.append(SplittingData(g, mg)) for splitting in Lold: g = [c.subst("y", KtoL) for c in splitting.pol.Vecrev().lift()] g = pari(g).Polrev() mg = splitting.dm if Integer(g.poldegree()).gcd( f.poldegree()) == 1: # linearly disjoint fields L.append(SplittingData(g, mg)) else: Lred.append(SplittingData(g, mg)) verbose("Converted polynomials to new field", t, level=2) # Convert Kpol to Sage and construct the absolute number field Kpol = PolynomialRing(RationalField(), name=poly.variable_name())(Kpol / Kpol.pollead()) K = NumberField(Kpol, name) if map: return K, F.hom(Fgen, K) else: return K
def f(n): if n == 0: return 0 else: return 1/factorial(n)
def tuple_orbit_reps(self, k, prefix=None): if prefix is None: prefix = [] s = len(prefix) tp = tuple(prefix) if s > k: raise ValueError if k == 0: return 1, {(): 1} gens = self._graph.automorphism_group_gens() # Pass generators to GAP to create a group for us. gen_str = ",".join("(" + "".join(str(cy) for cy in cys) + ")" for cys in gens) gap.eval("g := Group(%s);" % gen_str) if len(prefix) > 0: gap.eval("g := Stabilizer(g, %s, OnTuples);" % list(set(prefix))) S = [] for i in range(1, k - s + 1): S.extend( [tuple(sorted(list(x))) for x in Subsets(self._graph.n, i)]) set_orb_reps = {} #sys.stdout.write("Calculating orbits") while len(S) > 0: rep = list(S[0]) o = gap.new("Orbit(g, %s, OnSets);" % (rep, )).sage() o = list(set([tuple(sorted(t)) for t in o])) ot = o[0] set_orb_reps[ot] = len(o) for t in o: S.remove(t) #sys.stdout.write(".") #sys.stdout.flush() #sys.stdout.write("\n") combs = [tuple(c) for c in Compositions(k - s)] factors = [] for c in combs: factor = factorial(k - s) for x in c: factor /= factorial(x) factors.append(factor) orb_reps = {} total = 0 for ot, length in set_orb_reps.iteritems(): ne = len(ot) for ci in range(len(combs)): c = combs[ci] if len(c) == ne: t = tp for i in range(ne): t += c[i] * (ot[i], ) weight = factors[ci] * length orb_reps[t] = weight total += weight return total, orb_reps
def coeffs(self,n): if n==0: return 0 return sum([a0[k]*log(ev[k])**n for k in xrange(N)])/factorial(n)
def by_taylor_expansion(self, fs, k, is_integral=False): r""" We combine the theta decomposition and the heat operator as in the thesis of Nils Skoruppa. This yields a bijections of the space of weak Jacobi forms of weight `k` and index `m` with the product of spaces of elliptic modular forms `M_k \times S_{k+2} \times .. \times S_{k+2m}`. INPUT: - ``fs`` -- A list of functions that given an integer `p` return the q-expansion of a modular form with rational coefficients up to precision `p`. These modular forms correspond to the components of the above product. - `k` -- An integer. The weight of the weak Jacobi form to be computed. - ``is_integral`` -- A boolean. If ``True``, the ``fs`` have integral coefficients. TESTS:: sage: from psage.modform.jacobiforms.jacobiformd1nn_fegenerators import * sage: from psage.modform.jacobiforms.jacobiformd1nn_fourierexpansion import * sage: prec = JacobiFormD1NNFilter(10, 3) sage: factory = JacobiFormD1NNFactory(prec) sage: R.<q> = ZZ[[]] sage: expansion = factory.by_taylor_expansion([lambda p: 0 + O(q^p), lambda p: CuspForms(1, 12).gen(0).qexp(p)], 9, True) sage: exp_gcd = gcd(expansion.values()) sage: sorted([ (12 * n - r**2, c/exp_gcd) for ((n, r), c) in expansion.iteritems()]) [(-4, 0), (-1, 0), (8, 1), (11, -2), (20, -14), (23, 32), (32, 72), (35, -210), (44, -112), (47, 672), (56, -378), (59, -728), (68, 1736), (71, -1856), (80, -1008), (83, 6902), (92, -6400), (95, -5792), (104, 10738), (107, -6564)] """ if is_integral: PS = self.integral_power_series_ring() else: PS = self.power_series_ring() if (k % 2 == 0 and not len(fs) == self.jacobi_index() + 1) \ or (k % 2 != 0 and not len(fs) == self.jacobi_index() - 1) : raise ValueError( "fs (which has length {0}) must be a list of {1} Fourier expansions" \ .format(len(fs), self.jacobi_index() + 1 if k % 2 == 0 else self.jacobi_index() - 1) ) qexp_prec = self._qexp_precision() if qexp_prec is None: # there are no Fourier indices below the precision return dict() f_divs = dict() for (i, f) in enumerate(fs): f_divs[(i, 0)] = PS(f(qexp_prec), qexp_prec + 10) ## a special implementation of the case m = 1, which is important when computing Siegel modular forms. ## TODO: Fix _by_taylor_expansion_m1 if False and self.jacobi_index() == 1 and k % 2 == 0: return self._by_taylor_expansion_m1(f_divs, k, is_integral) m = self.jacobi_index() for i in (xrange(m + 1) if k % 2 == 0 else xrange(m - 1)): for j in xrange(1, m - i + 1): f_divs[(i, j)] = f_divs[(i, j - 1)].derivative().shift(1) phi_divs = list() for i in (xrange(m + 1) if k % 2 == 0 else xrange(m - 1)): if k % 2 == 0: ## This is (13) on page 131 of Skoruppa (change of variables n -> i, r -> j). ## The additional factor (2m + k - 1)! is a renormalization to make coefficients integral. ## The additional factor (4m)^i stems from the fact that we have used d / d\tau instead of ## d^2 / dz^2 when treating the theta series. Since these are annihilated by the heat operator ## the additional factor compensates for this. phi_divs.append( sum(f_divs[(j, i - j)] * ( (4 * self.jacobi_index())**i * binomial(i, j) / 2**i # 2**(self.__precision.jacobi_index() - i + 1) * prod(2 * l + 1 for l in xrange(i)) / factorial(i + k + j - 1) * factorial(2 * self.jacobi_index() + k - 1)) for j in range(i + 1))) else: phi_divs.append( sum(f_divs[(j, i - j)] * ( (4 * self.jacobi_index())**i * binomial(i, j) / 2** (i + 1) # 2**(self.__precision.jacobi_index() - i + 1) * prod(2 * l + 1 for l in xrange(i + 1)) / factorial(i + k + j) * factorial(2 * self.jacobi_index() + k - 1)) for j in range(i + 1))) phi_coeffs = dict() for r in (xrange(m + 1) if k % 2 == 0 else xrange(1, m)): if k % 2 == 0: series = sum( map(operator.mul, self._wronskian_adjoint(k)[r], phi_divs)) else: series = sum( map(operator.mul, self._wronskian_adjoint(k)[r - 1], phi_divs)) series = self._wronskian_invdeterminant(k) * series for n in xrange(qexp_prec): phi_coeffs[(n, r)] = series[n] return phi_coeffs
def __init__(self,b,N,iprec,x0=0): self.bsym = b self.N = N self.iprec = iprec self.x0sym = x0 self.prec = None bname = repr(b).strip('0').replace('.',',') if b == sqrt(2): bname = "sqrt2" if b == e**(1/e): bname = "eta" x0name = repr(x0) if x0name.find('.') > -1: if x0.is_real(): x0name = repr(float(real(x0))).strip('0').replace('.',',') else: x0name = repr(complex(x0)).strip('0').replace('.',',') # by some reason save does not work with additional . inside the path self.path = "savings/msexp_%s"%bname + "_N%04d"%N + "_iprec%05d"%iprec + "_a%s"%x0name b = b.n(iprec) self.b = b x0 = x0.n(iprec) self.x0 = x0 if isinstance(x0,RealNumber): R = RealField(iprec) else: R = ComplexField(iprec) #symbolic carleman matrix if x0 == 0: #C = Matrix([[ m**n*log(b)**n/factorial(n) for n in range(N)] for m in range(N)]) coeffs = [log(b)**n/factorial(n) for n in xrange(N)] else: #too slow #c = b**x0 #C = Matrix([ [log(b)**n/factorial(n)*sum([binomial(m,k)*k**n*c**k*(-x0)**(m-k) for k in range(m+1)]) for n in range(N)] for m in range(N)]) coeffs = [b**x0-x0]+[b**x0*log(b)**n/factorial(n) for n in xrange(1,N)] def psmul(A,B): N = len(B) return [sum([A[k]*B[n-k] for k in xrange(n+1)]) for n in xrange(N)] C = Matrix(R,N) row = vector(R,[1]+(N-1)*[0]) C[0] = row for m in xrange(1,N): row = psmul(row,coeffs) C[m] = row print "Carleman matrix created." #numeric matrix and eigenvalues #self.CM = C.n(iprec) #n seems to reduce to a RealField self.CM = C self.eigenvalues = self.CM.eigenvalues() print "Eigenvalues computed." self.IM = None self.calc_IM() print "Iteration matrix computed." self.coeffs_1 = self.IM * vector([1]+[(1-x0)**n for n in range(1,N)]) if x0 == 0: self.coeffs_0 = self.IM.column(0) else: self.coeffs_0 = self.IM * vector([1]+[(-x0)**n for n in range(1,N)]) #there would also be a method to only coeffs_0 with x0, #this would require to make the offset -1-slog(0) self.L = None
def _closed_form(hyp): a, b, z = hyp.operands() a, b = a.operands(), b.operands() p, q = len(a), len(b) if z == 0: return Integer(1) if p == q == 0: return exp(z) if p == 1 and q == 0: return (1 - z) ** (-a[0]) if p == 0 and q == 1: # TODO: make this require only linear time def _0f1(b, z): F12 = cosh(2 * sqrt(z)) F32 = sinh(2 * sqrt(z)) / (2 * sqrt(z)) if 2 * b == 1: return F12 if 2 * b == 3: return F32 if 2 * b > 3: return ((b - 2) * (b - 1) / z * (_0f1(b - 2, z) - _0f1(b - 1, z))) if 2 * b < 1: return (_0f1(b + 1, z) + z / (b * (b + 1)) * _0f1(b + 2, z)) raise ValueError # Can evaluate 0F1 in terms of elementary functions when # the parameter is a half-integer if 2 * b[0] in ZZ and b[0] not in ZZ: return _0f1(b[0], z) # Confluent hypergeometric function if p == 1 and q == 1: aa, bb = a[0], b[0] if aa * 2 == 1 and bb * 2 == 3: t = sqrt(-z) return sqrt(pi) / 2 * erf(t) / t if a == 1 and b == 2: return (exp(z) - 1) / z n, m = aa, bb if n in ZZ and m in ZZ and m > 0 and n > 0: rf = rising_factorial if m <= n: return (exp(z) * sum(rf(m - n, k) * (-z) ** k / factorial(k) / rf(m, k) for k in xrange(n - m + 1))) else: T = sum(rf(n - m + 1, k) * z ** k / (factorial(k) * rf(2 - m, k)) for k in xrange(m - n)) U = sum(rf(1 - n, k) * (-z) ** k / (factorial(k) * rf(2 - m, k)) for k in xrange(n)) return (factorial(m - 2) * rf(1 - m, n) * z ** (1 - m) / factorial(n - 1) * (T - exp(z) * U)) if p == 2 and q == 1: R12 = QQ('1/2') R32 = QQ('3/2') def _2f1(a, b, c, z): """ Evaluation of 2F1(a, b, c, z), assuming a, b, c positive integers or half-integers """ if b == c: return (1 - z) ** (-a) if a == c: return (1 - z) ** (-b) if a == 0 or b == 0: return Integer(1) if a > b: a, b = b, a if b >= 2: F1 = _2f1(a, b - 1, c, z) F2 = _2f1(a, b - 2, c, z) q = (b - 1) * (z - 1) return (((c - 2 * b + 2 + (b - a - 1) * z) * F1 + (b - c - 1) * F2) / q) if c > 2: # how to handle this case? if a - c + 1 == 0 or b - c + 1 == 0: raise NotImplementedError F1 = _2f1(a, b, c - 1, z) F2 = _2f1(a, b, c - 2, z) r1 = (c - 1) * (2 - c - (a + b - 2 * c + 3) * z) r2 = (c - 1) * (c - 2) * (1 - z) q = (a - c + 1) * (b - c + 1) * z return (r1 * F1 + r2 * F2) / q if (a, b, c) == (R12, 1, 2): return (2 - 2 * sqrt(1 - z)) / z if (a, b, c) == (1, 1, 2): return -log(1 - z) / z if (a, b, c) == (1, R32, R12): return (1 + z) / (1 - z) ** 2 if (a, b, c) == (1, R32, 2): return 2 * (1 / sqrt(1 - z) - 1) / z if (a, b, c) == (R32, 2, R12): return (1 + 3 * z) / (1 - z) ** 3 if (a, b, c) == (R32, 2, 1): return (2 + z) / (2 * (sqrt(1 - z) * (1 - z) ** 2)) if (a, b, c) == (2, 2, 1): return (1 + z) / (1 - z) ** 3 raise NotImplementedError aa, bb = a cc, = b if z == 1: return (gamma(cc) * gamma(cc - aa - bb) / gamma(cc - aa) / gamma(cc - bb)) if ((aa * 2) in ZZ and (bb * 2) in ZZ and (cc * 2) in ZZ and aa > 0 and bb > 0 and cc > 0): try: return _2f1(aa, bb, cc, z) except NotImplementedError: pass return hyp
def gamma__exact(n): """ Evaluates the exact value of the `\Gamma` function at an integer or half-integer argument. EXAMPLES:: sage: gamma__exact(4) 6 sage: gamma__exact(3) 2 sage: gamma__exact(2) 1 sage: gamma__exact(1) 1 sage: gamma__exact(1/2) sqrt(pi) sage: gamma__exact(3/2) 1/2*sqrt(pi) sage: gamma__exact(5/2) 3/4*sqrt(pi) sage: gamma__exact(7/2) 15/8*sqrt(pi) sage: gamma__exact(-1/2) -2*sqrt(pi) sage: gamma__exact(-3/2) 4/3*sqrt(pi) sage: gamma__exact(-5/2) -8/15*sqrt(pi) sage: gamma__exact(-7/2) 16/105*sqrt(pi) TESTS:: sage: gamma__exact(1/3) Traceback (most recent call last): ... TypeError: you must give an integer or half-integer argument """ from sage.all import sqrt # SANITY CHECK if (not n in QQ) or (denominator(n) > 2): raise TypeError("you must give an integer or half-integer argument") if denominator(n) == 1: if n <= 0: return infinity if n > 0: return factorial(n - 1) else: ans = QQ(1) while (n != QQ(1) / 2): if n < 0: ans *= QQ(1) / n n += 1 elif n > 0: n += -1 ans *= n ans *= sqrt(pi) return ans
def Exp(self): return PowerSeriesI(lambda n: 1/factorial(n))