def paintCSNew(width, height, xMax, yMax, xfactor, yfactor, ticlength, xMin=5, yMin=1, xoffset=1, dashedx=5, dashedy=5): # x-axis xmlText = ("<line x1='0' y1='" + str(height) + "' x2='" + str(width) + "' y2='" + str(height) + "' style='stroke:rgb(0,0,0);'/>\n") xsign = 1 if xMax >= 0 else -1 ysign = 1 if yMax >= 0 else -1 for i in srange(xMin, xMax, xsign * dashedx): xmlText = xmlText + ("<text x='" + str(i * xsign * xfactor - 6) + "' y='" + str(xsign * height - 2 * ticlength) + "' style='fill:rgb(102,102,102);font-size:11px;'>" + "{:.5g}".format(i + xoffset) + "</text>\n") xmlText = xmlText + ( "<line y1='0' x1='" + str(i * xsign * xfactor) + "' y2='" + str(ysign * height) + "' x2='" + str(i * xsign * xfactor) + "' style='stroke:rgb(204,204,204);stroke-dasharray:3,3;'/>\n") for i in srange(xMin, xMax, xsign * dashedx): xmlText = xmlText + ("<line x1='" + str(i * xsign * xfactor) + "' y1='" + str(ysign * height - ticlength) + "' x2='" + str(i * xfactor) + "' y2='" + str(ysign * height) + "' style='stroke:rgb(0,0,0);'/>\n") # y-axis xmlText += "<line x1='0' y1='%d' x2='0' y2='0' style='stroke:rgb(0,0,0);'/>\n" % height for i in srange(yMin, yMax + 1, ysign * dashedy): xmlText = xmlText + ("<text x='-10' y='" + str(ysign * height - i * ysign * yfactor + 3) + "' style='fill:rgb(102,102,102);font-size:11px;'>" + "{:.5g}".format(float(i)) + "</text>\n") xmlText = xmlText + ( "<line x1='0' y1='" + str(height - i * ysign * yfactor) + "' x2='" + str(xsign * width) + "' y2='" + str(height - i * ysign * yfactor) + "' style='stroke:rgb(204,204,204);stroke-dasharray:3,3;'/>\n") for i in srange(yMin, yMax + 1, ysign * dashedy): xmlText = xmlText + ("<line x1='0' y1='" + str(height - i * ysign * yfactor) + "' x2='" + str(ticlength) + "' y2='" + str(height - i * ysign * yfactor) + "' style='stroke:rgb(0,0,0);'/>\n") return (xmlText)
def eisenstein_series_at_inf(phi, psi, k, prec=10, t=1, base_ring=None): r""" Return Fourier expansion of Eistenstein series at a cusp. INPUT: - ``phi`` -- Dirichlet character. - ``psi`` -- Dirichlet character. - ``k`` -- integer, the weight of the Eistenstein series. - ``prec`` -- integer (default: 10). - ``t`` -- integer (default: 1). OUTPUT: The Fourier expansion of the Eisenstein series $E_k^{\phi,\psi, t}$ (as defined by [Diamond-Shurman]) at the specific cusp. EXAMPLES: sage: phi = DirichletGroup(3)[1] sage: psi = DirichletGroup(5)[1] sage: E = eisenstein_series_at_inf(phi, psi, 4) """ N1, N2 = phi.level(), psi.level() N = N1 * N2 #The Fourier expansion of the Eisenstein series at infinity is in the field Q(zeta_Ncyc) Ncyc = lcm([euler_phi(N1), euler_phi(N2)]) if base_ring == None: base_ring = CyclotomicField(Ncyc) Q = PowerSeriesRing(base_ring, 'q') q = Q.gen() s = O(q**prec) #Weight 2 with trivial characters is calculated separately if k == 2 and phi.conductor() == 1 and psi.conductor() == 1: if t == 1: raise TypeError('E_2 is not a modular form.') s = 1 / 24 * (t - 1) for m in srange(1, prec): for n in srange(1, prec / m): s += n * (q**(m * n) - t * q**(m * n * t)) return s + O(q**prec) if psi.level() == 1 and k == 1: s -= phi.bernoulli(k) / k elif phi.level() == 1: s -= psi.bernoulli(k) / k for m in srange(1, prec / t): for n in srange(1, prec / t / m + 1): s += 2 * base_ring(phi(m)) * base_ring( psi(n)) * n**(k - 1) * q**(m * n * t) return s + O(q**prec)
def QuadraticResidueCodeOddPair(n, F): """ Quadratic residue codes of a given odd prime length and base ring either don't exist at all or occur as 4-tuples - a pair of "odd-like" codes and a pair of "even-like" codes. If n 2 is prime then (Theorem 6.6.2 in [HP2003]_) a QR code exists over GF(q) iff q is a quadratic residue mod n. They are constructed as "odd-like" duadic codes associated the splitting (Q,N) mod n, where Q is the set of non-zero quadratic residues and N is the non-residues. EXAMPLES:: sage: codes.QuadraticResidueCodeOddPair(17, GF(13)) # known bug (#25896) ([17, 9] Cyclic Code over GF(13), [17, 9] Cyclic Code over GF(13)) sage: codes.QuadraticResidueCodeOddPair(17, GF(2)) ([17, 9] Cyclic Code over GF(2), [17, 9] Cyclic Code over GF(2)) sage: codes.QuadraticResidueCodeOddPair(13, GF(9,"z")) # known bug (#25896) ([13, 7] Cyclic Code over GF(9), [13, 7] Cyclic Code over GF(9)) sage: C1 = codes.QuadraticResidueCodeOddPair(17, GF(2))[1] sage: C1x = C1.extended_code() sage: C2 = codes.QuadraticResidueCodeOddPair(17, GF(2))[0] sage: C2x = C2.extended_code() sage: C2x.spectrum(); C1x.spectrum() [1, 0, 0, 0, 0, 0, 102, 0, 153, 0, 153, 0, 102, 0, 0, 0, 0, 0, 1] [1, 0, 0, 0, 0, 0, 102, 0, 153, 0, 153, 0, 102, 0, 0, 0, 0, 0, 1] sage: C3 = codes.QuadraticResidueCodeOddPair(7, GF(2))[0] sage: C3x = C3.extended_code() sage: C3x.spectrum() [1, 0, 0, 0, 14, 0, 0, 0, 1] This is consistent with Theorem 6.6.14 in [HP2003]_. TESTS:: sage: codes.QuadraticResidueCodeOddPair(9,GF(2)) Traceback (most recent call last): ... ValueError: the argument n must be an odd prime """ from sage.arith.srange import srange from sage.categories.finite_fields import FiniteFields if F not in FiniteFields(): raise ValueError("the argument F must be a finite field") q = F.order() n = Integer(n) if n <= 2 or not n.is_prime(): raise ValueError("the argument n must be an odd prime") Q = quadratic_residues(n) Q.remove(0) # non-zero quad residues N = [x for x in srange(1, n) if x not in Q] # non-zero quad non-residues if q not in Q: raise ValueError( "the order of the finite field must be a quadratic residue modulo n" ) return DuadicCodeOddPair(F, Q, N)
def QuadraticResidueCodeOddPair(n, F): """ Quadratic residue codes of a given odd prime length and base ring either don't exist at all or occur as 4-tuples - a pair of "odd-like" codes and a pair of "even-like" codes. If n 2 is prime then (Theorem 6.6.2 in [HP]_) a QR code exists over GF(q) iff q is a quadratic residue mod n. They are constructed as "odd-like" duadic codes associated the splitting (Q,N) mod n, where Q is the set of non-zero quadratic residues and N is the non-residues. EXAMPLES:: sage: codes.QuadraticResidueCodeOddPair(17,GF(13)) (Linear code of length 17, dimension 9 over Finite Field of size 13, Linear code of length 17, dimension 9 over Finite Field of size 13) sage: codes.QuadraticResidueCodeOddPair(17,GF(2)) (Linear code of length 17, dimension 9 over Finite Field of size 2, Linear code of length 17, dimension 9 over Finite Field of size 2) sage: codes.QuadraticResidueCodeOddPair(13,GF(9,"z")) (Linear code of length 13, dimension 7 over Finite Field in z of size 3^2, Linear code of length 13, dimension 7 over Finite Field in z of size 3^2) sage: C1 = codes.QuadraticResidueCodeOddPair(17,GF(2))[1] sage: C1x = C1.extended_code() sage: C2 = codes.QuadraticResidueCodeOddPair(17,GF(2))[0] sage: C2x = C2.extended_code() sage: C2x.spectrum(); C1x.spectrum() [1, 0, 0, 0, 0, 0, 102, 0, 153, 0, 153, 0, 102, 0, 0, 0, 0, 0, 1] [1, 0, 0, 0, 0, 0, 102, 0, 153, 0, 153, 0, 102, 0, 0, 0, 0, 0, 1] sage: C3 = codes.QuadraticResidueCodeOddPair(7,GF(2))[0] sage: C3x = C3.extended_code() sage: C3x.spectrum() [1, 0, 0, 0, 14, 0, 0, 0, 1] This is consistent with Theorem 6.6.14 in [HP]_. TESTS:: sage: codes.QuadraticResidueCodeOddPair(9,GF(2)) Traceback (most recent call last): ... ValueError: the argument n must be an odd prime """ from sage.arith.srange import srange from sage.categories.finite_fields import FiniteFields if F not in FiniteFields(): raise ValueError("the argument F must be a finite field") q = F.order() n = Integer(n) if n <= 2 or not n.is_prime(): raise ValueError("the argument n must be an odd prime") Q = quadratic_residues(n) Q.remove(0) # non-zero quad residues N = [x for x in srange(1, n) if x not in Q] # non-zero quad non-residues if q not in Q: raise ValueError("the order of the finite field must be a quadratic residue modulo n") return DuadicCodeOddPair(F, Q, N)
def plot_fft(self, npoints=None, channel=0, half=True, **kwds): v = self.vector(npoints=npoints) w = v.fft() if half: w = w[:len(w) // 2] z = [abs(x) for x in w] if half: r = math.pi else: r = 2 * math.pi data = zip(srange(0, r, r / len(z)), z) L = list_plot(data, plotjoined=True, **kwds) L.xmin(0) L.xmax(r) return L
def plot_fft(self, npoints=None, channel=0, half=True, **kwds): v = self.vector(npoints=npoints) w = v.fft() if half: w = w[:len(w)//2] z = [abs(x) for x in w] if half: r = math.pi else: r = 2*math.pi data = zip(srange(0, r, r/len(z)), z) L = list_plot(data, plotjoined=True, **kwds) L.xmin(0) L.xmax(r) return L
def _log_StirlingNegativePowers_(var, precision): r""" Helper function to calculate the logarithm of Stirling's approximation formula from the negative powers of ``var`` on, i.e., it skips the summands `n \log n - n + (\log n)/2 + \log(2\pi)/2`. INPUT: - ``var`` -- a string for the variable name. - ``precision`` -- an integer specifying the number of exact summands. If this is negative, then the result is `0`. OUTPUT: An asymptotic expansion. TESTS:: sage: asymptotic_expansions._log_StirlingNegativePowers_( ....: 'm', precision=-1) 0 sage: asymptotic_expansions._log_StirlingNegativePowers_( ....: 'm', precision=0) O(m^(-1)) sage: asymptotic_expansions._log_StirlingNegativePowers_( ....: 'm', precision=3) 1/12*m^(-1) - 1/360*m^(-3) + 1/1260*m^(-5) + O(m^(-7)) sage: _.parent() Asymptotic Ring <m^ZZ> over Rational Field """ from asymptotic_ring import AsymptoticRing from sage.rings.rational_field import QQ A = AsymptoticRing(growth_group='{n}^ZZ'.format(n=var), coefficient_ring=QQ) if precision < 0: return A.zero() n = A.gen() from sage.arith.all import bernoulli from sage.arith.srange import srange result = sum((bernoulli(k) / k / (k-1) / n**(k-1) for k in srange(2, 2*precision + 2, 2)), A.zero()) return result + (1 / n**(2*precision + 1)).O()
def _log_StirlingNegativePowers_(var, precision): r""" Helper function to calculate the logarithm of Stirling's approximation formula from the negative powers of ``var`` on, i.e., it skips the summands `n \log n - n + (\log n)/2 + \log(2\pi)/2`. INPUT: - ``var`` -- a string for the variable name. - ``precision`` -- an integer specifying the number of exact summands. If this is negative, then the result is `0`. OUTPUT: An asymptotic expansion. TESTS:: sage: asymptotic_expansions._log_StirlingNegativePowers_( ....: 'm', precision=-1) 0 sage: asymptotic_expansions._log_StirlingNegativePowers_( ....: 'm', precision=0) O(m^(-1)) sage: asymptotic_expansions._log_StirlingNegativePowers_( ....: 'm', precision=3) 1/12*m^(-1) - 1/360*m^(-3) + 1/1260*m^(-5) + O(m^(-7)) sage: _.parent() Asymptotic Ring <m^ZZ> over Rational Field """ from asymptotic_ring import AsymptoticRing from sage.rings.rational_field import QQ A = AsymptoticRing(growth_group='{n}^ZZ'.format(n=var), coefficient_ring=QQ) if precision < 0: return A.zero() n = A.gen() from sage.arith.all import bernoulli from sage.arith.srange import srange result = sum((bernoulli(k) / k / (k - 1) / n**(k - 1) for k in srange(2, 2 * precision + 2, 2)), A.zero()) return result + (1 / n**(2 * precision + 1)).O()
def __old_make_values_list(vmin, vmax, step_size): """ This code is from slider_generic.__init__. This code requires sage mode to be checked. """ from sage.arith.srange import srange if isinstance(vmin, list): vals = vmin else: if vmax is None: vmax = vmin vmin = 0 #Compute step size; vmin and vmax are both defined here #500 is the length of the slider (in px) if step_size is None: step_size = (vmax - vmin) / 499.0 elif step_size <= 0: raise ValueError( "invalid negative step size -- step size must be positive") #Compute list of values num_steps = int(math.ceil((vmax - vmin) / float(step_size))) if num_steps <= 1: vals = [vmin, vmax] else: vals = srange(vmin, vmax, step_size, include_endpoint=True) if vals[-1] != vmax: try: if vals[-1] > vmax: vals[-1] = vmax else: vals.append(vmax) except (ValueError, TypeError): pass #If the list of values is small, use the whole list. #Otherwise, use evenly spaced values in the list. if len(vals) == 0: return_values = [0] elif (len(vals) <= 500): return_values = vals else: vlen = (len(vals) - 1) / 499.0 return_values = [vals[(int)(i * vlen)] for i in range(500)] return return_values
def __old_make_values_list(vmin, vmax, step_size): """ This code is from slider_generic.__init__. This code requires sage mode to be checked. """ from sage.arith.srange import srange if isinstance(vmin, list): vals=vmin else: if vmax is None: vmax=vmin vmin=0 #Compute step size; vmin and vmax are both defined here #500 is the length of the slider (in px) if step_size is None: step_size = (vmax-vmin)/499.0 elif step_size <= 0: raise ValueError, "invalid negative step size -- step size must be positive" #Compute list of values num_steps = int(math.ceil((vmax-vmin)/float(step_size))) if num_steps <= 1: vals = [vmin, vmax] else: vals = srange(vmin, vmax, step_size, include_endpoint=True) if vals[-1] != vmax: try: if vals[-1] > vmax: vals[-1] = vmax else: vals.append(vmax) except (ValueError, TypeError): pass #If the list of values is small, use the whole list. #Otherwise, use evenly spaced values in the list. if len(vals) == 0: return_values = [0] elif(len(vals)<=500): return_values = vals else: vlen = (len(vals)-1)/499.0 return_values = [vals[(int)(i*vlen)] for i in range(500)] return return_values
def boolean_cayley_graph(dim, f): r""" Construct the Cayley graph of a Boolean function. Given the non-negative integer ``dim`` and the function ``f``, a Boolean function that takes a non-negative integer argument, the function ``Boolean_Cayley_graph`` constructs the Cayley graph of ``f`` as a Boolean function on :math:`\mathbb{F}_2^{dim}`, with the lexicographica ordering. The value ``f(0)`` is assumed to be ``0``, so the graph is always simple. INPUT: - ``dim`` -- integer. The Boolean dimension of the given function. - ``f`` -- function. A Boolean function expressed as a Python function taking non-negative integer arguments. OUTPUT: A ``Graph`` object representing the Cayley graph of ``f``. .. SEEALSO: :module:`sage.graphs.graph` EXAMPLES: The Cayley graph of the function ``f`` where :math:`f(n) = n \mod 2`. :: sage: from boolean_cayley_graphs.boolean_cayley_graph import boolean_cayley_graph sage: f = lambda n: n % 2 sage: g = boolean_cayley_graph(2, f) sage: g.adjacency_matrix() [0 1 0 1] [1 0 1 0] [0 1 0 1] [1 0 1 0] """ return Graph([srange(2 ** dim), lambda i, j: f(i ^ j)], format="rule", immutable=True)
def slider(vmin, vmax=None, step_size=None, default=None, label=None, display_value=True, _range=False): """ A slider widget. INPUT: For a numeric slider (select a value from a range): - ``vmin``, ``vmax`` -- minimum and maximum value - ``step_size`` -- the step size For a selection slider (select a value from a list of values): - ``vmin`` -- a list of possible values for the slider For all sliders: - ``default`` -- initial value - ``label`` -- optional label - ``display_value`` -- (boolean) if ``True``, display the current value. EXAMPLES:: sage: from sage.repl.ipython_kernel.all_jupyter import slider sage: slider(5, label="slide me") TransformIntSlider(value=5, description=u'slide me', min=5) sage: slider(5, 20) TransformIntSlider(value=5, max=20, min=5) sage: slider(5, 20, 0.5) TransformFloatSlider(value=5.0, max=20.0, min=5.0, step=0.5) sage: slider(5, 20, default=12) TransformIntSlider(value=12, max=20, min=5) The parent of the inputs determines the parent of the value:: sage: w = slider(5); w TransformIntSlider(value=5, min=5) sage: parent(w.get_interact_value()) Integer Ring sage: w = slider(int(5)); w IntSlider(value=5, min=5) sage: parent(w.get_interact_value()) <... 'int'> sage: w = slider(5, 20, step_size=RDF("0.1")); w TransformFloatSlider(value=5.0, max=20.0, min=5.0) sage: parent(w.get_interact_value()) Real Double Field sage: w = slider(5, 20, step_size=10/3); w SelectionSlider(index=2, options=(5, 25/3, 35/3, 15, 55/3), value=35/3) sage: parent(w.get_interact_value()) Rational Field Symbolic input is evaluated numerically:: sage: w = slider(e, pi); w TransformFloatSlider(value=2.718281828459045, max=3.141592653589793, min=2.718281828459045) sage: parent(w.get_interact_value()) Real Field with 53 bits of precision For a selection slider, the default is adjusted to one of the possible values:: sage: slider(range(10), default=17/10) SelectionSlider(index=2, options=(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), value=2) TESTS:: sage: slider(range(5), range(5)) Traceback (most recent call last): ... TypeError: unexpected argument 'vmax' for a selection slider sage: slider(range(5), step_size=2) Traceback (most recent call last): ... TypeError: unexpected argument 'step_size' for a selection slider sage: slider(5).readout True sage: slider(5, display_value=False).readout False """ kwds = {"readout": display_value} if label: kwds["description"] = u(label) # If vmin is iterable, return a SelectionSlider if isinstance(vmin, Iterable): if vmax is not None: raise TypeError("unexpected argument 'vmax' for a selection slider") if step_size is not None: raise TypeError("unexpected argument 'step_size' for a selection slider") if _range: # https://github.com/ipython/ipywidgets/issues/760 raise NotImplementedError("range_slider does not support a list of values") options = list(vmin) # Find default in options def err(v): if v is default: return (-1, 0) try: if v == default: return (0, 0) return (0, abs(v - default)) except Exception: return (1, 0) kwds["options"] = options if default is not None: kwds["value"] = min(options, key=err) return SelectionSlider(**kwds) if default is not None: kwds["value"] = default # Sum all input numbers to figure out type/parent p = parent(sum(x for x in (vmin, vmax, step_size) if x is not None)) # Change SR to RR if p is SR: p = RR # Convert all inputs to the common parent if vmin is not None: vmin = p(vmin) if vmax is not None: vmax = p(vmax) if step_size is not None: step_size = p(step_size) def tuple_elements_p(t): "Convert all entries of the tuple `t` to `p`" return tuple(p(x) for x in t) zero = p() if isinstance(zero, Integral): if p is int: if _range: cls = IntRangeSlider else: cls = IntSlider else: if _range: kwds["transform"] = tuple_elements_p cls = TransformIntRangeSlider else: kwds["transform"] = p cls = TransformIntSlider elif isinstance(zero, Rational): # Rational => implement as SelectionSlider if _range: # https://github.com/ipython/ipywidgets/issues/760 raise NotImplementedError("range_slider does not support rational numbers") vmin, vmax, value = _get_min_max_value(vmin, vmax, default, step_size) kwds["value"] = value kwds["options"] = srange(vmin, vmax, step_size, include_endpoint=True) return SelectionSlider(**kwds) elif isinstance(zero, Real): if p is float: if _range: cls = FloatRangeSlider else: cls = FloatSlider else: if _range: kwds["transform"] = tuple_elements_p cls = TransformFloatRangeSlider else: kwds["transform"] = p cls = TransformFloatSlider else: raise TypeError("unknown parent {!r} for slider".format(p)) kwds["min"] = vmin if vmax is not None: kwds["max"] = vmax if step_size is not None: kwds["step"] = step_size return cls(**kwds)
def ruler(start, end, ticks=4, sub_ticks=4, absolute=False, snap=False, **kwds): """ Draw a ruler in 3-D, with major and minor ticks. INPUT: - ``start`` -- the beginning of the ruler, as a list, tuple, or vector. - ``end`` -- the end of the ruler, as a list, tuple, or vector. - ``ticks`` -- (default: 4) the number of major ticks shown on the ruler. - ``sub_ticks`` -- (default: 4) the number of shown subdivisions between each major tick. - ``absolute`` -- (default: ``False``) if ``True``, makes a huge ruler in the direction of an axis. - ``snap`` -- (default: ``False``) if ``True``, snaps to an implied grid. Type ``line3d.options`` for a dictionary of the default options for lines, which are also available. EXAMPLES: A ruler:: sage: from sage.plot.plot3d.shapes2 import ruler sage: R = ruler([1,2,3],vector([2,3,4])); R Graphics3d Object A ruler with some options:: sage: R = ruler([1,2,3],vector([2,3,4]),ticks=6, sub_ticks=2, color='red'); R Graphics3d Object The keyword ``snap`` makes the ticks not necessarily coincide with the ruler:: sage: ruler([1,2,3],vector([1,2,4]),snap=True) Graphics3d Object The keyword ``absolute`` makes a huge ruler in one of the axis directions:: sage: ruler([1,2,3],vector([1,2,4]),absolute=True) Graphics3d Object TESTS:: sage: ruler([1,2,3],vector([1,3,4]),absolute=True) Traceback (most recent call last): ... ValueError: Absolute rulers only valid for axis-aligned paths """ start = vector(RDF, start) end = vector(RDF, end) dir = end - start dist = math.sqrt(dir.dot_product(dir)) dir /= dist one_tick = dist / ticks * 1.414 unit = 10**math.floor(math.log(dist / ticks, 10)) if unit * 5 < one_tick: unit *= 5 elif unit * 2 < one_tick: unit *= 2 if dir[0]: tick = dir.cross_product(vector(RDF, (0, 0, -dist / 30))) elif dir[1]: tick = dir.cross_product(vector(RDF, (0, 0, dist / 30))) else: tick = vector(RDF, (dist / 30, 0, 0)) if snap: for i in range(3): start[i] = unit * math.floor(start[i] / unit + 1e-5) end[i] = unit * math.ceil(end[i] / unit - 1e-5) if absolute: if dir[0] * dir[1] or dir[1] * dir[2] or dir[0] * dir[2]: raise ValueError( "Absolute rulers only valid for axis-aligned paths") m = max(dir[0], dir[1], dir[2]) if dir[0] == m: off = start[0] elif dir[1] == m: off = start[1] else: off = start[2] first_tick = unit * math.ceil(off / unit - 1e-5) - off else: off = 0 first_tick = 0 ruler = shapes.LineSegment(start, end, **kwds) for k in range(1, int(sub_ticks * first_tick / unit)): P = start + dir * (k * unit / sub_ticks) ruler += shapes.LineSegment(P, P + tick / 2, **kwds) for d in srange(first_tick, dist + unit / (sub_ticks + 1), unit): P = start + dir * d ruler += shapes.LineSegment(P, P + tick, **kwds) ruler += shapes.Text(str(d + off), **kwds).translate(P - tick) if dist - d < unit: sub_ticks = int(sub_ticks * (dist - d) / unit) for k in range(1, sub_ticks): P += dir * (unit / sub_ticks) ruler += shapes.LineSegment(P, P + tick / 2, **kwds) return ruler
def _parametric_plot3d_surface(f, urange, vrange, plot_points, boundary_style, **kwds): r""" Return a parametric three-dimensional space surface. This function is used internally by the :func:`parametric_plot3d` command. There are two ways this function is invoked by :func:`parametric_plot3d`. - ``parametric_plot3d([f_x, f_y, f_z], (u_min, u_max), (v_min, v_max))``: `f_x, f_y, f_z` are each functions of two variables - ``parametric_plot3d([f_x, f_y, f_z], (u, u_min, u_max), (v, v_min, v_max))``: `f_x, f_y, f_z` can be viewed as functions of `u` and `v` INPUT: - ``f`` - a 3-tuple of functions or expressions, or vector of size 3 - ``urange`` - a 2-tuple (u_min, u_max) or a 3-tuple (u, u_min, u_max) - ``vrange`` - a 2-tuple (v_min, v_max) or a 3-tuple (v, v_min, v_max) - ``plot_points`` - (default: "automatic", which is [40,40] for surfaces) initial number of sample points in each parameter; a pair of integers. - ``boundary_style`` - (default: None, no boundary) a dict that describes how to draw the boundaries of regions by giving options that are passed to the line3d command. EXAMPLES: We demonstrate each of the two ways of calling this. See :func:`parametric_plot3d` for many more examples. We do the first one with lambda functions:: sage: f = (lambda u,v: cos(u), lambda u,v: sin(u)+cos(v), lambda u,v: sin(v)) sage: parametric_plot3d(f, (0, 2*pi), (-pi, pi)) # indirect doctest Graphics3d Object Now we do the same thing with symbolic expressions:: sage: u, v = var('u,v') sage: parametric_plot3d((cos(u), sin(u) + cos(v), sin(v)), (u, 0, 2*pi), (v, -pi, pi), mesh=True) Graphics3d Object """ from sage.plot.misc import setup_for_eval_on_grid g, ranges = setup_for_eval_on_grid(f, [urange, vrange], plot_points) urange = srange(*ranges[0], include_endpoint=True) vrange = srange(*ranges[1], include_endpoint=True) G = ParametricSurface(g, (urange, vrange), **kwds) if boundary_style is not None: for u in (urange[0], urange[-1]): G += line3d([(g[0](u,v), g[1](u,v), g[2](u,v)) for v in vrange], **boundary_style) for v in (vrange[0], vrange[-1]): G += line3d([(g[0](u,v), g[1](u,v), g[2](u,v)) for u in urange], **boundary_style) return G
def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, precision=None, normalized=True): r""" Return the asymptotic expansion of the coefficients of an power series with specified pole and logarithmic singularity. More precisely, this extracts the `n`-th coefficient .. MATH:: [z^n] \left(\frac{1}{1-z/\zeta}\right)^\alpha \left(\frac{1}{z/\zeta} \log \frac{1}{1-z/\zeta}\right)^\beta \left(\frac{1}{z/\zeta} \log \left(\frac{1}{z/\zeta} \log \frac{1}{1-z/\zeta}\right)\right)^\delta (if ``normalized=True``, the default) or .. MATH:: [z^n] \left(\frac{1}{1-z/\zeta}\right)^\alpha \left(\log \frac{1}{1-z/\zeta}\right)^\beta \left(\log \left(\frac{1}{z/\zeta} \log \frac{1}{1-z/\zeta}\right)\right)^\delta (if ``normalized=False``). INPUT: - ``var`` -- a string for the variable name. - ``zeta`` -- (default: `1`) the location of the singularity. - ``alpha`` -- (default: `0`) the pole order of the singularty. - ``beta`` -- (default: `0`) the order of the logarithmic singularity. - ``delta`` -- (default: `0`) the order of the log-log singularity. Not yet implemented for ``delta != 0``. - ``precision`` -- (default: ``None``) an integer. If ``None``, then the default precision of the asymptotic ring is used. - ``normalized`` -- (default: ``True``) a boolean, see above. OUTPUT: An asymptotic expansion. EXAMPLES:: sage: asymptotic_expansions.SingularityAnalysis('n', alpha=1) 1 sage: asymptotic_expansions.SingularityAnalysis('n', alpha=2) n + 1 sage: asymptotic_expansions.SingularityAnalysis('n', alpha=3) 1/2*n^2 + 3/2*n + 1 sage: _.parent() Asymptotic Ring <n^ZZ> over Rational Field :: sage: asymptotic_expansions.SingularityAnalysis('n', alpha=-3/2, ....: precision=3) 3/4/sqrt(pi)*n^(-5/2) + 45/32/sqrt(pi)*n^(-7/2) + 1155/512/sqrt(pi)*n^(-9/2) + O(n^(-11/2)) sage: asymptotic_expansions.SingularityAnalysis('n', alpha=-1/2, ....: precision=3) -1/2/sqrt(pi)*n^(-3/2) - 3/16/sqrt(pi)*n^(-5/2) - 25/256/sqrt(pi)*n^(-7/2) + O(n^(-9/2)) sage: asymptotic_expansions.SingularityAnalysis('n', alpha=1/2, ....: precision=4) 1/sqrt(pi)*n^(-1/2) - 1/8/sqrt(pi)*n^(-3/2) + 1/128/sqrt(pi)*n^(-5/2) + 5/1024/sqrt(pi)*n^(-7/2) + O(n^(-9/2)) sage: _.parent() Asymptotic Ring <n^QQ> over Symbolic Constants Subring :: sage: S = SR.subring(rejecting_variables=('n',)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=S.var('a'), ....: precision=4).map_coefficients(lambda c: c.factor()) 1/gamma(a)*n^(a - 1) + (1/2*(a - 1)*a/gamma(a))*n^(a - 2) + (1/24*(3*a - 1)*(a - 1)*(a - 2)*a/gamma(a))*n^(a - 3) + (1/48*(a - 1)^2*(a - 2)*(a - 3)*a^2/gamma(a))*n^(a - 4) + O(n^(a - 5)) sage: _.parent() Asymptotic Ring <n^(Symbolic Subring rejecting the variable n)> over Symbolic Subring rejecting the variable n :: sage: ae = asymptotic_expansions.SingularityAnalysis('n', ....: alpha=1/2, beta=1, precision=4); ae 1/sqrt(pi)*n^(-1/2)*log(n) + ((euler_gamma + 2*log(2))/sqrt(pi))*n^(-1/2) - 5/8/sqrt(pi)*n^(-3/2)*log(n) + (1/8*(3*euler_gamma + 6*log(2) - 8)/sqrt(pi) - (euler_gamma + 2*log(2) - 2)/sqrt(pi))*n^(-3/2) + O(n^(-5/2)*log(n)) sage: n = ae.parent().gen() sage: ae.subs(n=n-1).map_coefficients(lambda x: x.canonicalize_radical()) 1/sqrt(pi)*n^(-1/2)*log(n) + ((euler_gamma + 2*log(2))/sqrt(pi))*n^(-1/2) - 1/8/sqrt(pi)*n^(-3/2)*log(n) + (-1/8*(euler_gamma + 2*log(2))/sqrt(pi))*n^(-3/2) + O(n^(-5/2)*log(n)) :: sage: asymptotic_expansions.SingularityAnalysis('n', ....: alpha=1, beta=1/2, precision=4) log(n)^(1/2) + 1/2*euler_gamma*log(n)^(-1/2) + (-1/8*euler_gamma^2 + 1/48*pi^2)*log(n)^(-3/2) + (1/16*euler_gamma^3 - 1/32*euler_gamma*pi^2 + 1/8*zeta(3))*log(n)^(-5/2) + O(log(n)^(-7/2)) :: sage: ae = asymptotic_expansions.SingularityAnalysis('n', ....: alpha=0, beta=2, precision=14) sage: n = ae.parent().gen() sage: ae.subs(n=n-2) 2*n^(-1)*log(n) + 2*euler_gamma*n^(-1) - n^(-2) - 1/6*n^(-3) + O(n^(-5)) :: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=-1/2, beta=1, precision=2, normalized=False) -1/2/sqrt(pi)*n^(-3/2)*log(n) + (-1/2*(euler_gamma + 2*log(2) - 2)/sqrt(pi))*n^(-3/2) + O(n^(-5/2)*log(n)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1/2, alpha=0, beta=1, precision=3, normalized=False) 2^n*n^(-1) + O(2^n*n^(-2)) ALGORITHM: See [FS2009]_ together with the `errata list <http://algo.inria.fr/flajolet/Publications/AnaCombi/errata.pdf>`_. REFERENCES: .. [FS2009] Philippe Flajolet and Robert Sedgewick, `Analytic combinatorics <http://algo.inria.fr/flajolet/Publications/AnaCombi/book.pdf>`_. Cambridge University Press, Cambridge, 2009. TESTS:: sage: ex = asymptotic_expansions.SingularityAnalysis('n', alpha=-1/2, ....: precision=4) sage: n = ex.parent().gen() sage: coefficients = ((1-x)^(1/2)).series( ....: x, 21).truncate().coefficients(x, sparse=False) sage: ex.compare_with_values(n, # rel tol 1e-6 ....: lambda k: coefficients[k], [5, 10, 20]) [(5, 0.015778873294?), (10, 0.01498952777?), (20, 0.0146264622?)] sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=3, precision=2) 1/2*n^2 + 3/2*n + O(1) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=3, precision=3) 1/2*n^2 + 3/2*n + 1 sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=3, precision=4) 1/2*n^2 + 3/2*n + 1 :: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=0) Traceback (most recent call last): ... NotImplementedOZero: The error term in the result is O(0) which means 0 for sufficiently large n. sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=-1) Traceback (most recent call last): ... NotImplementedOZero: The error term in the result is O(0) which means 0 for sufficiently large n. :: sage: asymptotic_expansions.SingularityAnalysis( ....: 'm', alpha=-1/2, precision=3) -1/2/sqrt(pi)*m^(-3/2) - 3/16/sqrt(pi)*m^(-5/2) - 25/256/sqrt(pi)*m^(-7/2) + O(m^(-9/2)) sage: _.parent() Asymptotic Ring <m^QQ> over Symbolic Constants Subring Location of the singularity:: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=1, zeta=2, precision=3) (1/2)^n sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=1, zeta=1/2, precision=3) 2^n sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=1, zeta=CyclotomicField(3).gen(), ....: precision=3) (-zeta3 - 1)^n sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=4, zeta=2, precision=3) 1/6*(1/2)^n*n^3 + (1/2)^n*n^2 + 11/6*(1/2)^n*n + O((1/2)^n) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=-1, zeta=2, precision=3) Traceback (most recent call last): ... NotImplementedOZero: The error term in the result is O(0) which means 0 for sufficiently large n. sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=1/2, zeta=2, precision=3) 1/sqrt(pi)*(1/2)^n*n^(-1/2) - 1/8/sqrt(pi)*(1/2)^n*n^(-3/2) + 1/128/sqrt(pi)*(1/2)^n*n^(-5/2) + O((1/2)^n*n^(-7/2)) The following tests correspond to Table VI.5 in [FS2009]_. :: sage: A.<n> = AsymptoticRing('n^QQ * log(n)^QQ', QQ) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=-1/2, beta=1, precision=2, ....: normalized=False) * (- sqrt(pi*n^3)) 1/2*log(n) + 1/2*euler_gamma + log(2) - 1 + O(n^(-1)*log(n)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=0, beta=1, precision=3, ....: normalized=False) n^(-1) + O(n^(-2)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=0, beta=2, precision=14, ....: normalized=False) * n 2*log(n) + 2*euler_gamma - n^(-1) - 1/6*n^(-2) + O(n^(-4)) sage: (asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=1/2, beta=1, precision=4, ....: normalized=False) * sqrt(pi*n)).\ ....: map_coefficients(lambda x: x.expand()) log(n) + euler_gamma + 2*log(2) - 1/8*n^(-1)*log(n) + (-1/8*euler_gamma - 1/4*log(2))*n^(-1) + O(n^(-2)*log(n)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=1, beta=1, precision=13, ....: normalized=False) log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4) + O(n^(-6)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=1, beta=2, precision=4, ....: normalized=False) log(n)^2 + 2*euler_gamma*log(n) + euler_gamma^2 - 1/6*pi^2 + O(n^(-1)*log(n)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=3/2, beta=1, precision=3, ....: normalized=False) * sqrt(pi/n) 2*log(n) + 2*euler_gamma + 4*log(2) - 4 + 3/4*n^(-1)*log(n) + O(n^(-1)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=2, beta=1, precision=5, ....: normalized=False) n*log(n) + (euler_gamma - 1)*n + log(n) + euler_gamma + 1/2 + O(n^(-1)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=2, beta=2, precision=4, ....: normalized=False) / n log(n)^2 + (2*euler_gamma - 2)*log(n) - 2*euler_gamma + euler_gamma^2 - 1/6*pi^2 + 2 + n^(-1)*log(n)^2 + O(n^(-1)*log(n)) Be aware that the last result does *not* coincide with [FS2009]_, they do have a different error term. Checking parameters:: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, 1, 1/2, precision=0, normalized=False) Traceback (most recent call last): ... ValueError: beta and delta must be integers sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, 1, 1, 1/2, normalized=False) Traceback (most recent call last): ... ValueError: beta and delta must be integers :: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=0, beta=0, delta=1, precision=3) Traceback (most recent call last): ... NotImplementedError: not implemented for delta!=0 """ from itertools import islice, count from asymptotic_ring import AsymptoticRing from growth_group import ExponentialGrowthGroup, \ MonomialGrowthGroup from sage.arith.all import falling_factorial from sage.categories.cartesian_product import cartesian_product from sage.functions.other import binomial, gamma from sage.calculus.calculus import limit from sage.misc.cachefunc import cached_function from sage.arith.srange import srange from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ from sage.symbolic.ring import SR SCR = SR.subring(no_variables=True) s = SR('s') iga = 1/gamma(alpha) if iga.parent() is SR: try: iga = SCR(iga) except TypeError: pass coefficient_ring = iga.parent() if beta != 0: coefficient_ring = SCR @cached_function def inverse_gamma_derivative(shift, r): """ Return value of `r`-th derivative of 1/Gamma at alpha-shift. """ if r == 0: result = iga*falling_factorial(alpha-1, shift) else: result = limit((1/gamma(s)).diff(s, r), s=alpha-shift) try: return coefficient_ring(result) except TypeError: return result if isinstance(alpha, int): alpha = ZZ(alpha) if isinstance(beta, int): beta = ZZ(beta) if isinstance(delta, int): delta = ZZ(delta) if precision is None: precision = AsymptoticRing.__default_prec__ if not normalized and not (beta in ZZ and delta in ZZ): raise ValueError("beta and delta must be integers") if delta != 0: raise NotImplementedError("not implemented for delta!=0") groups = [] if zeta != 1: groups.append(ExponentialGrowthGroup((1/zeta).parent(), var)) groups.append(MonomialGrowthGroup(alpha.parent(), var)) if beta != 0: groups.append(MonomialGrowthGroup(beta.parent(), 'log({})'.format(var))) group = cartesian_product(groups) A = AsymptoticRing(growth_group=group, coefficient_ring=coefficient_ring, default_prec=precision) n = A.gen() if zeta == 1: exponential_factor = 1 else: exponential_factor = n.rpow(1/zeta) if beta in ZZ and beta >= 0: it = ((k, r) for k in count() for r in srange(beta+1)) k_max = precision else: it = ((0, r) for r in count()) k_max = 0 if beta != 0: log_n = n.log() else: # avoid construction of log(n) # because it does not exist in growth group. log_n = 1 it = reversed(list(islice(it, precision+1))) if normalized: beta_denominator = beta else: beta_denominator = 0 L = _sa_coefficients_lambda_(max(1, k_max), beta=beta_denominator) (k, r) = next(it) result = (n**(-k) * log_n**(-r)).O() if alpha in ZZ and beta == 0: if alpha > 0 and alpha <= precision: result = A(0) elif alpha <= 0 and precision > 0: from misc import NotImplementedOZero raise NotImplementedOZero(A) for (k, r) in it: result += binomial(beta, r) * \ sum(L[(k, ell)] * (-1)**ell * inverse_gamma_derivative(ell, r) for ell in srange(k, 2*k+1) if (k, ell) in L) * \ n**(-k) * log_n**(-r) result *= exponential_factor * n**(alpha-1) * log_n**beta return result
def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, precision=None, normalized=True): r""" Return the asymptotic expansion of the coefficients of an power series with specified pole and logarithmic singularity. More precisely, this extracts the `n`-th coefficient .. MATH:: [z^n] \left(\frac{1}{1-z/\zeta}\right)^\alpha \left(\frac{1}{z/\zeta} \log \frac{1}{1-z/\zeta}\right)^\beta \left(\frac{1}{z/\zeta} \log \left(\frac{1}{z/\zeta} \log \frac{1}{1-z/\zeta}\right)\right)^\delta (if ``normalized=True``, the default) or .. MATH:: [z^n] \left(\frac{1}{1-z/\zeta}\right)^\alpha \left(\log \frac{1}{1-z/\zeta}\right)^\beta \left(\log \left(\frac{1}{z/\zeta} \log \frac{1}{1-z/\zeta}\right)\right)^\delta (if ``normalized=False``). INPUT: - ``var`` -- a string for the variable name. - ``zeta`` -- (default: `1`) the location of the singularity. - ``alpha`` -- (default: `0`) the pole order of the singularty. - ``beta`` -- (default: `0`) the order of the logarithmic singularity. - ``delta`` -- (default: `0`) the order of the log-log singularity. Not yet implemented for ``delta != 0``. - ``precision`` -- (default: ``None``) an integer. If ``None``, then the default precision of the asymptotic ring is used. - ``normalized`` -- (default: ``True``) a boolean, see above. OUTPUT: An asymptotic expansion. EXAMPLES:: sage: asymptotic_expansions.SingularityAnalysis('n', alpha=1) 1 sage: asymptotic_expansions.SingularityAnalysis('n', alpha=2) n + 1 sage: asymptotic_expansions.SingularityAnalysis('n', alpha=3) 1/2*n^2 + 3/2*n + 1 sage: _.parent() Asymptotic Ring <n^ZZ> over Rational Field :: sage: asymptotic_expansions.SingularityAnalysis('n', alpha=-3/2, ....: precision=3) 3/4/sqrt(pi)*n^(-5/2) + 45/32/sqrt(pi)*n^(-7/2) + 1155/512/sqrt(pi)*n^(-9/2) + O(n^(-11/2)) sage: asymptotic_expansions.SingularityAnalysis('n', alpha=-1/2, ....: precision=3) -1/2/sqrt(pi)*n^(-3/2) - 3/16/sqrt(pi)*n^(-5/2) - 25/256/sqrt(pi)*n^(-7/2) + O(n^(-9/2)) sage: asymptotic_expansions.SingularityAnalysis('n', alpha=1/2, ....: precision=4) 1/sqrt(pi)*n^(-1/2) - 1/8/sqrt(pi)*n^(-3/2) + 1/128/sqrt(pi)*n^(-5/2) + 5/1024/sqrt(pi)*n^(-7/2) + O(n^(-9/2)) sage: _.parent() Asymptotic Ring <n^QQ> over Symbolic Constants Subring :: sage: S = SR.subring(rejecting_variables=('n',)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=S.var('a'), ....: precision=4).map_coefficients(lambda c: c.factor()) 1/gamma(a)*n^(a - 1) + (1/2*(a - 1)*a/gamma(a))*n^(a - 2) + (1/24*(3*a - 1)*(a - 1)*(a - 2)*a/gamma(a))*n^(a - 3) + (1/48*(a - 1)^2*(a - 2)*(a - 3)*a^2/gamma(a))*n^(a - 4) + O(n^(a - 5)) sage: _.parent() Asymptotic Ring <n^(Symbolic Subring rejecting the variable n)> over Symbolic Subring rejecting the variable n :: sage: ae = asymptotic_expansions.SingularityAnalysis('n', ....: alpha=1/2, beta=1, precision=4); ae 1/sqrt(pi)*n^(-1/2)*log(n) + ((euler_gamma + 2*log(2))/sqrt(pi))*n^(-1/2) - 5/8/sqrt(pi)*n^(-3/2)*log(n) + (1/8*(3*euler_gamma + 6*log(2) - 8)/sqrt(pi) - (euler_gamma + 2*log(2) - 2)/sqrt(pi))*n^(-3/2) + O(n^(-5/2)*log(n)) sage: n = ae.parent().gen() sage: ae.subs(n=n-1).map_coefficients(lambda x: x.canonicalize_radical()) 1/sqrt(pi)*n^(-1/2)*log(n) + ((euler_gamma + 2*log(2))/sqrt(pi))*n^(-1/2) - 1/8/sqrt(pi)*n^(-3/2)*log(n) + (-1/8*(euler_gamma + 2*log(2))/sqrt(pi))*n^(-3/2) + O(n^(-5/2)*log(n)) :: sage: asymptotic_expansions.SingularityAnalysis('n', ....: alpha=1, beta=1/2, precision=4) log(n)^(1/2) + 1/2*euler_gamma*log(n)^(-1/2) + (-1/8*euler_gamma^2 + 1/48*pi^2)*log(n)^(-3/2) + (1/16*euler_gamma^3 - 1/32*euler_gamma*pi^2 + 1/8*zeta(3))*log(n)^(-5/2) + O(log(n)^(-7/2)) :: sage: ae = asymptotic_expansions.SingularityAnalysis('n', ....: alpha=0, beta=2, precision=14) sage: n = ae.parent().gen() sage: ae.subs(n=n-2) 2*n^(-1)*log(n) + 2*euler_gamma*n^(-1) - n^(-2) - 1/6*n^(-3) + O(n^(-5)) :: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=-1/2, beta=1, precision=2, normalized=False) -1/2/sqrt(pi)*n^(-3/2)*log(n) + (-1/2*(euler_gamma + 2*log(2) - 2)/sqrt(pi))*n^(-3/2) + O(n^(-5/2)*log(n)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1/2, alpha=0, beta=1, precision=3, normalized=False) 2^n*n^(-1) + O(2^n*n^(-2)) ALGORITHM: See [FS2009]_ together with the `errata list <http://algo.inria.fr/flajolet/Publications/AnaCombi/errata.pdf>`_. REFERENCES: .. [FS2009] Philippe Flajolet and Robert Sedgewick, `Analytic combinatorics <http://algo.inria.fr/flajolet/Publications/AnaCombi/book.pdf>`_. Cambridge University Press, Cambridge, 2009. TESTS:: sage: ex = asymptotic_expansions.SingularityAnalysis('n', alpha=-1/2, ....: precision=4) sage: n = ex.parent().gen() sage: coefficients = ((1-x)^(1/2)).series( ....: x, 21).truncate().coefficients(x, sparse=False) sage: ex.compare_with_values(n, # rel tol 1e-6 ....: lambda k: coefficients[k], [5, 10, 20]) [(5, 0.015778873294?), (10, 0.01498952777?), (20, 0.0146264622?)] sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=3, precision=2) 1/2*n^2 + 3/2*n + O(1) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=3, precision=3) 1/2*n^2 + 3/2*n + 1 sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=3, precision=4) 1/2*n^2 + 3/2*n + 1 :: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=0) Traceback (most recent call last): ... NotImplementedOZero: The error term in the result is O(0) which means 0 for sufficiently large n. sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=-1) Traceback (most recent call last): ... NotImplementedOZero: The error term in the result is O(0) which means 0 for sufficiently large n. :: sage: asymptotic_expansions.SingularityAnalysis( ....: 'm', alpha=-1/2, precision=3) -1/2/sqrt(pi)*m^(-3/2) - 3/16/sqrt(pi)*m^(-5/2) - 25/256/sqrt(pi)*m^(-7/2) + O(m^(-9/2)) sage: _.parent() Asymptotic Ring <m^QQ> over Symbolic Constants Subring Location of the singularity:: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=1, zeta=2, precision=3) (1/2)^n sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=1, zeta=1/2, precision=3) 2^n sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=1, zeta=CyclotomicField(3).gen(), ....: precision=3) (-zeta3 - 1)^n sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=4, zeta=2, precision=3) 1/6*(1/2)^n*n^3 + (1/2)^n*n^2 + 11/6*(1/2)^n*n + O((1/2)^n) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=-1, zeta=2, precision=3) Traceback (most recent call last): ... NotImplementedOZero: The error term in the result is O(0) which means 0 for sufficiently large n. sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=1/2, zeta=2, precision=3) 1/sqrt(pi)*(1/2)^n*n^(-1/2) - 1/8/sqrt(pi)*(1/2)^n*n^(-3/2) + 1/128/sqrt(pi)*(1/2)^n*n^(-5/2) + O((1/2)^n*n^(-7/2)) The following tests correspond to Table VI.5 in [FS2009]_. :: sage: A.<n> = AsymptoticRing('n^QQ * log(n)^QQ', QQ) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=-1/2, beta=1, precision=2, ....: normalized=False) * (- sqrt(pi*n^3)) 1/2*log(n) + 1/2*euler_gamma + log(2) - 1 + O(n^(-1)*log(n)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=0, beta=1, precision=3, ....: normalized=False) n^(-1) + O(n^(-2)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=0, beta=2, precision=14, ....: normalized=False) * n 2*log(n) + 2*euler_gamma - n^(-1) - 1/6*n^(-2) + O(n^(-4)) sage: (asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=1/2, beta=1, precision=4, ....: normalized=False) * sqrt(pi*n)).\ ....: map_coefficients(lambda x: x.expand()) log(n) + euler_gamma + 2*log(2) - 1/8*n^(-1)*log(n) + (-1/8*euler_gamma - 1/4*log(2))*n^(-1) + O(n^(-2)*log(n)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=1, beta=1, precision=13, ....: normalized=False) log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4) + O(n^(-6)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=1, beta=2, precision=4, ....: normalized=False) log(n)^2 + 2*euler_gamma*log(n) + euler_gamma^2 - 1/6*pi^2 + O(n^(-1)*log(n)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=3/2, beta=1, precision=3, ....: normalized=False) * sqrt(pi/n) 2*log(n) + 2*euler_gamma + 4*log(2) - 4 + 3/4*n^(-1)*log(n) + O(n^(-1)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=2, beta=1, precision=5, ....: normalized=False) n*log(n) + (euler_gamma - 1)*n + log(n) + euler_gamma + 1/2 + O(n^(-1)) sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, alpha=2, beta=2, precision=4, ....: normalized=False) / n log(n)^2 + (2*euler_gamma - 2)*log(n) - 2*euler_gamma + euler_gamma^2 - 1/6*pi^2 + 2 + n^(-1)*log(n)^2 + O(n^(-1)*log(n)) Be aware that the last result does *not* coincide with [FS2009]_, they do have a different error term. Checking parameters:: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, 1, 1/2, precision=0, normalized=False) Traceback (most recent call last): ... ValueError: beta and delta must be integers sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', 1, 1, 1, 1/2, normalized=False) Traceback (most recent call last): ... ValueError: beta and delta must be integers :: sage: asymptotic_expansions.SingularityAnalysis( ....: 'n', alpha=0, beta=0, delta=1, precision=3) Traceback (most recent call last): ... NotImplementedError: not implemented for delta!=0 """ from itertools import islice, count from asymptotic_ring import AsymptoticRing from growth_group import ExponentialGrowthGroup, \ MonomialGrowthGroup from sage.arith.all import falling_factorial from sage.categories.cartesian_product import cartesian_product from sage.functions.other import binomial, gamma from sage.calculus.calculus import limit from sage.misc.cachefunc import cached_function from sage.arith.srange import srange from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ from sage.symbolic.ring import SR SCR = SR.subring(no_variables=True) s = SR('s') iga = 1 / gamma(alpha) if iga.parent() is SR: try: iga = SCR(iga) except TypeError: pass coefficient_ring = iga.parent() if beta != 0: coefficient_ring = SCR @cached_function def inverse_gamma_derivative(shift, r): """ Return value of `r`-th derivative of 1/Gamma at alpha-shift. """ if r == 0: result = iga * falling_factorial(alpha - 1, shift) else: result = limit((1 / gamma(s)).diff(s, r), s=alpha - shift) try: return coefficient_ring(result) except TypeError: return result if isinstance(alpha, int): alpha = ZZ(alpha) if isinstance(beta, int): beta = ZZ(beta) if isinstance(delta, int): delta = ZZ(delta) if precision is None: precision = AsymptoticRing.__default_prec__ if not normalized and not (beta in ZZ and delta in ZZ): raise ValueError("beta and delta must be integers") if delta != 0: raise NotImplementedError("not implemented for delta!=0") groups = [] if zeta != 1: groups.append(ExponentialGrowthGroup((1 / zeta).parent(), var)) groups.append(MonomialGrowthGroup(alpha.parent(), var)) if beta != 0: groups.append( MonomialGrowthGroup(beta.parent(), 'log({})'.format(var))) group = cartesian_product(groups) A = AsymptoticRing(growth_group=group, coefficient_ring=coefficient_ring, default_prec=precision) n = A.gen() if zeta == 1: exponential_factor = 1 else: exponential_factor = n.rpow(1 / zeta) if beta in ZZ and beta >= 0: it = ((k, r) for k in count() for r in srange(beta + 1)) k_max = precision else: it = ((0, r) for r in count()) k_max = 0 if beta != 0: log_n = n.log() else: # avoid construction of log(n) # because it does not exist in growth group. log_n = 1 it = reversed(list(islice(it, precision + 1))) if normalized: beta_denominator = beta else: beta_denominator = 0 L = _sa_coefficients_lambda_(max(1, k_max), beta=beta_denominator) (k, r) = next(it) result = (n**(-k) * log_n**(-r)).O() if alpha in ZZ and beta == 0: if alpha > 0 and alpha <= precision: result = A(0) elif alpha <= 0 and precision > 0: from misc import NotImplementedOZero raise NotImplementedOZero(A) for (k, r) in it: result += binomial(beta, r) * \ sum(L[(k, ell)] * (-1)**ell * inverse_gamma_derivative(ell, r) for ell in srange(k, 2*k+1) if (k, ell) in L) * \ n**(-k) * log_n**(-r) result *= exponential_factor * n**(alpha - 1) * log_n**beta return result
def _Omega_numerator_(a, x, y, t): r""" Return the numerator of `\Omega_{\ge}` of the expression specified by the input. To be more precise, calculate .. MATH:: \Omega_{\ge} \frac{\mu^a}{ (1 - x_1 \mu) \dots (1 - x_n \mu) (1 - y_1 / \mu) \dots (1 - y_m / \mu)} and return its numerator. This function is meant to be a helper function of :func:`MacMahonOmega`. INPUT: - ``a`` -- an integer - ``x`` and ``y`` -- a tuple of tuples of Laurent polynomials The flattened ``x`` contains `x_1,...,x_n`, the flattened ``y`` the `y_1,...,y_m`. The non-flatness of these parameters is to be interface-consistent with :func:`_Omega_factors_denominator_`. - ``t`` -- a temporary Laurent polynomial variable used for substituting OUTPUT: A Laurent polynomial The output is normalized such that the corresponding denominator (:func:`_Omega_factors_denominator_`) has constant term `1`. EXAMPLES:: sage: from sage.rings.polynomial.omega import _Omega_numerator_, _Omega_factors_denominator_ sage: L.<x0, x1, x2, x3, y0, y1, t> = LaurentPolynomialRing(ZZ) sage: _Omega_numerator_(0, ((x0,),), ((y0,),), t) 1 sage: _Omega_numerator_(0, ((x0,), (x1,)), ((y0,),), t) -x0*x1*y0 + 1 sage: _Omega_numerator_(0, ((x0,),), ((y0,), (y1,)), t) 1 sage: _Omega_numerator_(0, ((x0,), (x1,), (x2,)), ((y0,),), t) x0*x1*x2*y0^2 + x0*x1*x2*y0 - x0*x1*y0 - x0*x2*y0 - x1*x2*y0 + 1 sage: _Omega_numerator_(0, ((x0,), (x1,)), ((y0,), (y1,)), t) x0^2*x1*y0*y1 + x0*x1^2*y0*y1 - x0*x1*y0*y1 - x0*x1*y0 - x0*x1*y1 + 1 sage: _Omega_numerator_(-2, ((x0,),), ((y0,),), t) x0^2 sage: _Omega_numerator_(-1, ((x0,),), ((y0,),), t) x0 sage: _Omega_numerator_(1, ((x0,),), ((y0,),), t) -x0*y0 + y0 + 1 sage: _Omega_numerator_(2, ((x0,),), ((y0,),), t) -x0*y0^2 - x0*y0 + y0^2 + y0 + 1 TESTS:: sage: _Omega_factors_denominator_((), ()) () sage: _Omega_numerator_(0, (), (), t) 1 sage: _Omega_numerator_(+2, (), (), t) 1 sage: _Omega_numerator_(-2, (), (), t) 0 sage: _Omega_factors_denominator_(((x0,),), ()) (-x0 + 1,) sage: _Omega_numerator_(0, ((x0,),), (), t) 1 sage: _Omega_numerator_(+2, ((x0,),), (), t) 1 sage: _Omega_numerator_(-2, ((x0,),), (), t) x0^2 sage: _Omega_factors_denominator_((), ((y0,),)) () sage: _Omega_numerator_(0, (), ((y0,),), t) 1 sage: _Omega_numerator_(+2, (), ((y0,),), t) y0^2 + y0 + 1 sage: _Omega_numerator_(-2, (), ((y0,),), t) 0 :: sage: L.<X, Y, t> = LaurentPolynomialRing(ZZ) sage: _Omega_numerator_(2, ((X,),), ((Y,),), t) -X*Y^2 - X*Y + Y^2 + Y + 1 """ from sage.arith.srange import srange from sage.misc.misc_c import prod x_flat = sum(x, tuple()) y_flat = sum(y, tuple()) n = len(x_flat) m = len(y_flat) xy = x_flat + y_flat import logging logger = logging.getLogger(__name__) logger.info('Omega_numerator: a=%s, n=%s, m=%s', a, n, m) if m == 0: result = 1 - (prod(_Omega_factors_denominator_(x, y)) * sum( homogenous_symmetric_function(j, xy) for j in srange(-a)) if a < 0 else 0) elif n == 0: result = sum( homogenous_symmetric_function(j, xy) for j in srange(a + 1)) else: result = _Omega_numerator_P_(a, x_flat[:-1], y_flat, t).subs({t: x_flat[-1]}) L = t.parent() result = L(result) logger.info('_Omega_numerator_: %s terms', result.number_of_terms()) return result
def plot_vector_field3d(functions, xrange, yrange, zrange, plot_points=5, colors='jet', center_arrows=False, **kwds): r""" Plot a 3d vector field INPUT: - ``functions`` - a list of three functions, representing the x-, y-, and z-coordinates of a vector - ``xrange``, ``yrange``, and ``zrange`` - three tuples of the form (var, start, stop), giving the variables and ranges for each axis - ``plot_points`` (default 5) - either a number or list of three numbers, specifying how many points to plot for each axis - ``colors`` (default 'jet') - a color, list of colors (which are interpolated between), or matplotlib colormap name, giving the coloring of the arrows. If a list of colors or a colormap is given, coloring is done as a function of length of the vector - ``center_arrows`` (default False) - If True, draw the arrows centered on the points; otherwise, draw the arrows with the tail at the point - any other keywords are passed on to the plot command for each arrow EXAMPLES:: sage: x,y,z=var('x y z') sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi)) Graphics3d Object sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),colors=['red','green','blue']) Graphics3d Object sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),colors='red') Graphics3d Object sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),plot_points=4) Graphics3d Object sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),plot_points=[3,5,7]) Graphics3d Object sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),center_arrows=True) Graphics3d Object TESTS: This tests that :trac:`2100` is fixed in a way compatible with this command:: sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),center_arrows=True,aspect_ratio=(1,2,1)) Graphics3d Object """ (ff,gg,hh), ranges = setup_for_eval_on_grid(functions, [xrange, yrange, zrange], plot_points) xpoints, ypoints, zpoints = [srange(*r, include_endpoint=True) for r in ranges] points = [vector((i,j,k)) for i in xpoints for j in ypoints for k in zpoints] vectors = [vector((ff(*point), gg(*point), hh(*point))) for point in points] try: from matplotlib.cm import get_cmap cm = get_cmap(colors) except (TypeError, ValueError): cm = None if cm is None: if isinstance(colors, (list, tuple)): from matplotlib.colors import LinearSegmentedColormap cm = LinearSegmentedColormap.from_list('mymap',colors) else: cm = lambda x: colors max_len = max(v.norm() for v in vectors) scaled_vectors = [v/max_len for v in vectors] if center_arrows: G = sum([plot(v,color=cm(v.norm()),**kwds).translate(p-v/2) for v,p in zip(scaled_vectors, points)]) G._set_extra_kwds(kwds) return G else: G = sum([plot(v,color=cm(v.norm()),**kwds).translate(p) for v,p in zip(scaled_vectors, points)]) G._set_extra_kwds(kwds) return G
def product_space(chi, k, weights=False, base_ring=None, verbose=False): r""" Computes all eisenstein series, and products of pairs of eisenstein series of lower weight, lying in the space of modular forms of weight $k$ and nebentypus $\chi$. INPUT: - chi - Dirichlet character, the nebentypus of the target space - k - an integer, the weight of the target space OUTPUT: - a matrix of coefficients of q-expansions, which are the products of Eisenstein series in M_k(chi). WARNING: It is only for principal chi that we know that the resulting space is the whole space of modular forms. """ if weights == False: weights = srange(1, k / 2 + 1) weight_dict = {} weight_dict[-1] = [w for w in weights if w % 2] # Odd weights weight_dict[1] = [w for w in weights if not w % 2] # Even weights try: N = chi.modulus() except AttributeError: if chi.parent() == ZZ: N = chi chi = DirichletGroup(N)[0] Id = DirichletGroup(1)[0] if chi(-1) != (-1)**k: raise ValueError('chi(-1)!=(-1)^k') sturm = ModularForms(N, k).sturm_bound() + 1 if N > 1: target_dim = dimension_modular_forms(chi, k) else: target_dim = dimension_modular_forms(1, k) D = DirichletGroup(N) # product_space should ideally be called over number fields. Over complex # numbers the exact linear algebra solutions might not exist. if base_ring == None: base_ring = CyclotomicField(euler_phi(N)) Q = PowerSeriesRing(base_ring, 'q') q = Q.gen() d = len(D) prim_chars = [phi.primitive_character() for phi in D] divs = divisors(N) products = Matrix(base_ring, []) indexlist = [] rank = 0 if verbose: print(D) print('Sturm bound', sturm) #TODO: target_dim needs refinment in the case of weight 2. print('Target dimension', target_dim) for i in srange(0, d): # First character phi = prim_chars[i] M1 = phi.conductor() for j in srange(0, d): # Second character psi = prim_chars[j] M2 = psi.conductor() if not M1 * M2 in divs: continue parity = psi(-1) * phi(-1) for t1 in divs: if not M1 * M2 * t1 in divs: continue #TODO: THE NEXT CONDITION NEEDS TO BE CORRECTED. THIS IS JUST A TEST if phi.bar() == psi and not ( k == 2): #and i==0 and j==0 and t1==1): E = eisenstein_series_at_inf(phi, psi, k, sturm, t1, base_ring).padded_list() try: products.T.solve_right(vector(base_ring, E)) except ValueError: products = Matrix(products.rows() + [E]) indexlist.append([k, i, j, t1]) rank += 1 if verbose: print('Added ', [k, i, j, t1]) print('Rank is now', rank) if rank == target_dim: return products, indexlist for t in divs: if not M1 * M2 * t1 * t in divs: continue for t2 in divs: if not M1 * M2 * t1 * t2 * t in divs: continue for l in weight_dict[parity]: if l == 1 and phi.is_odd(): continue if i == 0 and j == 0 and (l == 2 or l == k - 2): continue #TODO: THE NEXT CONDITION NEEDS TO BE REMOVED. THIS IS JUST A TEST if l == 2 or l == k - 2: continue E1 = eisenstein_series_at_inf( phi, psi, l, sturm, t1 * t, base_ring) E2 = eisenstein_series_at_inf( phi**(-1), psi**(-1), k - l, sturm, t2 * t, base_ring) #If chi is non-principal this needs to be changed to be something like chi*phi^(-1) instead of phi^(-1) E = (E1 * E2 + O(q**sturm)).padded_list() try: products.T.solve_right(vector(base_ring, E)) except ValueError: products = Matrix(products.rows() + [E]) indexlist.append([l, k - l, i, j, t1, t2, t]) rank += 1 if verbose: print('Added ', [l, k - l, i, j, t1, t2, t]) print('Rank', rank) if rank == target_dim: return products, indexlist return products, indexlist
def slider(vmin, vmax=None, step_size=None, default=None, label=None, display_value=True, _range=False): """ A slider widget. INPUT: For a numeric slider (select a value from a range): - ``vmin``, ``vmax`` -- minimum and maximum value - ``step_size`` -- the step size For a selection slider (select a value from a list of values): - ``vmin`` -- a list of possible values for the slider For all sliders: - ``default`` -- initial value - ``label`` -- optional label - ``display_value`` -- (boolean) if ``True``, display the current value. EXAMPLES:: sage: from sage.repl.ipython_kernel.all_jupyter import slider sage: slider(5, label="slide me") TransformIntSlider(value=5, description=u'slide me', min=5) sage: slider(5, 20) TransformIntSlider(value=5, max=20, min=5) sage: slider(5, 20, 0.5) TransformFloatSlider(value=5.0, max=20.0, min=5.0, step=0.5) sage: slider(5, 20, default=12) TransformIntSlider(value=12, max=20, min=5) The parent of the inputs determines the parent of the value:: sage: w = slider(5); w TransformIntSlider(value=5, min=5) sage: parent(w.get_interact_value()) Integer Ring sage: w = slider(int(5)); w IntSlider(value=5, min=5) sage: parent(w.get_interact_value()) <... 'int'> sage: w = slider(5, 20, step_size=RDF("0.1")); w TransformFloatSlider(value=5.0, max=20.0, min=5.0) sage: parent(w.get_interact_value()) Real Double Field sage: w = slider(5, 20, step_size=10/3); w SelectionSlider(index=2, options=(5, 25/3, 35/3, 15, 55/3), value=35/3) sage: parent(w.get_interact_value()) Rational Field Symbolic input is evaluated numerically:: sage: w = slider(e, pi); w TransformFloatSlider(value=2.718281828459045, max=3.141592653589793, min=2.718281828459045) sage: parent(w.get_interact_value()) Real Field with 53 bits of precision For a selection slider, the default is adjusted to one of the possible values:: sage: slider(range(10), default=17/10) SelectionSlider(index=2, options=(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), value=2) TESTS:: sage: slider(range(5), range(5)) Traceback (most recent call last): ... TypeError: unexpected argument 'vmax' for a selection slider sage: slider(range(5), step_size=2) Traceback (most recent call last): ... TypeError: unexpected argument 'step_size' for a selection slider sage: slider(5).readout True sage: slider(5, display_value=False).readout False """ kwds = {"readout": display_value} if label: kwds["description"] = u(label) # If vmin is iterable, return a SelectionSlider if isinstance(vmin, Iterable): if vmax is not None: raise TypeError( "unexpected argument 'vmax' for a selection slider") if step_size is not None: raise TypeError( "unexpected argument 'step_size' for a selection slider") if _range: # https://github.com/ipython/ipywidgets/issues/760 raise NotImplementedError( "range_slider does not support a list of values") options = list(vmin) # Find default in options def err(v): if v is default: return (-1, 0) try: if v == default: return (0, 0) return (0, abs(v - default)) except Exception: return (1, 0) kwds["options"] = options if default is not None: kwds["value"] = min(options, key=err) return SelectionSlider(**kwds) if default is not None: kwds["value"] = default # Sum all input numbers to figure out type/parent p = parent(sum(x for x in (vmin, vmax, step_size) if x is not None)) # Change SR to RR if p is SR: p = RR # Convert all inputs to the common parent if vmin is not None: vmin = p(vmin) if vmax is not None: vmax = p(vmax) if step_size is not None: step_size = p(step_size) def tuple_elements_p(t): "Convert all entries of the tuple `t` to `p`" return tuple(p(x) for x in t) zero = p() if isinstance(zero, Integral): if p is int: if _range: cls = IntRangeSlider else: cls = IntSlider else: if _range: kwds["transform"] = tuple_elements_p cls = TransformIntRangeSlider else: kwds["transform"] = p cls = TransformIntSlider elif isinstance(zero, Rational): # Rational => implement as SelectionSlider if _range: # https://github.com/ipython/ipywidgets/issues/760 raise NotImplementedError( "range_slider does not support rational numbers") vmin, vmax, value = _get_min_max_value(vmin, vmax, default, step_size) kwds["value"] = value kwds["options"] = srange(vmin, vmax, step_size, include_endpoint=True) return SelectionSlider(**kwds) elif isinstance(zero, Real): if p is float: if _range: cls = FloatRangeSlider else: cls = FloatSlider else: if _range: kwds["transform"] = tuple_elements_p cls = TransformFloatRangeSlider else: kwds["transform"] = p cls = TransformFloatSlider else: raise TypeError("unknown parent {!r} for slider".format(p)) kwds["min"] = vmin if vmax is not None: kwds["max"] = vmax if step_size is not None: kwds["step"] = step_size return cls(**kwds)
def _Omega_numerator_P_(a, x, y, t): r""" Helper function for :func:`_Omega_numerator_`. This is an implementation of the function `P` of [APR2001]_. INPUT: - ``a`` -- an integer - ``x`` and ``y`` -- a tuple of Laurent polynomials The tuple ``x`` here is the flattened ``x`` of :func:`_Omega_numerator_` but without its last entry. - ``t`` -- a temporary Laurent polynomial variable In the (final) result, ``t`` has to be substituted by the last entry of the flattened ``x`` of :func:`_Omega_numerator_`. OUTPUT: A Laurent polynomial TESTS:: sage: from sage.rings.polynomial.omega import _Omega_numerator_P_ sage: L.<x0, x1, y0, y1, t> = LaurentPolynomialRing(ZZ) sage: _Omega_numerator_P_(0, (x0,), (y0,), t).subs({t: x1}) -x0*x1*y0 + 1 """ # This function takes Laurent polynomials as inputs. It would # be possible to input only the sizes of ``x`` and ``y`` and # perform a substitution afterwards; in this way caching of this # function would make sense. However, the way it is now allows # automatic collection and simplification of the summands, which # makes it more efficient for higher powers at the input of # :func:`Omega_ge`. # Caching occurs in :func:`Omega_ge`. import logging logger = logging.getLogger(__name__) from sage.arith.srange import srange from sage.misc.misc_c import prod n = len(x) if n == 0: x0 = t result = x0**(-a) + \ (prod(1 - x0*yy for yy in y) * sum(homogenous_symmetric_function(j, y) * (1-x0**(j-a)) for j in srange(a)) if a > 0 else 0) else: Pprev = _Omega_numerator_P_(a, x[:n - 1], y, t) x2 = x[n - 1] logger.debug('Omega_numerator: P(%s): substituting...', n) x1 = t p1 = Pprev p2 = Pprev.subs({t: x2}) logger.debug('Omega_numerator: P(%s): preparing...', n) dividend = x1 * (1-x2) * prod(1 - x2*yy for yy in y) * p1 - \ x2 * (1-x1) * prod(1 - x1*yy for yy in y) * p2 logger.debug('Omega_numerator: P(%s): dividing...', n) q, r = dividend.quo_rem(x1 - x2) assert r == 0 result = q logger.debug('Omega_numerator: P(%s) has %s terms', n, result.number_of_terms()) return result
def _parametric_plot3d_surface(f, urange, vrange, plot_points, boundary_style, **kwds): r""" Return a parametric three-dimensional space surface. This function is used internally by the :func:`parametric_plot3d` command. There are two ways this function is invoked by :func:`parametric_plot3d`. - ``parametric_plot3d([f_x, f_y, f_z], (u_min, u_max), (v_min, v_max))``: `f_x, f_y, f_z` are each functions of two variables - ``parametric_plot3d([f_x, f_y, f_z], (u, u_min, u_max), (v, v_min, v_max))``: `f_x, f_y, f_z` can be viewed as functions of `u` and `v` INPUT: - ``f`` - a 3-tuple of functions or expressions, or vector of size 3 - ``urange`` - a 2-tuple (u_min, u_max) or a 3-tuple (u, u_min, u_max) - ``vrange`` - a 2-tuple (v_min, v_max) or a 3-tuple (v, v_min, v_max) - ``plot_points`` - (default: "automatic", which is [40,40] for surfaces) initial number of sample points in each parameter; a pair of integers. - ``boundary_style`` - (default: None, no boundary) a dict that describes how to draw the boundaries of regions by giving options that are passed to the line3d command. EXAMPLES: We demonstrate each of the two ways of calling this. See :func:`parametric_plot3d` for many more examples. We do the first one with lambda functions:: sage: f = (lambda u,v: cos(u), lambda u,v: sin(u)+cos(v), lambda u,v: sin(v)) sage: parametric_plot3d(f, (0, 2*pi), (-pi, pi)) # indirect doctest Graphics3d Object Now we do the same thing with symbolic expressions:: sage: u, v = var('u,v') sage: parametric_plot3d((cos(u), sin(u) + cos(v), sin(v)), (u, 0, 2*pi), (v, -pi, pi), mesh=True) Graphics3d Object """ from sage.plot.misc import setup_for_eval_on_grid g, ranges = setup_for_eval_on_grid(f, [urange, vrange], plot_points) urange = srange(*ranges[0], include_endpoint=True) vrange = srange(*ranges[1], include_endpoint=True) G = ParametricSurface(g, (urange, vrange), **kwds) if boundary_style is not None: for u in (urange[0], urange[-1]): G += line3d([(g[0](u, v), g[1](u, v), g[2](u, v)) for v in vrange], **boundary_style) for v in (vrange[0], vrange[-1]): G += line3d([(g[0](u, v), g[1](u, v), g[2](u, v)) for u in urange], **boundary_style) return G
def QuadraticResidueCodeEvenPair(n, F): """ Quadratic residue codes of a given odd prime length and base ring either don't exist at all or occur as 4-tuples - a pair of "odd-like" codes and a pair of "even-like" codes. If `n > 2` is prime then (Theorem 6.6.2 in [HP2003]_) a QR code exists over `GF(q)` iff q is a quadratic residue mod `n`. They are constructed as "even-like" duadic codes associated the splitting (Q,N) mod n, where Q is the set of non-zero quadratic residues and N is the non-residues. EXAMPLES:: sage: codes.QuadraticResidueCodeEvenPair(17, GF(13)) # known bug (#25896) ([17, 8] Cyclic Code over GF(13), [17, 8] Cyclic Code over GF(13)) sage: codes.QuadraticResidueCodeEvenPair(17, GF(2)) ([17, 8] Cyclic Code over GF(2), [17, 8] Cyclic Code over GF(2)) sage: codes.QuadraticResidueCodeEvenPair(13,GF(9,"z")) # known bug (#25896) ([13, 6] Cyclic Code over GF(9), [13, 6] Cyclic Code over GF(9)) sage: C1,C2 = codes.QuadraticResidueCodeEvenPair(7,GF(2)) sage: C1.is_self_orthogonal() True sage: C2.is_self_orthogonal() True sage: C3 = codes.QuadraticResidueCodeOddPair(17,GF(2))[0] sage: C4 = codes.QuadraticResidueCodeEvenPair(17,GF(2))[1] sage: C3.systematic_generator_matrix() == C4.dual_code().systematic_generator_matrix() True This is consistent with Theorem 6.6.9 and Exercise 365 in [HP2003]_. TESTS:: sage: codes.QuadraticResidueCodeEvenPair(14,Zmod(4)) Traceback (most recent call last): ... ValueError: the argument F must be a finite field sage: codes.QuadraticResidueCodeEvenPair(14,GF(2)) Traceback (most recent call last): ... ValueError: the argument n must be an odd prime sage: codes.QuadraticResidueCodeEvenPair(5,GF(2)) Traceback (most recent call last): ... ValueError: the order of the finite field must be a quadratic residue modulo n """ from sage.arith.srange import srange from sage.categories.finite_fields import FiniteFields if F not in FiniteFields(): raise ValueError("the argument F must be a finite field") q = F.order() n = Integer(n) if n <= 2 or not n.is_prime(): raise ValueError("the argument n must be an odd prime") Q = quadratic_residues(n) Q.remove(0) # non-zero quad residues N = [x for x in srange(1, n) if x not in Q] # non-zero quad non-residues if q not in Q: raise ValueError( "the order of the finite field must be a quadratic residue modulo n" ) return DuadicCodeEvenPair(F, Q, N)
def Krawtchouk(n, q, l, x, check=True): """ Compute ``K^{n,q}_l(x)``, the Krawtchouk polynomial. See :wikipedia:`Kravchuk_polynomials`; It is defined by the generating function `(1+(q-1)z)^{n-x}(1-z)^x=\sum_{l} K^{n,q}_l(x)z^l` and is equal to .. math:: K^{n,q}_l(x)=\sum_{j=0}^l (-1)^j(q-1)^{(l-j)}{x \choose j}{n-x \choose l-j}, INPUT: - ``n, q, x`` -- arbitrary numbers - ``l`` -- a nonnegative integer - ``check`` -- check the input for correctness. ``True`` by default. Otherwise, pass it as it is. Use ``check=False`` at your own risk. EXAMPLES:: sage: Krawtchouk(24,2,5,4) 2224 sage: Krawtchouk(12300,4,5,6) 567785569973042442072 TESTS: check that the bug reported on :trac:`19561` is fixed:: sage: Krawtchouk(3,2,3,3) -1 sage: Krawtchouk(int(3),int(2),int(3),int(3)) -1 sage: Krawtchouk(int(3),int(2),int(3),int(3),check=False) -5 other unusual inputs :: sage: Krawtchouk(sqrt(5),1-I*sqrt(3),3,55.3).n() 211295.892797... + 1186.42763...*I sage: Krawtchouk(-5/2,7*I,3,-1/10) 480053/250*I - 357231/400 sage: Krawtchouk(1,1,-1,1) Traceback (most recent call last): ... ValueError: l must be a nonnegative integer sage: Krawtchouk(1,1,3/2,1) Traceback (most recent call last): ... TypeError: no conversion of this rational to integer """ from sage.arith.all import binomial from sage.arith.srange import srange # Use the expression in equation (55) of MacWilliams & Sloane, pg 151 # We write jth term = some_factor * (j-1)th term if check: from sage.rings.integer_ring import ZZ l0 = ZZ(l) if l0 != l or l0 < 0: raise ValueError('l must be a nonnegative integer') l = l0 kraw = jth_term = (q - 1)**l * binomial(n, l) # j=0 for j in srange(1, l + 1): jth_term *= -q * (l - j + 1) * (x - j + 1) / ((q - 1) * j * (n - j + 1)) kraw += jth_term return kraw
def QuadraticResidueCodeEvenPair(n,F): """ Quadratic residue codes of a given odd prime length and base ring either don't exist at all or occur as 4-tuples - a pair of "odd-like" codes and a pair of "even-like" codes. If `n > 2` is prime then (Theorem 6.6.2 in [HP2003]_) a QR code exists over `GF(q)` iff q is a quadratic residue mod `n`. They are constructed as "even-like" duadic codes associated the splitting (Q,N) mod n, where Q is the set of non-zero quadratic residues and N is the non-residues. EXAMPLES:: sage: codes.QuadraticResidueCodeEvenPair(17, GF(13)) ([17, 8] Cyclic Code over GF(13), [17, 8] Cyclic Code over GF(13)) sage: codes.QuadraticResidueCodeEvenPair(17, GF(2)) ([17, 8] Cyclic Code over GF(2), [17, 8] Cyclic Code over GF(2)) sage: codes.QuadraticResidueCodeEvenPair(13,GF(9,"z")) ([13, 6] Cyclic Code over GF(9), [13, 6] Cyclic Code over GF(9)) sage: C1,C2 = codes.QuadraticResidueCodeEvenPair(7,GF(2)) sage: C1.is_self_orthogonal() True sage: C2.is_self_orthogonal() True sage: C3 = codes.QuadraticResidueCodeOddPair(17,GF(2))[0] sage: C4 = codes.QuadraticResidueCodeEvenPair(17,GF(2))[1] sage: C3.systematic_generator_matrix() == C4.dual_code().systematic_generator_matrix() True This is consistent with Theorem 6.6.9 and Exercise 365 in [HP2003]_. TESTS:: sage: codes.QuadraticResidueCodeEvenPair(14,Zmod(4)) Traceback (most recent call last): ... ValueError: the argument F must be a finite field sage: codes.QuadraticResidueCodeEvenPair(14,GF(2)) Traceback (most recent call last): ... ValueError: the argument n must be an odd prime sage: codes.QuadraticResidueCodeEvenPair(5,GF(2)) Traceback (most recent call last): ... ValueError: the order of the finite field must be a quadratic residue modulo n """ from sage.arith.srange import srange from sage.categories.finite_fields import FiniteFields if F not in FiniteFields(): raise ValueError("the argument F must be a finite field") q = F.order() n = Integer(n) if n <= 2 or not n.is_prime(): raise ValueError("the argument n must be an odd prime") Q = quadratic_residues(n); Q.remove(0) # non-zero quad residues N = [x for x in srange(1,n) if x not in Q] # non-zero quad non-residues if q not in Q: raise ValueError("the order of the finite field must be a quadratic residue modulo n") return DuadicCodeEvenPair(F,Q,N)
def ruler(start, end, ticks=4, sub_ticks=4, absolute=False, snap=False, **kwds): """ Draw a ruler in 3-D, with major and minor ticks. INPUT: - ``start`` -- the beginning of the ruler, as a list, tuple, or vector. - ``end`` -- the end of the ruler, as a list, tuple, or vector. - ``ticks`` -- (default: 4) the number of major ticks shown on the ruler. - ``sub_ticks`` -- (default: 4) the number of shown subdivisions between each major tick. - ``absolute`` -- (default: ``False``) if ``True``, makes a huge ruler in the direction of an axis. - ``snap`` -- (default: ``False``) if ``True``, snaps to an implied grid. Type ``line3d.options`` for a dictionary of the default options for lines, which are also available. EXAMPLES: A ruler:: sage: from sage.plot.plot3d.shapes2 import ruler sage: R = ruler([1,2,3],vector([2,3,4])); R Graphics3d Object A ruler with some options:: sage: R = ruler([1,2,3],vector([2,3,4]),ticks=6, sub_ticks=2, color='red'); R Graphics3d Object The keyword ``snap`` makes the ticks not necessarily coincide with the ruler:: sage: ruler([1,2,3],vector([1,2,4]),snap=True) Graphics3d Object The keyword ``absolute`` makes a huge ruler in one of the axis directions:: sage: ruler([1,2,3],vector([1,2,4]),absolute=True) Graphics3d Object TESTS:: sage: ruler([1,2,3],vector([1,3,4]),absolute=True) Traceback (most recent call last): ... ValueError: Absolute rulers only valid for axis-aligned paths """ start = vector(RDF, start) end = vector(RDF, end) dir = end - start dist = math.sqrt(dir.dot_product(dir)) dir /= dist one_tick = dist/ticks * 1.414 unit = 10 ** math.floor(math.log(dist/ticks, 10)) if unit * 5 < one_tick: unit *= 5 elif unit * 2 < one_tick: unit *= 2 if dir[0]: tick = dir.cross_product(vector(RDF, (0,0,-dist/30))) elif dir[1]: tick = dir.cross_product(vector(RDF, (0,0,dist/30))) else: tick = vector(RDF, (dist/30,0,0)) if snap: for i in range(3): start[i] = unit * math.floor(start[i]/unit + 1e-5) end[i] = unit * math.ceil(end[i]/unit - 1e-5) if absolute: if dir[0]*dir[1] or dir[1]*dir[2] or dir[0]*dir[2]: raise ValueError("Absolute rulers only valid for axis-aligned paths") m = max(dir[0], dir[1], dir[2]) if dir[0] == m: off = start[0] elif dir[1] == m: off = start[1] else: off = start[2] first_tick = unit * math.ceil(off/unit - 1e-5) - off else: off = 0 first_tick = 0 ruler = shapes.LineSegment(start, end, **kwds) for k in range(1, int(sub_ticks * first_tick/unit)): P = start + dir*(k*unit/sub_ticks) ruler += shapes.LineSegment(P, P + tick/2, **kwds) for d in srange(first_tick, dist + unit/(sub_ticks+1), unit): P = start + dir*d ruler += shapes.LineSegment(P, P + tick, **kwds) ruler += shapes.Text(str(d+off), **kwds).translate(P - tick) if dist - d < unit: sub_ticks = int(sub_ticks * (dist - d)/unit) for k in range(1, sub_ticks): P += dir * (unit/sub_ticks) ruler += shapes.LineSegment(P, P + tick/2, **kwds) return ruler
def Omega_ge(a, exponents): r""" Return `\Omega_{\ge}` of the expression specified by the input. To be more precise, calculate .. MATH:: \Omega_{\ge} \frac{\mu^a}{ (1 - z_0 \mu^{e_0}) \dots (1 - z_{n-1} \mu^{e_{n-1}})} and return its numerator and a factorization of its denominator. Note that `z_0`, ..., `z_{n-1}` only appear in the output, but not in the input. INPUT: - ``a`` -- an integer - ``exponents`` -- a tuple of integers OUTPUT: A pair representing a quotient as follows: Its first component is the numerator as a Laurent polynomial, its second component a factorization of the denominator as a tuple of Laurent polynomials, where each Laurent polynomial `z` represents a factor `1 - z`. The parents of these Laurent polynomials is always a Laurent polynomial ring in `z_0`, ..., `z_{n-1}` over `\ZZ`, where `n` is the length of ``exponents``. EXAMPLES:: sage: from sage.rings.polynomial.omega import Omega_ge sage: Omega_ge(0, (1, -2)) (1, (z0, z0^2*z1)) sage: Omega_ge(0, (1, -3)) (1, (z0, z0^3*z1)) sage: Omega_ge(0, (1, -4)) (1, (z0, z0^4*z1)) sage: Omega_ge(0, (2, -1)) (z0*z1 + 1, (z0, z0*z1^2)) sage: Omega_ge(0, (3, -1)) (z0*z1^2 + z0*z1 + 1, (z0, z0*z1^3)) sage: Omega_ge(0, (4, -1)) (z0*z1^3 + z0*z1^2 + z0*z1 + 1, (z0, z0*z1^4)) sage: Omega_ge(0, (1, 1, -2)) (-z0^2*z1*z2 - z0*z1^2*z2 + z0*z1*z2 + 1, (z0, z1, z0^2*z2, z1^2*z2)) sage: Omega_ge(0, (2, -1, -1)) (z0*z1*z2 + z0*z1 + z0*z2 + 1, (z0, z0*z1^2, z0*z2^2)) sage: Omega_ge(0, (2, 1, -1)) (-z0*z1*z2^2 - z0*z1*z2 + z0*z2 + 1, (z0, z1, z0*z2^2, z1*z2)) :: sage: Omega_ge(0, (2, -2)) (-z0*z1 + 1, (z0, z0*z1, z0*z1)) sage: Omega_ge(0, (2, -3)) (z0^2*z1 + 1, (z0, z0^3*z1^2)) sage: Omega_ge(0, (3, 1, -3)) (-z0^3*z1^3*z2^3 + 2*z0^2*z1^3*z2^2 - z0*z1^3*z2 + z0^2*z2^2 - 2*z0*z2 + 1, (z0, z1, z0*z2, z0*z2, z0*z2, z1^3*z2)) :: sage: Omega_ge(0, (3, 6, -1)) (-z0*z1*z2^8 - z0*z1*z2^7 - z0*z1*z2^6 - z0*z1*z2^5 - z0*z1*z2^4 + z1*z2^5 - z0*z1*z2^3 + z1*z2^4 - z0*z1*z2^2 + z1*z2^3 - z0*z1*z2 + z0*z2^2 + z1*z2^2 + z0*z2 + z1*z2 + 1, (z0, z1, z0*z2^3, z1*z2^6)) TESTS:: sage: Omega_ge(0, (2, 2, 1, 1, 1, 1, 1, -1, -1))[0].number_of_terms() # long time 27837 :: sage: Omega_ge(1, (2,)) (1, (z0,)) """ import logging logger = logging.getLogger(__name__) logger.info('Omega_ge: a=%s, exponents=%s', a, exponents) from sage.arith.misc import lcm from sage.arith.srange import srange from sage.misc.misc_c import prod from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.number_field.number_field import CyclotomicField if not exponents or any(e == 0 for e in exponents): raise NotImplementedError rou = sorted(set(abs(e) for e in exponents) - set([1])) ellcm = lcm(rou) B = CyclotomicField(ellcm, 'zeta') zeta = B.gen() z_names = tuple('z{}'.format(i) for i in range(len(exponents))) L = LaurentPolynomialRing(B, ('t', ) + z_names, len(z_names) + 1) t = L.gens()[0] Z = LaurentPolynomialRing(ZZ, z_names, len(z_names)) powers = {i: L(zeta**(ellcm // i)) for i in rou} powers[2] = L(-1) powers[1] = L(1) exponents_and_values = tuple( (e, tuple(powers[abs(e)]**j * z for j in srange(abs(e)))) for z, e in zip(L.gens()[1:], exponents)) x = tuple(v for e, v in exponents_and_values if e > 0) y = tuple(v for e, v in exponents_and_values if e < 0) def subs_power(expression, var, exponent): r""" Substitute ``var^exponent`` by ``var`` in ``expression``. It is assumed that ``var`` only occurs with exponents divisible by ``exponent``. """ p = tuple(var.dict().popitem()[0]).index( 1) # var is the p-th generator def subs_e(e): e = list(e) assert e[p] % exponent == 0 e[p] = e[p] // exponent return tuple(e) parent = expression.parent() result = parent( {subs_e(e): c for e, c in iteritems(expression.dict())}) return result def de_power(expression): expression = Z(expression) for e, var in zip(exponents, Z.gens()): if abs(e) == 1: continue expression = subs_power(expression, var, abs(e)) return expression logger.debug('Omega_ge: preparing denominator') factors_denominator = tuple( de_power(1 - factor) for factor in _Omega_factors_denominator_(x, y)) logger.debug('Omega_ge: preparing numerator') numerator = de_power(_Omega_numerator_(a, x, y, t)) logger.info('Omega_ge: completed') return numerator, factors_denominator
def plot_vector_field3d(functions, xrange, yrange, zrange, plot_points=5, colors='jet', center_arrows=False,**kwds): r""" Plot a 3d vector field INPUT: - ``functions`` - a list of three functions, representing the x-, y-, and z-coordinates of a vector - ``xrange``, ``yrange``, and ``zrange`` - three tuples of the form (var, start, stop), giving the variables and ranges for each axis - ``plot_points`` (default 5) - either a number or list of three numbers, specifying how many points to plot for each axis - ``colors`` (default 'jet') - a color, list of colors (which are interpolated between), or matplotlib colormap name, giving the coloring of the arrows. If a list of colors or a colormap is given, coloring is done as a function of length of the vector - ``center_arrows`` (default False) - If True, draw the arrows centered on the points; otherwise, draw the arrows with the tail at the point - any other keywords are passed on to the plot command for each arrow EXAMPLES:: sage: x,y,z=var('x y z') sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi)) Graphics3d Object sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),colors=['red','green','blue']) Graphics3d Object sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),colors='red') Graphics3d Object sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),plot_points=4) Graphics3d Object sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),plot_points=[3,5,7]) Graphics3d Object sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),center_arrows=True) Graphics3d Object TESTS: This tests that :trac:`2100` is fixed in a way compatible with this command:: sage: plot_vector_field3d((x*cos(z),-y*cos(z),sin(z)), (x,0,pi), (y,0,pi), (z,0,pi),center_arrows=True,aspect_ratio=(1,2,1)) Graphics3d Object """ (ff,gg,hh), ranges = setup_for_eval_on_grid(functions, [xrange, yrange, zrange], plot_points) xpoints, ypoints, zpoints = [srange(*r, include_endpoint=True) for r in ranges] points = [vector((i,j,k)) for i in xpoints for j in ypoints for k in zpoints] vectors = [vector((ff(*point), gg(*point), hh(*point))) for point in points] try: from matplotlib.cm import get_cmap cm = get_cmap(colors) except (TypeError, ValueError): cm = None if cm is None: if isinstance(colors, (list, tuple)): from matplotlib.colors import LinearSegmentedColormap cm = LinearSegmentedColormap.from_list('mymap',colors) else: cm = lambda x: colors max_len = max(v.norm() for v in vectors) scaled_vectors = [v/max_len for v in vectors] if center_arrows: return sum([plot(v,color=cm(v.norm()),**kwds).translate(p-v/2) for v,p in zip(scaled_vectors, points)]) else: return sum([plot(v,color=cm(v.norm()),**kwds).translate(p) for v,p in zip(scaled_vectors, points)])
def HarmonicNumber(var, precision=None, skip_constant_summand=False): r""" Return the asymptotic expansion of a harmonic number. INPUT: - ``var`` -- a string for the variable name. - ``precision`` -- (default: ``None``) an integer. If ``None``, then the default precision of the asymptotic ring is used. - ``skip_constant_summand`` -- (default: ``False``) a boolean. If set, then the constant summand ``euler_gamma`` is left out. As a consequence, the coefficient ring of the output changes from ``Symbolic Constants Subring`` (if ``False``) to ``Rational Field`` (if ``True``). OUTPUT: An asymptotic expansion. EXAMPLES:: sage: asymptotic_expansions.HarmonicNumber('n', precision=5) log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4) + O(n^(-6)) TESTS:: sage: ex = asymptotic_expansions.HarmonicNumber('n', precision=5) sage: n = ex.parent().gen() sage: ex.compare_with_values(n, # rel tol 1e-6 ....: lambda x: sum(1/k for k in srange(1, x+1)), [5, 10, 20]) [(5, 0.0038125360?), (10, 0.00392733?), (20, 0.0039579?)] sage: asymptotic_expansions.HarmonicNumber('n') log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4) - 1/252*n^(-6) + 1/240*n^(-8) - 1/132*n^(-10) + 691/32760*n^(-12) - 1/12*n^(-14) + 3617/8160*n^(-16) - 43867/14364*n^(-18) + 174611/6600*n^(-20) - 77683/276*n^(-22) + 236364091/65520*n^(-24) - 657931/12*n^(-26) + 3392780147/3480*n^(-28) - 1723168255201/85932*n^(-30) + 7709321041217/16320*n^(-32) - 151628697551/12*n^(-34) + O(n^(-36)) sage: _.parent() Asymptotic Ring <n^ZZ * log(n)^ZZ> over Symbolic Constants Subring :: sage: asymptotic_expansions.HarmonicNumber( ....: 'n', precision=5, skip_constant_summand=True) log(n) + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4) + O(n^(-6)) sage: _.parent() Asymptotic Ring <n^ZZ * log(n)^ZZ> over Rational Field sage: for p in range(5): ....: print asymptotic_expansions.HarmonicNumber( ....: 'n', precision=p) O(log(n)) log(n) + O(1) log(n) + euler_gamma + O(n^(-1)) log(n) + euler_gamma + 1/2*n^(-1) + O(n^(-2)) log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + O(n^(-4)) sage: asymptotic_expansions.HarmonicNumber('m', precision=5) log(m) + euler_gamma + 1/2*m^(-1) - 1/12*m^(-2) + 1/120*m^(-4) + O(m^(-6)) """ if not skip_constant_summand: from sage.symbolic.ring import SR coefficient_ring = SR.subring(no_variables=True) else: from sage.rings.rational_field import QQ coefficient_ring = QQ from asymptotic_ring import AsymptoticRing A = AsymptoticRing(growth_group='{n}^ZZ * log({n})^ZZ'.format(n=var), coefficient_ring=coefficient_ring) n = A.gen() if precision is None: precision = A.default_prec from sage.functions.log import log result = A.zero() if precision >= 1: result += log(n) if precision >= 2 and not skip_constant_summand: from sage.symbolic.constants import euler_gamma result += coefficient_ring(euler_gamma) if precision >= 3: result += 1 / (2 * n) from sage.arith.srange import srange from sage.arith.all import bernoulli for k in srange(2, 2*precision - 4, 2): result += -bernoulli(k) / k / n**k if precision < 1: result += (log(n)).O() elif precision == 1: result += A(1).O() elif precision == 2: result += (1 / n).O() else: result += (1 / n**(2*precision - 4)).O() return result
def Krawtchouk(n,q,l,x,check=True): """ Compute ``K^{n,q}_l(x)``, the Krawtchouk (a.k.a. Kravchuk) polynomial. See :wikipedia:`Kravchuk_polynomials`; It is defined by the generating function `(1+(q-1)z)^{n-x}(1-z)^x=\sum_{l} K^{n,q}_l(x)z^l` and is equal to .. math:: K^{n,q}_l(x)=\sum_{j=0}^l (-1)^j(q-1)^{(l-j)}{x \choose j}{n-x \choose l-j}, INPUT: - ``n, q, x`` -- arbitrary numbers - ``l`` -- a nonnegative integer - ``check`` -- check the input for correctness. ``True`` by default. Otherwise, pass it as it is. Use ``check=False`` at your own risk. EXAMPLES:: sage: Krawtchouk(24,2,5,4) 2224 sage: Krawtchouk(12300,4,5,6) 567785569973042442072 TESTS: check that the bug reported on :trac:`19561` is fixed:: sage: Krawtchouk(3,2,3,3) -1 sage: Krawtchouk(int(3),int(2),int(3),int(3)) -1 sage: Krawtchouk(int(3),int(2),int(3),int(3),check=False) -5 sage: Kravchuk(24,2,5,4) 2224 other unusual inputs :: sage: Krawtchouk(sqrt(5),1-I*sqrt(3),3,55.3).n() 211295.892797... + 1186.42763...*I sage: Krawtchouk(-5/2,7*I,3,-1/10) 480053/250*I - 357231/400 sage: Krawtchouk(1,1,-1,1) Traceback (most recent call last): ... ValueError: l must be a nonnegative integer sage: Krawtchouk(1,1,3/2,1) Traceback (most recent call last): ... TypeError: no conversion of this rational to integer """ from sage.arith.all import binomial from sage.arith.srange import srange # Use the expression in equation (55) of MacWilliams & Sloane, pg 151 # We write jth term = some_factor * (j-1)th term if check: from sage.rings.integer_ring import ZZ l0 = ZZ(l) if l0 != l or l0<0: raise ValueError('l must be a nonnegative integer') l = l0 kraw = jth_term = (q-1)**l * binomial(n, l) # j=0 for j in srange(1,l+1): jth_term *= -q*(l-j+1)*(x-j+1)/((q-1)*j*(n-j+1)) kraw += jth_term return kraw
def HarmonicNumber(var, precision=None, skip_constant_summand=False): r""" Return the asymptotic expansion of a harmonic number. INPUT: - ``var`` -- a string for the variable name. - ``precision`` -- (default: ``None``) an integer. If ``None``, then the default precision of the asymptotic ring is used. - ``skip_constant_summand`` -- (default: ``False``) a boolean. If set, then the constant summand ``euler_gamma`` is left out. As a consequence, the coefficient ring of the output changes from ``Symbolic Constants Subring`` (if ``False``) to ``Rational Field`` (if ``True``). OUTPUT: An asymptotic expansion. EXAMPLES:: sage: asymptotic_expansions.HarmonicNumber('n', precision=5) log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4) + O(n^(-6)) TESTS:: sage: ex = asymptotic_expansions.HarmonicNumber('n', precision=5) sage: n = ex.parent().gen() sage: ex.compare_with_values(n, # rel tol 1e-6 ....: lambda x: sum(1/k for k in srange(1, x+1)), [5, 10, 20]) [(5, 0.0038125360?), (10, 0.00392733?), (20, 0.0039579?)] sage: asymptotic_expansions.HarmonicNumber('n') log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4) - 1/252*n^(-6) + 1/240*n^(-8) - 1/132*n^(-10) + 691/32760*n^(-12) - 1/12*n^(-14) + 3617/8160*n^(-16) - 43867/14364*n^(-18) + 174611/6600*n^(-20) - 77683/276*n^(-22) + 236364091/65520*n^(-24) - 657931/12*n^(-26) + 3392780147/3480*n^(-28) - 1723168255201/85932*n^(-30) + 7709321041217/16320*n^(-32) - 151628697551/12*n^(-34) + O(n^(-36)) sage: _.parent() Asymptotic Ring <n^ZZ * log(n)^ZZ> over Symbolic Constants Subring :: sage: asymptotic_expansions.HarmonicNumber( ....: 'n', precision=5, skip_constant_summand=True) log(n) + 1/2*n^(-1) - 1/12*n^(-2) + 1/120*n^(-4) + O(n^(-6)) sage: _.parent() Asymptotic Ring <n^ZZ * log(n)^ZZ> over Rational Field sage: for p in range(5): ....: print asymptotic_expansions.HarmonicNumber( ....: 'n', precision=p) O(log(n)) log(n) + O(1) log(n) + euler_gamma + O(n^(-1)) log(n) + euler_gamma + 1/2*n^(-1) + O(n^(-2)) log(n) + euler_gamma + 1/2*n^(-1) - 1/12*n^(-2) + O(n^(-4)) sage: asymptotic_expansions.HarmonicNumber('m', precision=5) log(m) + euler_gamma + 1/2*m^(-1) - 1/12*m^(-2) + 1/120*m^(-4) + O(m^(-6)) """ if not skip_constant_summand: from sage.symbolic.ring import SR coefficient_ring = SR.subring(no_variables=True) else: from sage.rings.rational_field import QQ coefficient_ring = QQ from asymptotic_ring import AsymptoticRing A = AsymptoticRing(growth_group='{n}^ZZ * log({n})^ZZ'.format(n=var), coefficient_ring=coefficient_ring) n = A.gen() if precision is None: precision = A.default_prec from sage.functions.log import log result = A.zero() if precision >= 1: result += log(n) if precision >= 2 and not skip_constant_summand: from sage.symbolic.constants import euler_gamma result += coefficient_ring(euler_gamma) if precision >= 3: result += 1 / (2 * n) from sage.arith.srange import srange from sage.arith.all import bernoulli for k in srange(2, 2 * precision - 4, 2): result += -bernoulli(k) / k / n**k if precision < 1: result += (log(n)).O() elif precision == 1: result += A(1).O() elif precision == 2: result += (1 / n).O() else: result += (1 / n**(2 * precision - 4)).O() return result