Beispiel #1
0
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)
Beispiel #3
0
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)
Beispiel #4
0
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)
Beispiel #5
0
 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
Beispiel #6
0
 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)
Beispiel #12
0
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)
Beispiel #13
0
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
Beispiel #14
0
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
Beispiel #17
0
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
Beispiel #18
0
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
Beispiel #20
0
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)
Beispiel #21
0
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
Beispiel #22
0
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
Beispiel #23
0
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)
Beispiel #24
0
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
Beispiel #25
0
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)
Beispiel #26
0
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
Beispiel #27
0
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
Beispiel #28
0
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
Beispiel #30
0
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