Ejemplo n.º 1
0
def _parse_poly(f):
    from sage.all import SR, QQ, HyperplaneArrangements, Matrix
    if type(f) == str:
        f = SR(f)
    if f.base_ring() == SR:
        L = f.factor_list()
        K = QQ
    else:
        L = list(f.factor())
        K = f.base_ring()

    L = filter(lambda T: not T[0] in K, L)  # Remove constant factors
    F, M = list(zip(*L))

    # Verify that each polynomial factor is linear
    is_lin = lambda g: all(map(lambda x: g.degree(x) <= 1, g.variables()))
    if not all(map(is_lin, F)):
        raise ValueError("Expected product of linear factors.")

    varbs = f.variables()
    varbs_str = tuple(map(lambda x: str(x), varbs))
    HH = HyperplaneArrangements(K, varbs_str)

    def poly_vec(g):
        c = K(g.subs({x: 0 for x in g.variables()}))
        return tuple([c] + [K(g.coefficient(x)) for x in varbs])

    F_vec = tuple(map(poly_vec, F))
    A = HH(Matrix(K, F_vec))

    # This scrambles the hyperplanes, so we need to scramble M in the same way.
    A_vec = tuple(map(lambda H: tuple(H.coefficients()), A.hyperplanes()))
    perm = tuple([F_vec.index(v) for v in A_vec])
    M_new = tuple([M[i] for i in perm])

    return A, M_new
Ejemplo n.º 2
0
def from_symbolic(exp, dR=None):
    r'''
        Method to transform a symbolic expression into a :class:`~ajpastor.dd_functions.ddFunction.DDFunction`.

        This method takes a symbolic expression an tries to cast it into a differentially definable function.
        This is closed related with the names that the module :mod:`~ajpastor.dd_functions.ddExamples` gives to 
        the functions.

        This method is the inverse of :func:`symbolic`, meaning that the output of this method after applying
        :func:`symbolic` is always an object that is equal to the first input.

        INPUT:

        * ``exp``: symbolic expression or an object that can be casted into one. We also allow lists, tuples and
          sets as possible inputs, applying this method recursively to each of its elements.
        * ``dR``: :class:`~ajpastor.dd_functions.ddFunction.DDRing` in which hierarchy we try to include
          the symbolic expression ``exp``. If ``None`` is given, we compute a :class:`~ajpastor.dd_functions.ddFunction.DDRing`
          using `x` as a variable and all other variables appearing in ``exp`` considered as parameters.

        OUTPUT:

        A :class:`~ajpastor.dd_functions.ddFunction.DDFunction` representation of ``exp``.

        TODO: add more cases from ddExamples

        EXAMPLES::

            sage: from ajpastor.dd_functions import *
            sage: var('y', 'm', 'n')
            (y, m, n)
            sage: from_symbolic(exp(x)) == Exp(x)
            True
            sage: sin_yx = from_symbolic(sin(y*x))
            sage: parent(sin_yx)
            DD-Ring over (Univariate Polynomial Ring in x over Rational Field) with parameter (y)
            sage: sin_yx.init(6, True)
            [0, y, 0, -y^3, 0, y^5]
            sage: from_symbolic(cos(x)) == Cos(x)
            True
            sage: from_symbolic(sinh(x)) == Sinh(x)
            True
            sage: from_symbolic(cosh(x)) == Cosh(x)
            True
            sage: from_symbolic(tan(x)) == Tan(x)
            True
            sage: from_symbolic(log(x + 1)) == Log(x+1)
            True
            sage: from_symbolic(bessel_J(4, x)) == BesselD(4)
            True
            sage: from_symbolic(hypergeometric([1,2,3],[5,6,7],x)) == GenericHypergeometricFunction((1,2,3),(5,6,7))
            True
    '''
    logger.debug("Looking for a DD-finite representation of %s", exp)

    if (isinstance(exp, list)):
        logger.debug("List case: converting each element")
        return [from_symbolic(el, dR) for el in exp]
    elif (isinstance(exp, tuple)):
        logger.debug("Tuple case: converting each element")
        return tuple([from_symbolic(el, dR) for el in exp])
    elif (isinstance(exp, set)):
        logger.debug("Set case: converting each element")
        return set([from_symbolic(el, dR) for el in exp])

    ## If it is not from the basic structures, we required a symbolic expression
    exp = SR(exp)

    logger.debug("Deciding the starting DDRing")
    if (not dR is None):
        logger.debug("User required solution to be in the hierarchy of %s", dR)
        if (any(v not in list(dR.variables(True)) + list(dR.parameters(True))
                for v in exp.variables())):
            raise TypeError("The symbolic expression has unknown variables")
    else:
        logger.debug("DDRing not specified: we compute one")
        params = [str(v) for v in exp.variables() if str(v) != 'x']
        if (len(params) > 0):
            dR = ParametrizedDDRing(
                DFinite, [str(v) for v in exp.variables() if str(v) != 'x'])
        else:
            dR = DFinite

    name = None
    try:
        name = exp.operator().__name__
    except AttributeError:
        try:
            name = exp.operator().name()
        except AttributeError:
            pass

    operands = exp.operands()
    if (name in ("list", "tuple")):  # special tuple and list cases
        logger.debug("Found a symbolic list or tuple")
        return tuple([from_symbolic(el, dR) for el in operands])
    elif (name == "set"):  # special set case
        logger.debug("Found a symbolic set")
        return set([from_symbolic(el, dR) for el in operands])
    elif (exp.is_rational_expression()):  # rational expression case
        logger.debug("Rational expression found")
        num = exp.numerator().polynomial(ring=dR.original_ring())
        den = exp.denominator().polynomial(ring=dR.original_ring())
        if (den == 1):
            return num

        return num / den
    elif (name == "add_vararg"):
        logger.debug("Found an addition")
        return sum([from_symbolic(el, dR) for el in operands])
    elif (name == "mul_vararg"):
        logger.debug("Found an product")
        return prod([from_symbolic(el, dR) for el in operands])
    elif (name == "pow"):
        logger.debug("Found an power")
        if (not operands[1] in QQ):
            raise TypeError("The exponent has to be a rational number")
        if (operands[1] in ZZ):
            logger.debug("Integer power: simple output")
            return pow(from_symbolic(operands[0], dR), ZZ(operands[1]))
        else:
            base = from_symbolic(operands[0], dR)
            if (is_DDFunction(base)):
                logger.debug("Fractional power: base DDFunction")
                return pow(base, QQ(operands[1]))
            else:
                logger.debug("Fractional power: base rational function")
                params = [str(el) for el in dR.parameters()]
                i = 0
                while ("y%d" % i in params):
                    i += 1

                R = PolynomialRing(dR.original_ring(), "y%d" % i)
                y = R.gens()[0]
                pq = QQ(operands[1])
                p = pq.numerator()
                q = pq.denominator()

                poly = y**q - R(str(operands[0]))**p
                x = dR.variables(True)[0]
                init = [
                    dR.coeff_field(exp.derivative(x, i)(**{
                        str(x): 0
                    })) for i in range(p + q)
                ]

                return DAlgebraic(poly, init, dR.to_depth(1))
    elif (name == "sin"):
        logger.debug("Found an sine")
        return Sin(operands[0])
    elif (name == "cos"):
        logger.debug("Found an cosine")
        return Cos(operands[0])
    elif (name == "sinh"):
        logger.debug("Found a hyperbolic sine")
        return Sinh(operands[0])
    elif (name == "cosh"):
        logger.debug("Found an hyperbolic cosine")
        return Cosh(operands[0])
    elif (name == "tan"):
        logger.debug("Found a tangent")
        return Tan(operands[0])
    elif (name == "log"):
        logger.debug("Found a logarithm")
        return Log(operands[0])
    elif (name == "exp"):
        logger.debug("Found an exponential")
        return Exp(operands[0])
    elif (name == "bessel_J"):
        logger.debug("Found an Bessel function of first kind")
        if (not (operands[0] in ZZ and operands[0] >= 0)):
            raise ValueError(
                "The Bessel has to have a non-negative integer index")
        return BesselD(ZZ(operands[0]))(from_symbolic(operands[1], dR))
    elif (name == "legendre_P"):
        logger.debug("Found an Legendre function of first kind")
        return LegendreD(operands[0], 0, 1)(from_symbolic(operands[1], dR))
    elif (name == "gen_legendre_P"):
        logger.debug("Found an generic Legendre function of first kind")
        return LegendreD(operands[0], operands[1],
                         1)(from_symbolic(operands[1], dR))
    elif (name == "legendre_Q"):
        logger.debug("Found an Legendre function of second kind")
        return LegendreD(operands[0], 0, 2)(from_symbolic(operands[1], dR))
    elif (name == "gen_legendre_Q"):
        logger.debug("Found an generic Legendre function of second kind")
        return LegendreD(operands[0], operands[1],
                         2)(from_symbolic(operands[1], dR))
    elif (name == "chebyshev_T"):
        logger.debug("Found an Chebyshev function of first kind")
        return ChebyshevD(operands[0], 1)(from_symbolic(operands[1], dR))
    elif (name == "chebyshev_U"):
        logger.debug("Found an Chebyshev function of second kind")
        return ChebyshevD(operands[0], 2)(from_symbolic(operands[1], dR))
    elif (name == "hypergeometric"):
        return GenericHypergeometricFunction(from_symbolic(operands[0], dR),
                                             from_symbolic(operands[1],
                                                           dR))(from_symbolic(
                                                               operands[2],
                                                               dR))
    else:
        raise NotImplementedError(
            "The operator %s is not valid for 'from_symbolic'" % name)