将Piecewise与非理性指数相结合会产生误差

时间:2018-05-26 14:06:48

标签: python sympy solver piecewise

当尝试将分段函数与非理性指数相结合时,我偶然发现了以下问题:

import sympy as sym

x, y = sym.symbols(['x', 'y'])
pdf = sym.Piecewise((0, x < 1),
                    (x ** -2.5, x < 2),
                    (0, True))
cdf = sym.integrate(pdf, (x, -sym.oo, y))

这会出现以下错误:

ValueError                                Traceback (most recent call last)
<ipython-input-3-c1f460aac84e> in <module>()
      5                     (x ** -2.5, x < 2),
      6                     (0, True))
----> 7 cdf = sym.integrate(pdf, (x, -sym.oo, y))
      8 print(cdf)

~/.local/lib/python3.6/site-packages/sympy/integrals/integrals.py in integrate(*args, **kwargs)
   1293     if isinstance(integral, Integral):
   1294         return integral.doit(deep=False, meijerg=meijerg, conds=conds,
-> 1295                              risch=risch, manual=manual)
   1296     else:
   1297         return integral

~/.local/lib/python3.6/site-packages/sympy/integrals/integrals.py in doit(self, **hints)
    551                                        for f in integrals])
    552                         try:
--> 553                             evalued = Add(*others)._eval_interval(x, a, b)
    554                             function = uneval + evalued
    555                         except NotImplementedError:

~/.local/lib/python3.6/site-packages/sympy/functions/elementary/piecewise.py in _eval_interval(self, sym, a, b)
    229                         rep = b
    230                         val = e._eval_interval(sym, mid, b)
--> 231                         val += self._eval_interval(sym, a, mid)
    232                     elif (a > upper) == True:
    233                         mid = upper

~/.local/lib/python3.6/site-packages/sympy/functions/elementary/piecewise.py in _eval_interval(self, sym, a, b)
    282                     super(Piecewise, expr)._eval_interval(sym, Max(a, int_a), Min(b, int_b)))
    283             else:
--> 284                 ret_fun += expr._eval_interval(sym, Max(a, int_a), Min(b, int_b))
    285         return mul * ret_fun
    286 

~/.local/lib/python3.6/site-packages/sympy/core/expr.py in _eval_interval(self, x, a, b)
    832             else:
    833                 domain = Interval(b, a)
--> 834             singularities = list(solveset(self.cancel().as_numer_denom()[1], x, domain = domain))
    835             for s in singularities:
    836                 if a < s < b:

~/.local/lib/python3.6/site-packages/sympy/solvers/solveset.py in solveset(f, symbol, domain)
    919         return result
    920 
--> 921     return _solveset(f, symbol, domain, _check=True)
    922 
    923 

~/.local/lib/python3.6/site-packages/sympy/solvers/solveset.py in _solveset(f, symbol, domain, _check)
    709             result += solns
    710     else:
--> 711         lhs, rhs_s = inverter(f, 0, symbol)
    712         if lhs == symbol:
    713             # do some very minimal simplification since

~/.local/lib/python3.6/site-packages/sympy/solvers/solveset.py in <lambda>(f, rhs, symbol)
    677     else:
    678         inverter_func = invert_complex
--> 679     inverter = lambda f, rhs, symbol: inverter_func(f, rhs, symbol, domain)
    680 
    681     result = EmptySet()

~/.local/lib/python3.6/site-packages/sympy/solvers/solveset.py in invert_real(f_x, y, x, domain)
    116     the domain to ``S.Reals`` before inverting.
    117     """
--> 118     return _invert(f_x, y, x, domain)
    119 
    120 

~/.local/lib/python3.6/site-packages/sympy/solvers/solveset.py in _invert(f_x, y, x, domain)
     98 
     99     if domain.is_subset(S.Reals):
--> 100         x1, s = _invert_real(f_x, FiniteSet(y), x)
    101     else:
    102         x1, s = _invert_complex(f_x, FiniteSet(y), x)

~/.local/lib/python3.6/site-packages/sympy/solvers/solveset.py in _invert_real(f, g_ys, symbol)
    184             else:
    185                 if not base.is_positive:
--> 186                     raise ValueError("x**w where w is irrational is not "
    187                                      "defined for negative x")
    188                 return _invert_real(base, res, symbol)

ValueError: x**w where w is irrational is not defined for negative x

但是,如果我只使用指数的部分并将其集成,它就可以正常工作:

pdf = x ** -2.5
cdf = sym.integrate(pdf, (x, -sym.oo, y))
print(cdf)

这给出了:

-0.666666666666667*_y**(-1.5)

问题:
如何集成第一个Piecewise功能?

我尝试了什么:
y指定为非负:

y = sym.Symbol('y', nonnegative=True)

像这样我不会得到第一个错误,但结果变得很奇怪:

0.666666666666667*Min(1, y)**(-1.5) - 0.666666666666667*Min(2, y)**(-1.5)

我以后不能使用:

eq = sym.Eq(x, cdf)
inverse_solutions = sym.solve(eq, y, rational=False)  

给出:

NotImplementedError: multiple generators [Min(1, y)**1.5, Min(2, y)**1.5]
No algorithms are implemented to solve equation x - 0.666666666666667*Min(1, y)**(-1.5) + 0.666666666666667*Min(2, y)**(-1.5)

1 个答案:

答案 0 :(得分:2)

看起来我找到了解决方法 我只需要按sympy.nsimplify简化pdf,错误就消失了:

import sympy as sym

x, y = sym.symbols(['x', 'y'])
pdf = sym.Piecewise((0, x < 1),
                    (x ** -2.5, x < 2),
                    (0, True))
pdf = sym.nsimplify(pdf)
print(pdf)
cdf = sym.integrate(pdf, (x, -sym.oo, y))
print(cdf)

给出:

Piecewise((0, x < 1), (x**(-5/2), x < 2), (0, True))
Piecewise((0, y < 1), (2/3 - 2/(3*y**(3/2)), y < 2), (-sqrt(2)/6 + 2/3, True))