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]
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)))
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)) )
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
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
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
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
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
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)
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)
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]
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, }
#%% 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) # %%
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])
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]
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
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}
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)
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, }
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}
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
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 }
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 }
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
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])
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
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 ]