Example #1
0
    def get_dixon_matrix(self, polynomial):
        r"""
        Construct the Dixon matrix from the coefficients of polynomial
        \alpha. Each coefficient is viewed as a polynomial of x_1, ...,
        x_n.
        """

        # A list of coefficients (in x_i, ..., x_n terms) of the power
        # products a_1, ..., a_n in Dixon's polynomial.
        coefficients = polynomial.coeffs()

        monomials = list(itermonomials(self.variables,
                                       self.get_upper_degree()))
        monomials = sorted(monomials,
                           reverse=True,
                           key=monomial_key('lex', self.variables))

        dixon_matrix = Matrix(
            [[Poly(c, *self.variables).coeff_monomial(m) for m in monomials]
             for c in coefficients])

        keep = [
            column for column in range(dixon_matrix.shape[-1])
            if any([element != 0 for element in dixon_matrix[:, column]])
        ]
        return dixon_matrix[:, keep]
Example #2
0
    def __init__(self, mm, poly_g, morder='grevlex'):
        """
        @param - mm is a MomentMatrix object
        @param - poly_g the localizing polynomial
        """
        self.mm = mm
        self.poly_g = poly_g
        self.deg_g = poly_g.as_poly().total_degree()
        #there is no point to a constant localization matrix,
        #and it will cause crash because how sympy handles 1
        assert (self.deg_g > 0)

        # change this to be everything still in mm.monos post multiplication
        rawmonos = mn.itermonomials(self.mm.vars, self.mm.degree - self.deg_g)
        self.row_monos = sorted(rawmonos,\
                                 key=monomial_key(morder, mm.vars[::-1]))
        self.expanded_polys = []
        for yi in self.row_monos:
            for yj in self.row_monos:
                self.expanded_polys.append(sp.expand(poly_g * yi * yj))
        # mapping from a monomial to a list of indices of
        # where the monomial appears in the moment matrix
        self.term_to_indices_dict = defaultdict(list)
        for i, pi in enumerate(self.expanded_polys):
            coeffdict = pi.as_coefficients_dict()
            for mono in coeffdict:
                coeff = coeffdict[mono]
                self.term_to_indices_dict[mono].append((i, float(coeff)))
Example #3
0
 def __init__(self, mm, poly_g, morder='grevlex'):
     """
     @param - mm is a MomentMatrix object
     @param - poly_g the localizing polynomial
     """
     self.mm = mm
     self.poly_g = poly_g
     self.deg_g = poly_g.as_poly().total_degree()
     #there is no point to a constant localization matrix,
     #and it will cause crash because how sympy handles 1
     assert(self.deg_g>0)
     
     # change this to be everything still in mm.monos post multiplication 
     rawmonos = mn.itermonomials(self.mm.vars, self.mm.degree-self.deg_g);
     self.row_monos = sorted(rawmonos,\
                              key=monomial_key(morder, mm.vars[::-1]))
     self.expanded_polys = [];
     for yi in self.row_monos:
         for yj in self.row_monos:
             self.expanded_polys.append(sp.expand(poly_g*yi*yj))
     # mapping from a monomial to a list of indices of
     # where the monomial appears in the moment matrix
     self.term_to_indices_dict = defaultdict(list)
     for i,pi in enumerate(self.expanded_polys):
         coeffdict = pi.as_coefficients_dict()
         for mono in coeffdict:
             coeff = coeffdict[mono]
             self.term_to_indices_dict[mono].append( (i,float(coeff)) )
Example #4
0
    def get_dixon_matrix(self, polynomial):
        r"""
        Construct the Dixon matrix from the coefficients of polynomial
        \alpha. Each coefficient is viewed as a polynomial of x_1, ...,
        x_n.
        """

        max_degrees = self.get_max_degrees(polynomial)

        # list of column headers of the Dixon matrix.
        monomials = itermonomials(self.variables, max_degrees)
        monomials = sorted(monomials, reverse=True,
                           key=monomial_key('lex', self.variables))

        dixon_matrix = Matrix([[Poly(c, *self.variables).coeff_monomial(m)
                                for m in monomials]
                                for c in polynomial.coeffs()])

        # remove columns if needed
        if dixon_matrix.shape[0] != dixon_matrix.shape[1]:
            keep = [column for column in range(dixon_matrix.shape[-1])
                    if any(element != 0 for element
                        in dixon_matrix[:, column])]

            dixon_matrix = dixon_matrix[:, keep]

        return dixon_matrix
Example #5
0
 def observed_monomials(self, maxdeg):
     """
     return scipy moment monomials
     """
     import sympy.polys.monomials as mn
     obsvars = self.sym_obs
     terms = mn.itermonomials(obsvars, maxdeg)
     return terms
Example #6
0
 def moment_monomials(self, maxdeg):
     """
     return scipy moment monomials
     """
     import sympy.polys.monomials as mn
     allvars = self.sym_obs
     terms = mn.itermonomials(allvars, maxdeg)
     return terms
Example #7
0
 def moment_monomials(self, maxdeg):
     """
     return scipy moment monomials
     """
     import sympy.polys.monomials as mn
     allvars = self.sym_betas
     terms = mn.itermonomials(allvars, maxdeg)
     return terms
Example #8
0
 def polymom_monos(self, deg):
     """ return monomials needed to fit this model
     """
     import sympy.polys.monomials as mn
     #ipdb.set_trace()
     allvars = self.sym_means+self.sym_covs
     rawmonos = mn.itermonomials(allvars, deg)
     
     # filter out anything whose total degree in cov is greater than deg
     filtered = []
     for mono in rawmonos:
         pd = mono.as_powers_dict()
         sumcovdeg = sum([2*pd[covvar] for covvar in self.sym_covs])
         sumcovdeg += sum([pd[meanvar] for meanvar in self.sym_means])
         if sumcovdeg <= deg:
             filtered.append(mono)
     return filtered
Example #9
0
    def __init__(self, degree, variables, morder='grevlex', monos=None):
        """
        @param degree - highest degree of the first row/column of the
        moment matrix
        @param variables - list of sympy symbols
        @param morder the monomial order lex, grlex, grevlex, ilex, igrlex, igrevlex
        """
        self.degree = degree
        self.vars = variables
        self.num_vars = len(self.vars)

        # this object is a list of all monomials
        # in num_vars variables up to degree degree
        if monos is None:
            rawmonos = mn.itermonomials(self.vars, self.degree)
        else:
            rawmonos = monos

        # the reverse here is a bit random..., but has to be done.
        # also try grlex sometimes
        self.row_monos = sorted(rawmonos,\
                                 key=monomial_key(morder, self.vars[::-1]))

        # expanded monos is the flattened moment matrix itself
        self.expanded_monos = []
        for yi in self.row_monos:
            for yj in self.row_monos:
                self.expanded_monos.append(yi * yj)

        # This list correspond to the actual variables in the sdp solver
        self.matrix_monos = sorted(set(self.expanded_monos),\
                                   key=monomial_key(morder, self.vars[::-1]))
        self.num_matrix_monos = len(self.matrix_monos)

        # mapping from a monomial to a list of indices of
        # where the monomial appears in the moment matrix
        self.term_to_indices_dict = defaultdict(list)
        for i, yi in enumerate(self.expanded_monos):
            self.term_to_indices_dict[yi].append(i)
Example #10
0
    def __init__(self, degree, variables, morder='grevlex', monos=None):
        """
        @param degree - highest degree of the first row/column of the
        moment matrix
        @param variables - list of sympy symbols
        @param morder the monomial order lex, grlex, grevlex, ilex, igrlex, igrevlex
        """
        self.degree = degree
        self.vars = variables
        self.num_vars = len(self.vars)

        # this object is a list of all monomials
        # in num_vars variables up to degree degree
        if monos is None:
            rawmonos = mn.itermonomials(self.vars, self.degree)
        else:
            rawmonos = monos

        # the reverse here is a bit random..., but has to be done.
        # also try grlex sometimes
        self.row_monos = sorted(rawmonos,\
                                 key=monomial_key(morder, self.vars[::-1]))

        # expanded monos is the flattened moment matrix itself
        self.expanded_monos = []
        for yi in self.row_monos:
            for yj in self.row_monos:
                self.expanded_monos.append(yi*yj)

        # This list correspond to the actual variables in the sdp solver
        self.matrix_monos = sorted(set(self.expanded_monos),\
                                   key=monomial_key(morder, self.vars[::-1]))
        self.num_matrix_monos = len(self.matrix_monos)

        # mapping from a monomial to a list of indices of
        # where the monomial appears in the moment matrix
        self.term_to_indices_dict = defaultdict(list)
        for i,yi in enumerate(self.expanded_monos):
            self.term_to_indices_dict[yi].append(i)
Example #11
0
    def get_dixon_matrix(self, polynomial):
        r"""
        Construct the Dixon matrix from the coefficients of polynomial
        \alpha. Each coefficient is viewed as a polynomial of x_1, ...,
        x_n.
        """

        # A list of coefficients (in x_i, ..., x_n terms) of the power
        # products a_1, ..., a_n in Dixon's polynomial.
        coefficients = polynomial.coeffs()

        monomials = list(itermonomials(self.variables,
                                       self.get_upper_degree()))
        monomials = sorted(monomials, reverse=True,
                           key=monomial_key('lex', self.variables))

        dixon_matrix = Matrix([[Poly(c, *self.variables).coeff_monomial(m)
                                for m in monomials]
                                for c in coefficients])

        keep = [column for column in range(dixon_matrix.shape[-1])
                if any([element != 0 for element
                        in dixon_matrix[:, column]])]
        return dixon_matrix[:, keep]
Example #12
0
def test_monomials():
    assert itermonomials([], -1) == set()
    assert itermonomials([], 0) == {S(1)}
    assert itermonomials([], 1) == {S(1)}
    assert itermonomials([], 2) == {S(1)}
    assert itermonomials([], 3) == {S(1)}

    assert itermonomials([x], -1) == set()
    assert itermonomials([x], 0) == {S(1)}
    assert itermonomials([x], 1) == {S(1), x}
    assert itermonomials([x], 2) == {S(1), x, x**2}
    assert itermonomials([x], 3) == {S(1), x, x**2, x**3}

    assert itermonomials([x, y], 0) == {S(1)}
    assert itermonomials([x, y], 1) == {S(1), x, y}
    assert itermonomials([x, y], 2) == {S(1), x, y, x**2, y**2, x * y}
    assert itermonomials([x, y], 3) == \
        {S(1), x, y, x**2, x**3, y**2, y**3, x*y, x*y**2, y*x**2}

    i, j, k = symbols('i j k', commutative=False)
    assert itermonomials([i, j, k], 0) == {S(1)}
    assert itermonomials([i, j, k], 1) == {S(1), i, j, k}
    assert itermonomials([i, j, k], 2) == \
            {S(1), i, j, k, i**2, j**2, k**2, i*j, i*k, j*i, j*k, k*i, k*j}

    assert itermonomials([i, j, k], 3) == \
            {S(1), i, j, k, i**2, j**2, k**2, i*j, i*k, j*i, j*k, k*i, k*j,
                        i**3, j**3, k**3,
                        i**2 * j, i**2 * k, j * i**2, k * i**2,
                        j**2 * i, j**2 * k, i * j**2, k * j**2,
                        k**2 * i, k**2 * j, i * k**2, j * k**2,
                        i*j*i, i*k*i, j*i*j, j*k*j, k*i*k, k*j*k,
                        i*j*k, i*k*j, j*i*k, j*k*i, k*i*j, k*j*i,
                    }

    assert itermonomials([x, i, j], 0) == {S(1)}
    assert itermonomials([x, i, j], 1) == {S(1), x, i, j}
    assert itermonomials([x, i, j], 2) == {
        S(1), x, i, j, x * i, x * j, i * j, j * i, x**2, i**2, j**2
    }
    assert itermonomials([x, i, j], 3) == \
            {S(1), x, i, j, x*i, x*j, i*j, j*i, x**2, i**2, j**2,
                        x**3, i**3, j**3,
                        x**2 * i, x**2 * j,
                        x * i**2, j * i**2, i**2 * j, i*j*i,
                        x * j**2, i * j**2, j**2 * i, j*i*j,
                        x * i * j, x * j * i,
                    }
Example #13
0
#%% Misc Array Testing
import numpy as np
a = np.array([1, 2, 3])

b = 1 + 2j

#%% Printing monomials
import numpy as np
from sympy import symbols
from sympy.polys.monomials import itermonomials, monomial_count
from sympy.polys.orderings import monomial_key

x_str = ""
for i in range(2):
    x_str += 'x_' + str(i) + ', '
x_syms = symbols(x_str)
M = itermonomials(x_syms, 5)
sortedM = sorted(M, key=monomial_key('grlex', np.flip(x_syms)))
print(sortedM)

# %%
Example #14
0
def test_monomials():
    assert itermonomials([], 0) == set([S(1)])
    assert itermonomials([], 1) == set([S(1)])
    assert itermonomials([], 2) == set([S(1)])
    assert itermonomials([], 3) == set([S(1)])

    assert itermonomials([x], 0) == set([S(1)])
    assert itermonomials([x], 1) == set([S(1), x])
    assert itermonomials([x], 2) == set([S(1), x, x**2])
    assert itermonomials([x], 3) == set([S(1), x, x**2, x**3])

    assert itermonomials([x, y], 0) == set([S(1)])
    assert itermonomials([x, y], 1) == set([S(1), x, y])
    assert itermonomials([x, y], 2) == set([S(1), x, y, x**2, y**2, x * y])
    assert itermonomials([x, y], 3) == \
        set([S(1), x, y, x**2, x**3, y**2, y**3, x*y, x*y**2, y*x**2])
Example #15
0
def test_monomials():
    assert sorted(itermonomials([], 0)) == [1]
    assert sorted(itermonomials([], 1)) == [1]
    assert sorted(itermonomials([], 2)) == [1]
    assert sorted(itermonomials([], 3)) == [1]

    assert sorted(itermonomials([x], 0)) == [1]
    assert sorted(itermonomials([x], 1)) == [1, x]
    assert sorted(itermonomials([x], 2)) == [1, x, x ** 2]
    assert sorted(itermonomials([x], 3)) == [1, x, x ** 2, x ** 3]

    assert sorted(itermonomials([x, y], 0)) == [1]
    assert sorted(itermonomials([x, y], 1)) == [1, x, y]
    assert sorted(itermonomials([x, y], 2)) == [1, x, y, x ** 2, y ** 2, x * y]
    assert sorted(itermonomials([x, y], 3)) == [1, x, y, x ** 2, x ** 3, y ** 2, y ** 3, x * y, x * y ** 2, y * x ** 2]
Example #16
0
def heurisch(f,
             x,
             rewrite=False,
             hints=None,
             mappings=None,
             retries=3,
             degree_offset=0,
             unnecessary_permutations=None):
    """
    Compute indefinite integral using heuristic Risch algorithm.

    This is a heuristic approach to indefinite integration in finite
    terms using the extended heuristic (parallel) Risch algorithm, based
    on Manuel Bronstein's "Poor Man's Integrator".

    The algorithm supports various classes of functions including
    transcendental elementary or special functions like Airy,
    Bessel, Whittaker and Lambert.

    Note that this algorithm is not a decision procedure. If it isn't
    able to compute the antiderivative for a given function, then this is
    not a proof that such a functions does not exist.  One should use
    recursive Risch algorithm in such case.  It's an open question if
    this algorithm can be made a full decision procedure.

    This is an internal integrator procedure. You should use toplevel
    'integrate' function in most cases,  as this procedure needs some
    preprocessing steps and otherwise may fail.

    Specification
    =============

     heurisch(f, x, rewrite=False, hints=None)

       where
         f : expression
         x : symbol

         rewrite -> force rewrite 'f' in terms of 'tan' and 'tanh'
         hints   -> a list of functions that may appear in anti-derivate

          - hints = None          --> no suggestions at all
          - hints = [ ]           --> try to figure out
          - hints = [f1, ..., fn] --> we know better

    Examples
    ========

    >>> from sympy import tan
    >>> from sympy.integrals.heurisch import heurisch
    >>> from sympy.abc import x, y

    >>> heurisch(y*tan(x), x)
    y*log(tan(x)**2 + 1)/2

    See Manuel Bronstein's "Poor Man's Integrator":

    [1] http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/index.html

    For more information on the implemented algorithm refer to:

    [2] K. Geddes, L. Stefanus, On the Risch-Norman Integration
       Method and its Implementation in Maple, Proceedings of
       ISSAC'89, ACM Press, 212-217.

    [3] J. H. Davenport, On the Parallel Risch Algorithm (I),
       Proceedings of EUROCAM'82, LNCS 144, Springer, 144-157.

    [4] J. H. Davenport, On the Parallel Risch Algorithm (III):
       Use of Tangents, SIGSAM Bulletin 16 (1982), 3-6.

    [5] J. H. Davenport, B. M. Trager, On the Parallel Risch
       Algorithm (II), ACM Transactions on Mathematical
       Software 11 (1985), 356-362.

    See Also
    ========

    sympy.integrals.integrals.Integral.doit
    sympy.integrals.integrals.Integral
    components
    """
    f = sympify(f)
    if x not in f.free_symbols:
        return f * x

    if not f.is_Add:
        indep, f = f.as_independent(x)
    else:
        indep = S.One

    rewritables = {
        (sin, cos, cot): tan,
        (sinh, cosh, coth): tanh,
    }

    if rewrite:
        for candidates, rule in rewritables.items():
            f = f.rewrite(candidates, rule)
    else:
        for candidates in rewritables.keys():
            if f.has(*candidates):
                break
        else:
            rewrite = True

    terms = components(f, x)

    if hints is not None:
        if not hints:
            a = Wild('a', exclude=[x])
            b = Wild('b', exclude=[x])
            c = Wild('c', exclude=[x])

            for g in set(terms):
                if g.is_Function:
                    if g.func is li:
                        M = g.args[0].match(a * x**b)

                        if M is not None:
                            terms.add(
                                x *
                                (li(M[a] * x**M[b]) -
                                 (M[a] * x**M[b])**(-1 / M[b]) * Ei(
                                     (M[b] + 1) * log(M[a] * x**M[b]) / M[b])))
                            #terms.add( x*(li(M[a]*x**M[b]) - (x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) )
                            #terms.add( x*(li(M[a]*x**M[b]) - x*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) )
                            #terms.add( li(M[a]*x**M[b]) - Ei((M[b]+1)*log(M[a]*x**M[b])/M[b]) )

                    elif g.func is exp:
                        M = g.args[0].match(a * x**2)

                        if M is not None:
                            if M[a].is_positive:
                                terms.add(erfi(sqrt(M[a]) * x))
                            else:  # M[a].is_negative or unknown
                                terms.add(erf(sqrt(-M[a]) * x))

                        M = g.args[0].match(a * x**2 + b * x + c)

                        if M is not None:
                            if M[a].is_positive:
                                terms.add(
                                    sqrt(pi / 4 * (-M[a])) *
                                    exp(M[c] - M[b]**2 / (4 * M[a])) * erfi(
                                        sqrt(M[a]) * x + M[b] /
                                        (2 * sqrt(M[a]))))
                            elif M[a].is_negative:
                                terms.add(
                                    sqrt(pi / 4 * (-M[a])) *
                                    exp(M[c] - M[b]**2 / (4 * M[a])) * erf(
                                        sqrt(-M[a]) * x - M[b] /
                                        (2 * sqrt(-M[a]))))

                        M = g.args[0].match(a * log(x)**2)

                        if M is not None:
                            if M[a].is_positive:
                                terms.add(
                                    erfi(
                                        sqrt(M[a]) * log(x) + 1 /
                                        (2 * sqrt(M[a]))))
                            if M[a].is_negative:
                                terms.add(
                                    erf(
                                        sqrt(-M[a]) * log(x) - 1 /
                                        (2 * sqrt(-M[a]))))

                elif g.is_Pow:
                    if g.exp.is_Rational and g.exp.q == 2:
                        M = g.base.match(a * x**2 + b)

                        if M is not None and M[b].is_positive:
                            if M[a].is_positive:
                                terms.add(asinh(sqrt(M[a] / M[b]) * x))
                            elif M[a].is_negative:
                                terms.add(asin(sqrt(-M[a] / M[b]) * x))

                        M = g.base.match(a * x**2 - b)

                        if M is not None and M[b].is_positive:
                            if M[a].is_positive:
                                terms.add(acosh(sqrt(M[a] / M[b]) * x))
                            elif M[a].is_negative:
                                terms.add((-M[b] / 2 * sqrt(-M[a]) * atan(
                                    sqrt(-M[a]) * x / sqrt(M[a] * x**2 - M[b]))
                                           ))

        else:
            terms |= set(hints)

    for g in set(terms):
        terms |= components(cancel(g.diff(x)), x)

    # TODO: caching is significant factor for why permutations work at all. Change this.
    V = _symbols('x', len(terms))

    mapping = dict(list(zip(terms, V)))

    rev_mapping = {}

    if unnecessary_permutations is None:
        unnecessary_permutations = []
    for k, v in mapping.items():
        rev_mapping[v] = k

    if mappings is None:
        # Pre-sort mapping in order of largest to smallest expressions (last is always x).
        def _sort_key(arg):
            return default_sort_key(arg[0].as_independent(x)[1])

        #optimizing the number of permutations of mappping
        unnecessary_permutations = [(x, mapping[x])]
        del mapping[x]
        mapping = sorted(list(mapping.items()), key=_sort_key, reverse=True)
        mappings = permutations(mapping)

    def _substitute(expr):
        return expr.subs(mapping)

    for mapping in mappings:
        mapping = list(mapping)
        mapping = mapping + unnecessary_permutations
        diffs = [_substitute(cancel(g.diff(x))) for g in terms]
        denoms = [g.as_numer_denom()[1] for g in diffs]
        if all(h.is_polynomial(*V)
               for h in denoms) and _substitute(f).is_rational_function(*V):
            denom = reduce(lambda p, q: lcm(p, q, *V), denoms)
            break
    else:
        if not rewrite:
            result = heurisch(
                f,
                x,
                rewrite=True,
                hints=hints,
                unnecessary_permutations=unnecessary_permutations)

            if result is not None:
                return indep * result
        return None

    numers = [cancel(denom * g) for g in diffs]

    def _derivation(h):
        return Add(*[d * h.diff(v) for d, v in zip(numers, V)])

    def _deflation(p):
        for y in V:
            if not p.has(y):
                continue

            if _derivation(p) is not S.Zero:
                c, q = p.as_poly(y).primitive()
                return _deflation(c) * gcd(q, q.diff(y)).as_expr()
        else:
            return p

    def _splitter(p):
        for y in V:
            if not p.has(y):
                continue

            if _derivation(y) is not S.Zero:
                c, q = p.as_poly(y).primitive()

                q = q.as_expr()

                h = gcd(q, _derivation(q), y)
                s = quo(h, gcd(q, q.diff(y), y), y)

                c_split = _splitter(c)

                if s.as_poly(y).degree() == 0:
                    return (c_split[0], q * c_split[1])

                q_split = _splitter(cancel(q / s))

                return (c_split[0] * q_split[0] * s, c_split[1] * q_split[1])
        else:
            return (S.One, p)

    special = {}

    for term in terms:
        if term.is_Function:
            if term.func is tan:
                special[1 + _substitute(term)**2] = False
            elif term.func is tanh:
                special[1 + _substitute(term)] = False
                special[1 - _substitute(term)] = False
            elif term.func is C.LambertW:
                special[_substitute(term)] = True

    F = _substitute(f)

    P, Q = F.as_numer_denom()

    u_split = _splitter(denom)
    v_split = _splitter(Q)

    polys = list(v_split) + [u_split[0]] + list(special.keys())

    s = u_split[0] * Mul(*[k for k, v in special.items() if v])
    polified = [p.as_poly(*V) for p in [s, P, Q]]

    if None in polified:
        return None

    a, b, c = [p.total_degree() for p in polified]

    poly_denom = (s * v_split[0] * _deflation(v_split[1])).as_expr()

    def _exponent(g):
        if g.is_Pow:
            if g.exp.is_Rational and g.exp.q != 1:
                if g.exp.p > 0:
                    return g.exp.p + g.exp.q - 1
                else:
                    return abs(g.exp.p + g.exp.q)
            else:
                return 1
        elif not g.is_Atom and g.args:
            return max([_exponent(h) for h in g.args])
        else:
            return 1

    A, B = _exponent(f), a + max(b, c)

    if A > 1 and B > 1:
        monoms = itermonomials(V, A + B - 1 + degree_offset)
    else:
        monoms = itermonomials(V, A + B + degree_offset)

    poly_coeffs = _symbols('A', len(monoms))

    poly_part = Add(
        *[poly_coeffs[i] * monomial for i, monomial in enumerate(monoms)])

    reducibles = set()

    for poly in polys:
        if poly.has(*V):
            try:
                factorization = factor(poly, greedy=True)
            except PolynomialError:
                factorization = poly
            factorization = poly

            if factorization.is_Mul:
                reducibles |= set(factorization.args)
            else:
                reducibles.add(factorization)

    def _integrate(field=None):
        irreducibles = set()

        for poly in reducibles:
            for z in poly.atoms(Symbol):
                if z in V:
                    break
            else:
                continue

            irreducibles |= set(root_factors(poly, z, filter=field))

        log_coeffs, log_part = [], []
        B = _symbols('B', len(irreducibles))

        for i, poly in enumerate(irreducibles):
            if poly.has(*V):
                log_coeffs.append(B[i])
                log_part.append(log_coeffs[-1] * log(poly))

        coeffs = poly_coeffs + log_coeffs

        # TODO: Currently it's better to use symbolic expressions here instead
        # of rational functions, because it's simpler and FracElement doesn't
        # give big speed improvement yet. This is because cancelation is slow
        # due to slow polynomial GCD algorithms. If this gets improved then
        # revise this code.
        candidate = poly_part / poly_denom + Add(*log_part)
        h = F - _derivation(candidate) / denom
        raw_numer = h.as_numer_denom()[0]

        # Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field
        # that we have to determine. We can't use simply atoms() because log(3),
        # sqrt(y) and similar expressions can appear, leading to non-trivial
        # domains.
        syms = set(coeffs) | set(V)
        non_syms = set([])

        def find_non_syms(expr):
            if expr.is_Integer or expr.is_Rational:
                pass  # ignore trivial numbers
            elif expr in syms:
                pass  # ignore variables
            elif not expr.has(*syms):
                non_syms.add(expr)
            elif expr.is_Add or expr.is_Mul or expr.is_Pow:
                list(map(find_non_syms, expr.args))
            else:
                # TODO: Non-polynomial expression. This should have been
                # filtered out at an earlier stage.
                raise PolynomialError

        try:
            find_non_syms(raw_numer)
        except PolynomialError:
            return None
        else:
            ground, _ = construct_domain(non_syms, field=True)

        coeff_ring = PolyRing(coeffs, ground)
        ring = PolyRing(V, coeff_ring)

        numer = ring.from_expr(raw_numer)

        solution = solve_lin_sys(numer.coeffs(), coeff_ring)

        if solution is None:
            return None
        else:
            solution = [(k.as_expr(), v.as_expr())
                        for k, v in solution.items()]
            return candidate.subs(solution).subs(
                list(zip(coeffs, [S.Zero] * len(coeffs))))

    if not (F.atoms(Symbol) - set(V)):
        solution = _integrate('Q')

        if solution is None:
            solution = _integrate()
    else:
        solution = _integrate()

    if solution is not None:
        antideriv = solution.subs(rev_mapping)
        antideriv = cancel(antideriv).expand(force=True)

        if antideriv.is_Add:
            antideriv = antideriv.as_independent(x)[1]

        return indep * antideriv
    else:
        if retries >= 0:
            result = heurisch(
                f,
                x,
                mappings=mappings,
                rewrite=rewrite,
                hints=hints,
                retries=retries - 1,
                unnecessary_permutations=unnecessary_permutations)

            if result is not None:
                return indep * result

        return None
Example #17
0
def test_monomials():
    assert itermonomials([], 0) == {S(1)}
    assert itermonomials([], 1) == {S(1)}
    assert itermonomials([], 2) == {S(1)}
    assert itermonomials([], 3) == {S(1)}

    assert itermonomials([x], 0) == {S(1)}
    assert itermonomials([x], 1) == {S(1), x}
    assert itermonomials([x], 2) == {S(1), x, x**2}
    assert itermonomials([x], 3) == {S(1), x, x**2, x**3}

    assert itermonomials([x, y], 0) == {S(1)}
    assert itermonomials([x, y], 1) == {S(1), x, y}
    assert itermonomials([x, y], 2) == {S(1), x, y, x**2, y**2, x * y}
    assert itermonomials([x, y], 3) == \
        {S(1), x, y, x**2, x**3, y**2, y**3, x*y, x*y**2, y*x**2}
Example #18
0
SizeFaceSpec=(FaceSpecArray.shape)[1]

NbDOF=0
if Dim==1:
    for i in range(0,SizeFaceSpec+1):
        NbDOF=sum(FaceSpecArray[i]*Face[i])
if Dim==2 & Quantity_type==RefQuantityType[0]:
    NbDOF=sum(FaceSpecArray[0]*2)+sum(FaceSpecArray[1])
if Dim==2 & Quantity_type==RefQuantityType[1]:
        
"""Calculation of the polynomial"""
x,y,z=symbols('x y z')
from sympy.abc import alpha

if Dim==1: 
    PB=itermonomials([x], NbDOF-1)
elif Dim==2:
    PB=itermonomials([x, y], NbDOF-1)
elif Dim==3: 
    PB=itermonomials([x, y, z], NbDOF-1)

"""Representation of the polynomial"""
PBL=list(PB)
A = MatrixSymbol('alpha', 1, NbDOF)
ALPHA=Matrix(A)
P=Matrix(A)*Matrix(PBL)
"""Analytical representation of functional evaluation"""
"""Point Evaluation - PE"""
PE=P[0]
"""First derivative evaluation -FD"""
FD=diff(PE,x,1)
Example #19
0
def test_monomials():
    assert itermonomials([], -1) == set()
    assert itermonomials([], 0) == {S(1)}
    assert itermonomials([], 1) == {S(1)}
    assert itermonomials([], 2) == {S(1)}
    assert itermonomials([], 3) == {S(1)}

    assert itermonomials([x], -1) == set()
    assert itermonomials([x], 0) == {S(1)}
    assert itermonomials([x], 1) == {S(1), x}
    assert itermonomials([x], 2) == {S(1), x, x**2}
    assert itermonomials([x], 3) == {S(1), x, x**2, x**3}

    assert itermonomials([x, y], 0) == {S(1)}
    assert itermonomials([x, y], 1) == {S(1), x, y}
    assert itermonomials([x, y], 2) == {S(1), x, y, x**2, y**2, x*y}
    assert itermonomials([x, y], 3) == \
        {S(1), x, y, x**2, x**3, y**2, y**3, x*y, x*y**2, y*x**2}


    i, j, k = symbols('i j k', commutative=False)
    assert itermonomials([i, j, k], 0) == {S(1)}
    assert itermonomials([i, j, k], 1) == {S(1), i, j, k}
    assert itermonomials([i, j, k], 2) == \
            {S(1), i, j, k, i**2, j**2, k**2, i*j, i*k, j*i, j*k, k*i, k*j}

    assert itermonomials([i, j, k], 3) == \
            {S(1), i, j, k, i**2, j**2, k**2, i*j, i*k, j*i, j*k, k*i, k*j,
                        i**3, j**3, k**3,
                        i**2 * j, i**2 * k, j * i**2, k * i**2,
                        j**2 * i, j**2 * k, i * j**2, k * j**2,
                        k**2 * i, k**2 * j, i * k**2, j * k**2,
                        i*j*i, i*k*i, j*i*j, j*k*j, k*i*k, k*j*k,
                        i*j*k, i*k*j, j*i*k, j*k*i, k*i*j, k*j*i,
                    }

    assert itermonomials([x, i, j], 0) == {S(1)}
    assert itermonomials([x, i, j], 1) == {S(1), x, i, j}
    assert itermonomials([x, i, j], 2) == {S(1), x, i, j, x*i, x*j, i*j, j*i, x**2, i**2, j**2}
    assert itermonomials([x, i, j], 3) == \
            {S(1), x, i, j, x*i, x*j, i*j, j*i, x**2, i**2, j**2,
                        x**3, i**3, j**3,
                        x**2 * i, x**2 * j,
                        x * i**2, j * i**2, i**2 * j, i*j*i,
                        x * j**2, i * j**2, j**2 * i, j*i*j,
                        x * i * j, x * j * i,
                    }
Example #20
0
def test_monomials():
    assert itermonomials([], 0) == {S(1)}
    assert itermonomials([], 1) == {S(1)}
    assert itermonomials([], 2) == {S(1)}
    assert itermonomials([], 3) == {S(1)}

    assert itermonomials([x], 0) == {S(1)}
    assert itermonomials([x], 1) == {S(1), x}
    assert itermonomials([x], 2) == {S(1), x, x**2}
    assert itermonomials([x], 3) == {S(1), x, x**2, x**3}

    assert itermonomials([x, y], 0) == {S(1)}
    assert itermonomials([x, y], 1) == {S(1), x, y}
    assert itermonomials([x, y], 2) == {S(1), x, y, x**2, y**2, x*y}
    assert itermonomials([x, y], 3) == \
        {S(1), x, y, x**2, x**3, y**2, y**3, x*y, x*y**2, y*x**2}
Example #21
0
def special_constraint(constraint, kind):
    """special constraints are the following inequalities

    (1) x + y <= 1 | xy
    (2) x1 + x2 + x3 <= 1 | x1x2 + x1x3 + x2x3
    (3) x <= y | x - xy
    (4) x = y | x + y - 2xy
    (5) x + y >= 1 | 1- x- y + xy
    (6) x + y = 1 | 1 - x- y + 2xy

    Parameters
    ----------
    constraint : sympy.core.expr.Expr or subclasses
        constraint
    kind : string
        'lt', 'gt' or 'eq'

    Returns
    -------
    sympy.core.expr.Expr, bool
        constraint and Boolean, if it is a special constraint
    """
    constraint_as_dict = Poly(constraint).as_expr().as_coefficients_dict()
    constant = constraint_as_dict[1]
    if constant == 0:
        del constraint_as_dict[1]
        length = len(constraint_as_dict)
    else:
        length = len(constraint_as_dict)
        del constraint_as_dict[1]
    
    sufficient_cond = [all(
        coeff==1 or coeff==-1 for coeff in constraint_as_dict.values()),
                       constant in [0, -1],
                       length <= 4]
    if not all(sufficient_cond):
        return constraint, False
    
    condition_eq_1_2 = [any([length == 3, length == 4]), 
                        kind == 'lt',
                        all(coeff==1 for coeff in constraint_as_dict.values()), 
                        constant==-1]
    condition_eq_3_4 = [length == 2,
                        any([kind=='eq', kind=='lt']),
                        sum(constraint_as_dict.values())==0,
                        constant==0]
    condition_eq_5_6 = [length == 3,
                        any([kind=='eq', kind == 'gt']),
                        all(coeff==1 for coeff in constraint_as_dict.values()),
                        constant==-1]

    ### x + y <= 1, x + y + z <= 1
    if all(condition_eq_1_2):
        var_combinations = sorted(
            itermonomials(list(constraint.free_symbols), 2), 
            key=monomial_key('lex', list(constraint.free_symbols))
        )
        new_constraint = sum([
            func for func in var_combinations 
            if (not func.is_integer) and Poly(func).is_multivariate
        ])
        return new_constraint, True
    ### x <= y , x = y
    elif all(condition_eq_3_4):
        if kind == 'lt':
            new_constraint = [var for var, coeff in constraint_as_dict.items() 
                               if coeff==-1][0]
            var_combinations = sorted(
                itermonomials(list(constraint.free_symbols), 2), 
                key=monomial_key('lex', list(constraint.free_symbols))
            )
            new_constraint -= [term for term in var_combinations 
                                if term.is_Mul][0]
            return new_constraint, True
        if kind == 'eq' :
            var_combinations = sorted(
                itermonomials(list(constraint.free_symbols), 2), 
                key=monomial_key('lex', list(constraint.free_symbols))
            )
            new_constraint = 0
            for term in var_combinations:
                if term.is_symbol:
                    new_constraint += term
                elif term.is_Mul:
                    new_constraint -= 2*term 
        return new_constraint, True
    ### x + y >= 1, x + y = 1
    if all(condition_eq_5_6):
        var_combinations = sorted(
            itermonomials(list(constraint.free_symbols), 2), 
            key=monomial_key('lex', list(constraint.free_symbols))
        )
        new_constraint = 0
        for term in var_combinations:
            if term.is_integer or term.is_Mul:
                new_constraint += term
            if term.is_Mul and kind=='eq':
                new_constraint += term 
            if term.is_symbol and kind=='gt':
                new_constraint -= term
            if term.is_symbol and kind == 'eq':
                new_constraint -= 2*term
        return new_constraint, True

    return constraint, False
Example #22
0
def test_monomials():

    # total_degree tests
    assert set(itermonomials([], 0)) == {S.One}
    assert set(itermonomials([], 1)) == {S.One}
    assert set(itermonomials([], 2)) == {S.One}

    assert set(itermonomials([], 0, 0)) == {S.One}
    assert set(itermonomials([], 1, 0)) == {S.One}
    assert set(itermonomials([], 2, 0)) == {S.One}

    raises(StopIteration, lambda: next(itermonomials([], 0, 1)))
    raises(StopIteration, lambda: next(itermonomials([], 0, 2)))
    raises(StopIteration, lambda: next(itermonomials([], 0, 3)))

    assert set(itermonomials([], 0, 1)) == set()
    assert set(itermonomials([], 0, 2)) == set()
    assert set(itermonomials([], 0, 3)) == set()

    raises(ValueError, lambda: set(itermonomials([], -1)))
    raises(ValueError, lambda: set(itermonomials([x], -1)))
    raises(ValueError, lambda: set(itermonomials([x, y], -1)))

    assert set(itermonomials([x], 0)) == {S.One}
    assert set(itermonomials([x], 1)) == {S.One, x}
    assert set(itermonomials([x], 2)) == {S.One, x, x**2}
    assert set(itermonomials([x], 3)) == {S.One, x, x**2, x**3}

    assert set(itermonomials([x, y], 0)) == {S.One}
    assert set(itermonomials([x, y], 1)) == {S.One, x, y}
    assert set(itermonomials([x, y], 2)) == {S.One, x, y, x**2, y**2, x * y}
    assert set(itermonomials([x, y], 3)) == \
            {S.One, x, y, x**2, x**3, y**2, y**3, x*y, x*y**2, y*x**2}

    i, j, k = symbols('i j k', commutative=False)
    assert set(itermonomials([i, j, k], 0)) == {S.One}
    assert set(itermonomials([i, j, k], 1)) == {S.One, i, j, k}
    assert set(itermonomials([i, j, k], 2)) == \
           {S.One, i, j, k, i**2, j**2, k**2, i*j, i*k, j*i, j*k, k*i, k*j}

    assert set(itermonomials([i, j, k], 3)) == \
            {S.One, i, j, k, i**2, j**2, k**2, i*j, i*k, j*i, j*k, k*i, k*j,
                    i**3, j**3, k**3,
                    i**2 * j, i**2 * k, j * i**2, k * i**2,
                    j**2 * i, j**2 * k, i * j**2, k * j**2,
                    k**2 * i, k**2 * j, i * k**2, j * k**2,
                    i*j*i, i*k*i, j*i*j, j*k*j, k*i*k, k*j*k,
                    i*j*k, i*k*j, j*i*k, j*k*i, k*i*j, k*j*i,
            }

    assert set(itermonomials([x, i, j], 0)) == {S.One}
    assert set(itermonomials([x, i, j], 1)) == {S.One, x, i, j}
    assert set(itermonomials([x, i, j], 2)) == {
        S.One, x, i, j, x * i, x * j, i * j, j * i, x**2, i**2, j**2
    }
    assert set(itermonomials([x, i, j], 3)) == \
            {S.One, x, i, j, x*i, x*j, i*j, j*i, x**2, i**2, j**2,
                            x**3, i**3, j**3,
                            x**2 * i, x**2 * j,
                            x * i**2, j * i**2, i**2 * j, i*j*i,
                            x * j**2, i * j**2, j**2 * i, j*i*j,
                            x * i * j, x * j * i
            }

    # degree_list tests
    assert set(itermonomials([], [])) == {S.One}

    raises(ValueError, lambda: set(itermonomials([], [0])))
    raises(ValueError, lambda: set(itermonomials([], [1])))
    raises(ValueError, lambda: set(itermonomials([], [2])))

    raises(ValueError, lambda: set(itermonomials([x], [1], [])))
    raises(ValueError, lambda: set(itermonomials([x], [1, 2], [])))
    raises(ValueError, lambda: set(itermonomials([x], [1, 2, 3], [])))

    raises(ValueError, lambda: set(itermonomials([x], [], [1])))
    raises(ValueError, lambda: set(itermonomials([x], [], [1, 2])))
    raises(ValueError, lambda: set(itermonomials([x], [], [1, 2, 3])))

    raises(ValueError, lambda: set(itermonomials([x, y], [1, 2], [1, 2, 3])))
    raises(ValueError,
           lambda: set(itermonomials([x, y, z], [1, 2, 3], [0, 1])))

    raises(ValueError, lambda: set(itermonomials([x], [1], [-1])))
    raises(ValueError, lambda: set(itermonomials([x, y], [1, 2], [1, -1])))

    raises(ValueError, lambda: set(itermonomials([], [], 1)))
    raises(ValueError, lambda: set(itermonomials([], [], 2)))
    raises(ValueError, lambda: set(itermonomials([], [], 3)))

    raises(ValueError, lambda: set(itermonomials([x, y], [0, 1], [1, 2])))
    raises(ValueError,
           lambda: set(itermonomials([x, y, z], [0, 0, 3], [0, 1, 2])))

    assert set(itermonomials([x], [0])) == {S.One}
    assert set(itermonomials([x], [1])) == {S.One, x}
    assert set(itermonomials([x], [2])) == {S.One, x, x**2}
    assert set(itermonomials([x], [3])) == {S.One, x, x**2, x**3}

    assert set(itermonomials([x], [3], [1])) == {x, x**3, x**2}
    assert set(itermonomials([x], [3], [2])) == {x**3, x**2}

    assert set(itermonomials([x, y], [0, 0])) == {S.One}
    assert set(itermonomials([x, y], [0, 1])) == {S.One, y}
    assert set(itermonomials([x, y], [0, 2])) == {S.One, y, y**2}
    assert set(itermonomials([x, y], [0, 2], [0, 1])) == {y, y**2}
    assert set(itermonomials([x, y], [0, 2], [0, 2])) == {y**2}

    assert set(itermonomials([x, y], [1, 0])) == {S.One, x}
    assert set(itermonomials([x, y], [1, 1])) == {S.One, x, y, x * y}
    assert set(itermonomials([x, y],
                             [1, 2])) == {S.One, x, y, x * y, y**2, x * y**2}
    assert set(itermonomials([x, y], [1, 2], [1, 1])) == {x * y, x * y**2}
    assert set(itermonomials([x, y], [1, 2], [1, 2])) == {x * y**2}

    assert set(itermonomials([x, y], [2, 0])) == {S.One, x, x**2}
    assert set(itermonomials([x, y],
                             [2, 1])) == {S.One, x, y, x * y, x**2, x**2 * y}
    assert set(itermonomials([x, y], [2, 2])) == \
            {S.One, y**2, x*y**2, x, x*y, x**2, x**2*y**2, y, x**2*y}

    i, j, k = symbols('i j k', commutative=False)
    assert set(itermonomials([i, j, k], [0, 0, 0])) == {S.One}
    assert set(itermonomials([i, j, k], [0, 0, 1])) == {1, k}
    assert set(itermonomials([i, j, k], [0, 1, 0])) == {1, j}
    assert set(itermonomials([i, j, k], [1, 0, 0])) == {i, 1}
    assert set(itermonomials([i, j, k], [0, 0, 2])) == {k**2, 1, k}
    assert set(itermonomials([i, j, k], [0, 2, 0])) == {1, j, j**2}
    assert set(itermonomials([i, j, k], [2, 0, 0])) == {i, 1, i**2}
    assert set(itermonomials(
        [i, j, k], [1, 1, 1])) == {1, k, j, j * k, i * k, i, i * j, i * j * k}
    assert set(itermonomials([i, j, k], [2, 2, 2])) == \
            {1, k, i**2*k**2, j*k, j**2, i, i*k, j*k**2, i*j**2*k**2,
                    i**2*j, i**2*j**2, k**2, j**2*k, i*j**2*k,
                    j**2*k**2, i*j, i**2*k, i**2*j**2*k, j, i**2*j*k,
                    i*j**2, i*k**2, i*j*k, i**2*j**2*k**2, i*j*k**2, i**2, i**2*j*k**2
            }

    assert set(itermonomials([x, j, k], [0, 0, 0])) == {S.One}
    assert set(itermonomials([x, j, k], [0, 0, 1])) == {1, k}
    assert set(itermonomials([x, j, k], [0, 1, 0])) == {1, j}
    assert set(itermonomials([x, j, k], [1, 0, 0])) == {x, 1}
    assert set(itermonomials([x, j, k], [0, 0, 2])) == {k**2, 1, k}
    assert set(itermonomials([x, j, k], [0, 2, 0])) == {1, j, j**2}
    assert set(itermonomials([x, j, k], [2, 0, 0])) == {x, 1, x**2}
    assert set(itermonomials(
        [x, j, k], [1, 1, 1])) == {1, k, j, j * k, x * k, x, x * j, x * j * k}
    assert set(itermonomials([x, j, k], [2, 2, 2])) == \
            {1, k, x**2*k**2, j*k, j**2, x, x*k, j*k**2, x*j**2*k**2,
                    x**2*j, x**2*j**2, k**2, j**2*k, x*j**2*k,
                    j**2*k**2, x*j, x**2*k, x**2*j**2*k, j, x**2*j*k,
                    x*j**2, x*k**2, x*j*k, x**2*j**2*k**2, x*j*k**2, x**2, x**2*j*k**2
            }
Example #23
0
def test_monomials():

    # total_degree tests
    assert set(itermonomials([], 0)) == {S(1)}
    assert set(itermonomials([], 1)) == {S(1)}
    assert set(itermonomials([], 2)) == {S(1)}

    assert set(itermonomials([], 0, 0)) == {S(1)}
    assert set(itermonomials([], 1, 0)) == {S(1)}
    assert set(itermonomials([], 2, 0)) == {S(1)}

    raises(StopIteration, lambda: next(itermonomials([], 0, 1)))
    raises(StopIteration, lambda: next(itermonomials([], 0, 2)))
    raises(StopIteration, lambda: next(itermonomials([], 0, 3)))

    assert set(itermonomials([], 0, 1)) == set()
    assert set(itermonomials([], 0, 2)) == set()
    assert set(itermonomials([], 0, 3)) == set()

    raises(ValueError, lambda: set(itermonomials([], -1)))
    raises(ValueError, lambda: set(itermonomials([x], -1)))
    raises(ValueError, lambda: set(itermonomials([x, y], -1)))

    assert set(itermonomials([x], 0)) == {S(1)}
    assert set(itermonomials([x], 1)) == {S(1), x}
    assert set(itermonomials([x], 2)) == {S(1), x, x**2}
    assert set(itermonomials([x], 3)) == {S(1), x, x**2, x**3}

    assert set(itermonomials([x, y], 0)) == {S(1)}
    assert set(itermonomials([x, y], 1)) == {S(1), x, y}
    assert set(itermonomials([x, y], 2)) == {S(1), x, y, x**2, y**2, x*y}
    assert set(itermonomials([x, y], 3)) == \
            {S(1), x, y, x**2, x**3, y**2, y**3, x*y, x*y**2, y*x**2}

    i, j, k = symbols('i j k', commutative=False)
    assert set(itermonomials([i, j, k], 0)) == {S(1)}
    assert set(itermonomials([i, j, k], 1)) == {S(1), i, j, k}
    assert set(itermonomials([i, j, k], 2)) == \
           {S(1), i, j, k, i**2, j**2, k**2, i*j, i*k, j*i, j*k, k*i, k*j}

    assert set(itermonomials([i, j, k], 3)) == \
            {S(1), i, j, k, i**2, j**2, k**2, i*j, i*k, j*i, j*k, k*i, k*j,
                    i**3, j**3, k**3,
                    i**2 * j, i**2 * k, j * i**2, k * i**2,
                    j**2 * i, j**2 * k, i * j**2, k * j**2,
                    k**2 * i, k**2 * j, i * k**2, j * k**2,
                    i*j*i, i*k*i, j*i*j, j*k*j, k*i*k, k*j*k,
                    i*j*k, i*k*j, j*i*k, j*k*i, k*i*j, k*j*i,
            }

    assert set(itermonomials([x, i, j], 0)) == {S(1)}
    assert set(itermonomials([x, i, j], 1)) == {S(1), x, i, j}
    assert set(itermonomials([x, i, j], 2)) == {S(1), x, i, j, x*i, x*j, i*j, j*i, x**2, i**2, j**2}
    assert set(itermonomials([x, i, j], 3)) == \
            {S(1), x, i, j, x*i, x*j, i*j, j*i, x**2, i**2, j**2,
                            x**3, i**3, j**3,
                            x**2 * i, x**2 * j,
                            x * i**2, j * i**2, i**2 * j, i*j*i,
                            x * j**2, i * j**2, j**2 * i, j*i*j,
                            x * i * j, x * j * i
            }

    # degree_list tests
    assert set(itermonomials([], [])) == {S(1)}

    raises(ValueError, lambda: set(itermonomials([], [0])))
    raises(ValueError, lambda: set(itermonomials([], [1])))
    raises(ValueError, lambda: set(itermonomials([], [2])))

    raises(ValueError, lambda: set(itermonomials([x], [1], [])))
    raises(ValueError, lambda: set(itermonomials([x], [1, 2], [])))
    raises(ValueError, lambda: set(itermonomials([x], [1, 2, 3], [])))

    raises(ValueError, lambda: set(itermonomials([x], [], [1])))
    raises(ValueError, lambda: set(itermonomials([x], [], [1, 2])))
    raises(ValueError, lambda: set(itermonomials([x], [], [1, 2, 3])))

    raises(ValueError, lambda: set(itermonomials([x, y], [1, 2], [1, 2, 3])))
    raises(ValueError, lambda: set(itermonomials([x, y, z], [1, 2, 3], [0, 1])))

    raises(ValueError, lambda: set(itermonomials([x], [1], [-1])))
    raises(ValueError, lambda: set(itermonomials([x, y], [1, 2], [1, -1])))

    raises(ValueError, lambda: set(itermonomials([], [], 1)))
    raises(ValueError, lambda: set(itermonomials([], [], 2)))
    raises(ValueError, lambda: set(itermonomials([], [], 3)))

    raises(ValueError, lambda: set(itermonomials([x, y], [0, 1], [1, 2])))
    raises(ValueError, lambda: set(itermonomials([x, y, z], [0, 0, 3], [0, 1, 2])))

    assert set(itermonomials([x], [0])) == {S(1)}
    assert set(itermonomials([x], [1])) == {S(1), x}
    assert set(itermonomials([x], [2])) == {S(1), x, x**2}
    assert set(itermonomials([x], [3])) == {S(1), x, x**2, x**3}

    assert set(itermonomials([x], [3], [1])) == {x, x**3, x**2}
    assert set(itermonomials([x], [3], [2])) == {x**3, x**2}

    assert set(itermonomials([x, y], [0, 0])) == {S(1)}
    assert set(itermonomials([x, y], [0, 1])) == {S(1), y}
    assert set(itermonomials([x, y], [0, 2])) == {S(1), y, y**2}
    assert set(itermonomials([x, y], [0, 2], [0, 1])) == {y, y**2}
    assert set(itermonomials([x, y], [0, 2], [0, 2])) == {y**2}

    assert set(itermonomials([x, y], [1, 0])) == {S(1), x}
    assert set(itermonomials([x, y], [1, 1])) == {S(1), x, y, x*y}
    assert set(itermonomials([x, y], [1, 2])) == {S(1), x, y, x*y, y**2, x*y**2}
    assert set(itermonomials([x, y], [1, 2], [1, 1])) == {x*y, x*y**2}
    assert set(itermonomials([x, y], [1, 2], [1, 2])) == {x*y**2}

    assert set(itermonomials([x, y], [2, 0])) == {S(1), x, x**2}
    assert set(itermonomials([x, y], [2, 1])) == {S(1), x, y, x*y, x**2, x**2*y}
    assert set(itermonomials([x, y], [2, 2])) == \
            {S(1), y**2, x*y**2, x, x*y, x**2, x**2*y**2, y, x**2*y}

    i, j, k = symbols('i j k', commutative=False)
    assert set(itermonomials([i, j, k], [0, 0, 0])) == {S(1)}
    assert set(itermonomials([i, j, k], [0, 0, 1])) == {1, k}
    assert set(itermonomials([i, j, k], [0, 1, 0])) == {1, j}
    assert set(itermonomials([i, j, k], [1, 0, 0])) == {i, 1}
    assert set(itermonomials([i, j, k], [0, 0, 2])) == {k**2, 1, k}
    assert set(itermonomials([i, j, k], [0, 2, 0])) == {1, j, j**2}
    assert set(itermonomials([i, j, k], [2, 0, 0])) == {i, 1, i**2}
    assert set(itermonomials([i, j, k], [1, 1, 1])) == {1, k, j, j*k, i*k, i, i*j, i*j*k}
    assert set(itermonomials([i, j, k], [2, 2, 2])) == \
            {1, k, i**2*k**2, j*k, j**2, i, i*k, j*k**2, i*j**2*k**2,
                    i**2*j, i**2*j**2, k**2, j**2*k, i*j**2*k,
                    j**2*k**2, i*j, i**2*k, i**2*j**2*k, j, i**2*j*k,
                    i*j**2, i*k**2, i*j*k, i**2*j**2*k**2, i*j*k**2, i**2, i**2*j*k**2
            }

    assert set(itermonomials([x, j, k], [0, 0, 0])) == {S(1)}
    assert set(itermonomials([x, j, k], [0, 0, 1])) == {1, k}
    assert set(itermonomials([x, j, k], [0, 1, 0])) == {1, j}
    assert set(itermonomials([x, j, k], [1, 0, 0])) == {x, 1}
    assert set(itermonomials([x, j, k], [0, 0, 2])) == {k**2, 1, k}
    assert set(itermonomials([x, j, k], [0, 2, 0])) == {1, j, j**2}
    assert set(itermonomials([x, j, k], [2, 0, 0])) == {x, 1, x**2}
    assert set(itermonomials([x, j, k], [1, 1, 1])) == {1, k, j, j*k, x*k, x, x*j, x*j*k}
    assert set(itermonomials([x, j, k], [2, 2, 2])) == \
            {1, k, x**2*k**2, j*k, j**2, x, x*k, j*k**2, x*j**2*k**2,
                    x**2*j, x**2*j**2, k**2, j**2*k, x*j**2*k,
                    j**2*k**2, x*j, x**2*k, x**2*j**2*k, j, x**2*j*k,
                    x*j**2, x*k**2, x*j*k, x**2*j**2*k**2, x*j*k**2, x**2, x**2*j*k**2
            }
Example #24
0
def heurisch(f, x, rewrite=False, hints=None, mappings=None, retries=3,
             degree_offset=0, unnecessary_permutations=None):
    """
    Compute indefinite integral using heuristic Risch algorithm.

    This is a heuristic approach to indefinite integration in finite
    terms using the extended heuristic (parallel) Risch algorithm, based
    on Manuel Bronstein's "Poor Man's Integrator".

    The algorithm supports various classes of functions including
    transcendental elementary or special functions like Airy,
    Bessel, Whittaker and Lambert.

    Note that this algorithm is not a decision procedure. If it isn't
    able to compute the antiderivative for a given function, then this is
    not a proof that such a functions does not exist.  One should use
    recursive Risch algorithm in such case.  It's an open question if
    this algorithm can be made a full decision procedure.

    This is an internal integrator procedure. You should use toplevel
    'integrate' function in most cases,  as this procedure needs some
    preprocessing steps and otherwise may fail.

    Specification
    =============

     heurisch(f, x, rewrite=False, hints=None)

       where
         f : expression
         x : symbol

         rewrite -> force rewrite 'f' in terms of 'tan' and 'tanh'
         hints   -> a list of functions that may appear in anti-derivate

          - hints = None          --> no suggestions at all
          - hints = [ ]           --> try to figure out
          - hints = [f1, ..., fn] --> we know better

    Examples
    ========

    >>> from sympy import tan
    >>> from sympy.integrals.heurisch import heurisch
    >>> from sympy.abc import x, y

    >>> heurisch(y*tan(x), x)
    y*log(tan(x)**2 + 1)/2

    See Manuel Bronstein's "Poor Man's Integrator":

    [1] http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/index.html

    For more information on the implemented algorithm refer to:

    [2] K. Geddes, L. Stefanus, On the Risch-Norman Integration
       Method and its Implementation in Maple, Proceedings of
       ISSAC'89, ACM Press, 212-217.

    [3] J. H. Davenport, On the Parallel Risch Algorithm (I),
       Proceedings of EUROCAM'82, LNCS 144, Springer, 144-157.

    [4] J. H. Davenport, On the Parallel Risch Algorithm (III):
       Use of Tangents, SIGSAM Bulletin 16 (1982), 3-6.

    [5] J. H. Davenport, B. M. Trager, On the Parallel Risch
       Algorithm (II), ACM Transactions on Mathematical
       Software 11 (1985), 356-362.

    See Also
    ========

    sympy.integrals.integrals.Integral.doit
    sympy.integrals.integrals.Integral
    components
    """
    f = sympify(f)
    if x not in f.free_symbols:
        return f*x

    if not f.is_Add:
        indep, f = f.as_independent(x)
    else:
        indep = S.One

    rewritables = {
        (sin, cos, cot): tan,
        (sinh, cosh, coth): tanh,
    }

    if rewrite:
        for candidates, rule in rewritables.items():
            f = f.rewrite(candidates, rule)
    else:
        for candidates in rewritables.keys():
            if f.has(*candidates):
                break
        else:
            rewrite = True

    terms = components(f, x)

    if hints is not None:
        if not hints:
            a = Wild('a', exclude=[x])
            b = Wild('b', exclude=[x])
            c = Wild('c', exclude=[x])

            for g in set(terms):
                if g.is_Function:
                    if g.func is li:
                        M = g.args[0].match(a*x**b)

                        if M is not None:
                            terms.add( x*(li(M[a]*x**M[b]) - (M[a]*x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) )
                            #terms.add( x*(li(M[a]*x**M[b]) - (x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) )
                            #terms.add( x*(li(M[a]*x**M[b]) - x*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) )
                            #terms.add( li(M[a]*x**M[b]) - Ei((M[b]+1)*log(M[a]*x**M[b])/M[b]) )

                    elif g.func is exp:
                        M = g.args[0].match(a*x**2)

                        if M is not None:
                            if M[a].is_positive:
                                terms.add(erfi(sqrt(M[a])*x))
                            else: # M[a].is_negative or unknown
                                terms.add(erf(sqrt(-M[a])*x))

                        M = g.args[0].match(a*x**2 + b*x + c)

                        if M is not None:
                            if M[a].is_positive:
                                terms.add(sqrt(pi/4*(-M[a]))*exp(M[c] - M[b]**2/(4*M[a]))*
                                          erfi(sqrt(M[a])*x + M[b]/(2*sqrt(M[a]))))
                            elif M[a].is_negative:
                                terms.add(sqrt(pi/4*(-M[a]))*exp(M[c] - M[b]**2/(4*M[a]))*
                                          erf(sqrt(-M[a])*x - M[b]/(2*sqrt(-M[a]))))

                        M = g.args[0].match(a*log(x)**2)

                        if M is not None:
                            if M[a].is_positive:
                                terms.add(erfi(sqrt(M[a])*log(x) + 1/(2*sqrt(M[a]))))
                            if M[a].is_negative:
                                terms.add(erf(sqrt(-M[a])*log(x) - 1/(2*sqrt(-M[a]))))

                elif g.is_Pow:
                    if g.exp.is_Rational and g.exp.q == 2:
                        M = g.base.match(a*x**2 + b)

                        if M is not None and M[b].is_positive:
                            if M[a].is_positive:
                                terms.add(asinh(sqrt(M[a]/M[b])*x))
                            elif M[a].is_negative:
                                terms.add(asin(sqrt(-M[a]/M[b])*x))

                        M = g.base.match(a*x**2 - b)

                        if M is not None and M[b].is_positive:
                            if M[a].is_positive:
                                terms.add(acosh(sqrt(M[a]/M[b])*x))
                            elif M[a].is_negative:
                                terms.add((-M[b]/2*sqrt(-M[a])*
                                           atan(sqrt(-M[a])*x/sqrt(M[a]*x**2 - M[b]))))

        else:
            terms |= set(hints)

    for g in set(terms):
        terms |= components(cancel(g.diff(x)), x)

    # TODO: caching is significant factor for why permutations work at all. Change this.
    V = _symbols('x', len(terms))

    mapping = dict(list(zip(terms, V)))

    rev_mapping = {}

    if unnecessary_permutations is None:
        unnecessary_permutations = []
    for k, v in mapping.items():
        rev_mapping[v] = k

    if mappings is None:
        # Pre-sort mapping in order of largest to smallest expressions (last is always x).
        def _sort_key(arg):
            return default_sort_key(arg[0].as_independent(x)[1])
        #optimizing the number of permutations of mappping
        unnecessary_permutations = [(x, mapping[x])]
        del mapping[x]
        mapping = sorted(list(mapping.items()), key=_sort_key, reverse=True)
        mappings = permutations(mapping)

    def _substitute(expr):
        return expr.subs(mapping)

    for mapping in mappings:
        mapping = list(mapping)
        mapping = mapping + unnecessary_permutations
        diffs = [ _substitute(cancel(g.diff(x))) for g in terms ]
        denoms = [ g.as_numer_denom()[1] for g in diffs ]
        if all(h.is_polynomial(*V) for h in denoms) and _substitute(f).is_rational_function(*V):
            denom = reduce(lambda p, q: lcm(p, q, *V), denoms)
            break
    else:
        if not rewrite:
            result = heurisch(f, x, rewrite=True, hints=hints, unnecessary_permutations=unnecessary_permutations)

            if result is not None:
                return indep*result
        return None

    numers = [ cancel(denom*g) for g in diffs ]
    def _derivation(h):
        return Add(*[ d * h.diff(v) for d, v in zip(numers, V) ])

    def _deflation(p):
        for y in V:
            if not p.has(y):
                continue

            if _derivation(p) is not S.Zero:
                c, q = p.as_poly(y).primitive()
                return _deflation(c)*gcd(q, q.diff(y)).as_expr()
        else:
            return p

    def _splitter(p):
        for y in V:
            if not p.has(y):
                continue

            if _derivation(y) is not S.Zero:
                c, q = p.as_poly(y).primitive()

                q = q.as_expr()

                h = gcd(q, _derivation(q), y)
                s = quo(h, gcd(q, q.diff(y), y), y)

                c_split = _splitter(c)

                if s.as_poly(y).degree() == 0:
                    return (c_split[0], q * c_split[1])

                q_split = _splitter(cancel(q / s))

                return (c_split[0]*q_split[0]*s, c_split[1]*q_split[1])
        else:
            return (S.One, p)

    special = {}

    for term in terms:
        if term.is_Function:
            if term.func is tan:
                special[1 + _substitute(term)**2] = False
            elif term.func is tanh:
                special[1 + _substitute(term)] = False
                special[1 - _substitute(term)] = False
            elif term.func is C.LambertW:
                special[_substitute(term)] = True

    F = _substitute(f)

    P, Q = F.as_numer_denom()

    u_split = _splitter(denom)
    v_split = _splitter(Q)

    polys = list(v_split) + [ u_split[0] ] + list(special.keys())

    s = u_split[0] * Mul(*[ k for k, v in special.items() if v ])
    polified = [ p.as_poly(*V) for p in [s, P, Q] ]

    if None in polified:
        return None

    a, b, c = [ p.total_degree() for p in polified ]

    poly_denom = (s * v_split[0] * _deflation(v_split[1])).as_expr()

    def _exponent(g):
        if g.is_Pow:
            if g.exp.is_Rational and g.exp.q != 1:
                if g.exp.p > 0:
                    return g.exp.p + g.exp.q - 1
                else:
                    return abs(g.exp.p + g.exp.q)
            else:
                return 1
        elif not g.is_Atom and g.args:
            return max([ _exponent(h) for h in g.args ])
        else:
            return 1

    A, B = _exponent(f), a + max(b, c)

    if A > 1 and B > 1:
        monoms = itermonomials(V, A + B - 1 + degree_offset)
    else:
        monoms = itermonomials(V, A + B + degree_offset)

    poly_coeffs = _symbols('A', len(monoms))

    poly_part = Add(*[ poly_coeffs[i]*monomial
        for i, monomial in enumerate(monoms) ])

    reducibles = set()

    for poly in polys:
        if poly.has(*V):
            try:
                factorization = factor(poly, greedy=True)
            except PolynomialError:
                factorization = poly
            factorization = poly

            if factorization.is_Mul:
                reducibles |= set(factorization.args)
            else:
                reducibles.add(factorization)

    def _integrate(field=None):
        irreducibles = set()

        for poly in reducibles:
            for z in poly.atoms(Symbol):
                if z in V:
                    break
            else:
                continue

            irreducibles |= set(root_factors(poly, z, filter=field))

        log_coeffs, log_part = [], []
        B = _symbols('B', len(irreducibles))

        for i, poly in enumerate(irreducibles):
            if poly.has(*V):
                log_coeffs.append(B[i])
                log_part.append(log_coeffs[-1] * log(poly))

        coeffs = poly_coeffs + log_coeffs

        # TODO: Currently it's better to use symbolic expressions here instead
        # of rational functions, because it's simpler and FracElement doesn't
        # give big speed improvement yet. This is because cancelation is slow
        # due to slow polynomial GCD algorithms. If this gets improved then
        # revise this code.
        candidate = poly_part/poly_denom + Add(*log_part)
        h = F - _derivation(candidate) / denom
        raw_numer = h.as_numer_denom()[0]

        # Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field
        # that we have to determine. We can't use simply atoms() because log(3),
        # sqrt(y) and similar expressions can appear, leading to non-trivial
        # domains.
        syms = set(coeffs) | set(V)
        non_syms = set([])

        def find_non_syms(expr):
            if expr.is_Integer or expr.is_Rational:
                pass # ignore trivial numbers
            elif expr in syms:
                pass # ignore variables
            elif not expr.has(*syms):
                non_syms.add(expr)
            elif expr.is_Add or expr.is_Mul or expr.is_Pow:
                list(map(find_non_syms, expr.args))
            else:
                # TODO: Non-polynomial expression. This should have been
                # filtered out at an earlier stage.
                raise PolynomialError

        try:
            find_non_syms(raw_numer)
        except PolynomialError:
            return None
        else:
            ground, _ = construct_domain(non_syms, field=True)

        coeff_ring = PolyRing(coeffs, ground)
        ring = PolyRing(V, coeff_ring)

        numer = ring.from_expr(raw_numer)

        solution = solve_lin_sys(numer.coeffs(), coeff_ring)

        if solution is None:
            return None
        else:
            solution = [ (k.as_expr(), v.as_expr()) for k, v in solution.items() ]
            return candidate.subs(solution).subs(list(zip(coeffs, [S.Zero]*len(coeffs))))

    if not (F.atoms(Symbol) - set(V)):
        solution = _integrate('Q')

        if solution is None:
            solution = _integrate()
    else:
        solution = _integrate()

    if solution is not None:
        antideriv = solution.subs(rev_mapping)
        antideriv = cancel(antideriv).expand(force=True)

        if antideriv.is_Add:
            antideriv = antideriv.as_independent(x)[1]

        return indep*antideriv
    else:
        if retries >= 0:
            result = heurisch(f, x, mappings=mappings, rewrite=rewrite, hints=hints, retries=retries - 1, unnecessary_permutations=unnecessary_permutations)

            if result is not None:
                return indep*result

        return None
Example #25
0
def test_monomials():
    assert itermonomials([], 0) == set([S(1)])
    assert itermonomials([], 1) == set([S(1)])
    assert itermonomials([], 2) == set([S(1)])
    assert itermonomials([], 3) == set([S(1)])

    assert itermonomials([x], 0) == set([S(1)])
    assert itermonomials([x], 1) == set([S(1), x])
    assert itermonomials([x], 2) == set([S(1), x, x**2])
    assert itermonomials([x], 3) == set([S(1), x, x**2, x**3])

    assert itermonomials([x, y], 0) == set([S(1)])
    assert itermonomials([x, y], 1) == set([S(1), x, y])
    assert itermonomials([x, y], 2) == set([S(1), x, y, x**2, y**2, x*y])
    assert itermonomials([x, y], 3) == \
        set([S(1), x, y, x**2, x**3, y**2, y**3, x*y, x*y**2, y*x**2])
Example #26
0
def heurisch(f, x, rewrite=False, hints=None, mappings=None, retries=3,
             degree_offset=0, unnecessary_permutations=None,
             _try_heurisch=None):
    """
    Compute indefinite integral using heuristic Risch algorithm.

    Explanation
    ===========

    This is a heuristic approach to indefinite integration in finite
    terms using the extended heuristic (parallel) Risch algorithm, based
    on Manuel Bronstein's "Poor Man's Integrator".

    The algorithm supports various classes of functions including
    transcendental elementary or special functions like Airy,
    Bessel, Whittaker and Lambert.

    Note that this algorithm is not a decision procedure. If it isn't
    able to compute the antiderivative for a given function, then this is
    not a proof that such a functions does not exist.  One should use
    recursive Risch algorithm in such case.  It's an open question if
    this algorithm can be made a full decision procedure.

    This is an internal integrator procedure. You should use top level
    'integrate' function in most cases, as this procedure needs some
    preprocessing steps and otherwise may fail.

    Specification
    =============

     heurisch(f, x, rewrite=False, hints=None)

       where
         f : expression
         x : symbol

         rewrite -> force rewrite 'f' in terms of 'tan' and 'tanh'
         hints   -> a list of functions that may appear in anti-derivate

          - hints = None          --> no suggestions at all
          - hints = [ ]           --> try to figure out
          - hints = [f1, ..., fn] --> we know better

    Examples
    ========

    >>> from sympy import tan
    >>> from sympy.integrals.heurisch import heurisch
    >>> from sympy.abc import x, y

    >>> heurisch(y*tan(x), x)
    y*log(tan(x)**2 + 1)/2

    See Manuel Bronstein's "Poor Man's Integrator":

    References
    ==========

    .. [1] http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/index.html

    For more information on the implemented algorithm refer to:

    .. [2] K. Geddes, L. Stefanus, On the Risch-Norman Integration
       Method and its Implementation in Maple, Proceedings of
       ISSAC'89, ACM Press, 212-217.

    .. [3] J. H. Davenport, On the Parallel Risch Algorithm (I),
       Proceedings of EUROCAM'82, LNCS 144, Springer, 144-157.

    .. [4] J. H. Davenport, On the Parallel Risch Algorithm (III):
       Use of Tangents, SIGSAM Bulletin 16 (1982), 3-6.

    .. [5] J. H. Davenport, B. M. Trager, On the Parallel Risch
       Algorithm (II), ACM Transactions on Mathematical
       Software 11 (1985), 356-362.

    See Also
    ========

    sympy.integrals.integrals.Integral.doit
    sympy.integrals.integrals.Integral
    sympy.integrals.heurisch.components
    """
    f = sympify(f)

    # There are some functions that Heurisch cannot currently handle,
    # so do not even try.
    # Set _try_heurisch=True to skip this check
    if _try_heurisch is not True:
        if f.has(Abs, re, im, sign, Heaviside, DiracDelta, floor, ceiling, arg):
            return

    if not f.has_free(x):
        return f*x

    if not f.is_Add:
        indep, f = f.as_independent(x)
    else:
        indep = S.One

    rewritables = {
        (sin, cos, cot): tan,
        (sinh, cosh, coth): tanh,
    }

    if rewrite:
        for candidates, rule in rewritables.items():
            f = f.rewrite(candidates, rule)
    else:
        for candidates in rewritables.keys():
            if f.has(*candidates):
                break
        else:
            rewrite = True

    terms = components(f, x)

    if hints is not None:
        if not hints:
            a = Wild('a', exclude=[x])
            b = Wild('b', exclude=[x])
            c = Wild('c', exclude=[x])

            for g in set(terms):  # using copy of terms
                if g.is_Function:
                    if isinstance(g, li):
                        M = g.args[0].match(a*x**b)

                        if M is not None:
                            terms.add( x*(li(M[a]*x**M[b]) - (M[a]*x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) )
                            #terms.add( x*(li(M[a]*x**M[b]) - (x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) )
                            #terms.add( x*(li(M[a]*x**M[b]) - x*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) )
                            #terms.add( li(M[a]*x**M[b]) - Ei((M[b]+1)*log(M[a]*x**M[b])/M[b]) )

                    elif isinstance(g, exp):
                        M = g.args[0].match(a*x**2)

                        if M is not None:
                            if M[a].is_positive:
                                terms.add(erfi(sqrt(M[a])*x))
                            else: # M[a].is_negative or unknown
                                terms.add(erf(sqrt(-M[a])*x))

                        M = g.args[0].match(a*x**2 + b*x + c)

                        if M is not None:
                            if M[a].is_positive:
                                terms.add(sqrt(pi/4*(-M[a]))*exp(M[c] - M[b]**2/(4*M[a]))*
                                          erfi(sqrt(M[a])*x + M[b]/(2*sqrt(M[a]))))
                            elif M[a].is_negative:
                                terms.add(sqrt(pi/4*(-M[a]))*exp(M[c] - M[b]**2/(4*M[a]))*
                                          erf(sqrt(-M[a])*x - M[b]/(2*sqrt(-M[a]))))

                        M = g.args[0].match(a*log(x)**2)

                        if M is not None:
                            if M[a].is_positive:
                                terms.add(erfi(sqrt(M[a])*log(x) + 1/(2*sqrt(M[a]))))
                            if M[a].is_negative:
                                terms.add(erf(sqrt(-M[a])*log(x) - 1/(2*sqrt(-M[a]))))

                elif g.is_Pow:
                    if g.exp.is_Rational and g.exp.q == 2:
                        M = g.base.match(a*x**2 + b)

                        if M is not None and M[b].is_positive:
                            if M[a].is_positive:
                                terms.add(asinh(sqrt(M[a]/M[b])*x))
                            elif M[a].is_negative:
                                terms.add(asin(sqrt(-M[a]/M[b])*x))

                        M = g.base.match(a*x**2 - b)

                        if M is not None and M[b].is_positive:
                            if M[a].is_positive:
                                terms.add(acosh(sqrt(M[a]/M[b])*x))
                            elif M[a].is_negative:
                                terms.add(-M[b]/2*sqrt(-M[a])*
                                           atan(sqrt(-M[a])*x/sqrt(M[a]*x**2 - M[b])))

        else:
            terms |= set(hints)

    dcache = DiffCache(x)

    for g in set(terms):  # using copy of terms
        terms |= components(dcache.get_diff(g), x)

    # TODO: caching is significant factor for why permutations work at all. Change this.
    V = _symbols('x', len(terms))


    # sort mapping expressions from largest to smallest (last is always x).
    mapping = list(reversed(list(zip(*ordered(                          #
        [(a[0].as_independent(x)[1], a) for a in zip(terms, V)])))[1])) #
    rev_mapping = {v: k for k, v in mapping}                            #
    if mappings is None:                                                #
        # optimizing the number of permutations of mapping              #
        assert mapping[-1][0] == x # if not, find it and correct this comment
        unnecessary_permutations = [mapping.pop(-1)]
        mappings = permutations(mapping)
    else:
        unnecessary_permutations = unnecessary_permutations or []

    def _substitute(expr):
        return expr.subs(mapping)

    for mapping in mappings:
        mapping = list(mapping)
        mapping = mapping + unnecessary_permutations
        diffs = [ _substitute(dcache.get_diff(g)) for g in terms ]
        denoms = [ g.as_numer_denom()[1] for g in diffs ]
        if all(h.is_polynomial(*V) for h in denoms) and _substitute(f).is_rational_function(*V):
            denom = reduce(lambda p, q: lcm(p, q, *V), denoms)
            break
    else:
        if not rewrite:
            result = heurisch(f, x, rewrite=True, hints=hints,
                unnecessary_permutations=unnecessary_permutations)

            if result is not None:
                return indep*result
        return None

    numers = [ cancel(denom*g) for g in diffs ]
    def _derivation(h):
        return Add(*[ d * h.diff(v) for d, v in zip(numers, V) ])

    def _deflation(p):
        for y in V:
            if not p.has(y):
                continue

            if _derivation(p) is not S.Zero:
                c, q = p.as_poly(y).primitive()
                return _deflation(c)*gcd(q, q.diff(y)).as_expr()

        return p

    def _splitter(p):
        for y in V:
            if not p.has(y):
                continue

            if _derivation(y) is not S.Zero:
                c, q = p.as_poly(y).primitive()

                q = q.as_expr()

                h = gcd(q, _derivation(q), y)
                s = quo(h, gcd(q, q.diff(y), y), y)

                c_split = _splitter(c)

                if s.as_poly(y).degree() == 0:
                    return (c_split[0], q * c_split[1])

                q_split = _splitter(cancel(q / s))

                return (c_split[0]*q_split[0]*s, c_split[1]*q_split[1])

        return (S.One, p)

    special = {}

    for term in terms:
        if term.is_Function:
            if isinstance(term, tan):
                special[1 + _substitute(term)**2] = False
            elif isinstance(term, tanh):
                special[1 + _substitute(term)] = False
                special[1 - _substitute(term)] = False
            elif isinstance(term, LambertW):
                special[_substitute(term)] = True

    F = _substitute(f)

    P, Q = F.as_numer_denom()

    u_split = _splitter(denom)
    v_split = _splitter(Q)

    polys = set(list(v_split) + [ u_split[0] ] + list(special.keys()))

    s = u_split[0] * Mul(*[ k for k, v in special.items() if v ])
    polified = [ p.as_poly(*V) for p in [s, P, Q] ]

    if None in polified:
        return None

    #--- definitions for _integrate
    a, b, c = [ p.total_degree() for p in polified ]

    poly_denom = (s * v_split[0] * _deflation(v_split[1])).as_expr()

    def _exponent(g):
        if g.is_Pow:
            if g.exp.is_Rational and g.exp.q != 1:
                if g.exp.p > 0:
                    return g.exp.p + g.exp.q - 1
                else:
                    return abs(g.exp.p + g.exp.q)
            else:
                return 1
        elif not g.is_Atom and g.args:
            return max([ _exponent(h) for h in g.args ])
        else:
            return 1

    A, B = _exponent(f), a + max(b, c)

    if A > 1 and B > 1:
        monoms = tuple(ordered(itermonomials(V, A + B - 1 + degree_offset)))
    else:
        monoms = tuple(ordered(itermonomials(V, A + B + degree_offset)))

    poly_coeffs = _symbols('A', len(monoms))

    poly_part = Add(*[ poly_coeffs[i]*monomial
        for i, monomial in enumerate(monoms) ])

    reducibles = set()

    for poly in ordered(polys):
        coeff, factors = factor_list(poly, *V)
        reducibles.add(coeff)
        for fact, mul in factors:
            reducibles.add(fact)

    def _integrate(field=None):
        atans = set()
        pairs = set()

        if field == 'Q':
            irreducibles = set(reducibles)
        else:
            setV = set(V)
            irreducibles = set()
            for poly in ordered(reducibles):
                zV = setV & set(iterfreeargs(poly))
                for z in ordered(zV):
                    s = set(root_factors(poly, z, filter=field))
                    irreducibles |= s
                    break

        log_part, atan_part = [], []

        for poly in ordered(irreducibles):
            m = collect(poly, I, evaluate=False)
            y = m.get(I, S.Zero)
            if y:
                x = m.get(S.One, S.Zero)
                if x.has(I) or y.has(I):
                    continue  # nontrivial x + I*y
                pairs.add((x, y))
                irreducibles.remove(poly)

        while pairs:
            x, y = pairs.pop()
            if (x, -y) in pairs:
                pairs.remove((x, -y))
                # Choosing b with no minus sign
                if y.could_extract_minus_sign():
                    y = -y
                irreducibles.add(x*x + y*y)
                atans.add(atan(x/y))
            else:
                irreducibles.add(x + I*y)


        B = _symbols('B', len(irreducibles))
        C = _symbols('C', len(atans))

        # Note: the ordering matters here
        for poly, b in reversed(list(zip(ordered(irreducibles), B))):
            if poly.has(*V):
                poly_coeffs.append(b)
                log_part.append(b * log(poly))

        for poly, c in reversed(list(zip(ordered(atans), C))):
            if poly.has(*V):
                poly_coeffs.append(c)
                atan_part.append(c * poly)

        # TODO: Currently it's better to use symbolic expressions here instead
        # of rational functions, because it's simpler and FracElement doesn't
        # give big speed improvement yet. This is because cancellation is slow
        # due to slow polynomial GCD algorithms. If this gets improved then
        # revise this code.
        candidate = poly_part/poly_denom + Add(*log_part) + Add(*atan_part)
        h = F - _derivation(candidate) / denom
        raw_numer = h.as_numer_denom()[0]

        # Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field
        # that we have to determine. We can't use simply atoms() because log(3),
        # sqrt(y) and similar expressions can appear, leading to non-trivial
        # domains.
        syms = set(poly_coeffs) | set(V)
        non_syms = set()

        def find_non_syms(expr):
            if expr.is_Integer or expr.is_Rational:
                pass # ignore trivial numbers
            elif expr in syms:
                pass # ignore variables
            elif not expr.has_free(*syms):
                non_syms.add(expr)
            elif expr.is_Add or expr.is_Mul or expr.is_Pow:
                list(map(find_non_syms, expr.args))
            else:
                # TODO: Non-polynomial expression. This should have been
                # filtered out at an earlier stage.
                raise PolynomialError

        try:
            find_non_syms(raw_numer)
        except PolynomialError:
            return None
        else:
            ground, _ = construct_domain(non_syms, field=True)

        coeff_ring = PolyRing(poly_coeffs, ground)
        ring = PolyRing(V, coeff_ring)
        try:
            numer = ring.from_expr(raw_numer)
        except ValueError:
            raise PolynomialError
        solution = solve_lin_sys(numer.coeffs(), coeff_ring, _raw=False)

        if solution is None:
            return None
        else:
            return candidate.xreplace(solution).xreplace(
                dict(zip(poly_coeffs, [S.Zero]*len(poly_coeffs))))

    if all(isinstance(_, Symbol) for _ in V):
        more_free = F.free_symbols - set(V)
    else:
        Fd = F.as_dummy()
        more_free = Fd.xreplace(dict(zip(V, (Dummy() for _ in V)))
            ).free_symbols & Fd.free_symbols
    if not more_free:
        # all free generators are identified in V
        solution = _integrate('Q')

        if solution is None:
            solution = _integrate()
    else:
        solution = _integrate()

    if solution is not None:
        antideriv = solution.subs(rev_mapping)
        antideriv = cancel(antideriv).expand()

        if antideriv.is_Add:
            antideriv = antideriv.as_independent(x)[1]

        return indep*antideriv
    else:
        if retries >= 0:
            result = heurisch(f, x, mappings=mappings, rewrite=rewrite, hints=hints, retries=retries - 1, unnecessary_permutations=unnecessary_permutations)

            if result is not None:
                return indep*result

        return None
Example #27
0
def test_monomials():
    assert sorted(itermonomials([], 0)) == [1]
    assert sorted(itermonomials([], 1)) == [1]
    assert sorted(itermonomials([], 2)) == [1]
    assert sorted(itermonomials([], 3)) == [1]

    assert sorted(itermonomials([x], 0)) == [1]
    assert sorted(itermonomials([x], 1)) == [1, x]
    assert sorted(itermonomials([x], 2)) == [1, x, x**2]
    assert sorted(itermonomials([x], 3)) == [1, x, x**2, x**3]

    assert sorted(itermonomials([x, y], 0)) == [1]
    assert sorted(itermonomials([x, y], 1)) == [1, x, y]
    assert sorted(itermonomials([x, y], 2)) == [1, x, y, x**2, y**2, x * y]
    assert sorted(itermonomials([x, y], 3)) == [
        1, x, y, x**2, x**3, y**2, y**3, x * y, x * y**2, y * x**2
    ]