m2m模型翻译
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

252 lines
8.1 KiB

from sympy.external import import_module
from sympy.utilities.decorator import doctest_depends_on
from sympy.core import Integer, Float
from sympy.core.add import Add
from sympy.core.function import Function
from sympy.core.mul import Mul
from sympy.core.numbers import E
from sympy.core.power import Pow
from sympy.core.singleton import S
from sympy.integrals.integrals import Integral
from sympy.functions import exp as sym_exp
import inspect
import re
from sympy.simplify.powsimp import powsimp
matchpy = import_module("matchpy")
if matchpy:
from matchpy import ManyToOneReplacer, ManyToOneMatcher
from sympy.integrals.rubi.utility_function import (
rubi_exp, rubi_unevaluated_expr, process_trig
)
from sympy.utilities.matchpy_connector import op_iter, op_len
@doctest_depends_on(modules=('matchpy',))
def get_rubi_object():
"""
Returns rubi ManyToOneReplacer by adding all rules from different modules.
Uncomment the lines to add integration capabilities of that module.
Currently, there are parsing issues with special_function,
derivative and miscellaneous_integration. Hence they are commented.
"""
from sympy.integrals.rubi.rules.integrand_simplification import integrand_simplification
from sympy.integrals.rubi.rules.linear_products import linear_products
from sympy.integrals.rubi.rules.quadratic_products import quadratic_products
from sympy.integrals.rubi.rules.binomial_products import binomial_products
from sympy.integrals.rubi.rules.trinomial_products import trinomial_products
from sympy.integrals.rubi.rules.miscellaneous_algebraic import miscellaneous_algebraic
from sympy.integrals.rubi.rules.exponential import exponential
from sympy.integrals.rubi.rules.logarithms import logarithms
from sympy.integrals.rubi.rules.sine import sine
from sympy.integrals.rubi.rules.tangent import tangent
from sympy.integrals.rubi.rules.secant import secant
from sympy.integrals.rubi.rules.miscellaneous_trig import miscellaneous_trig
from sympy.integrals.rubi.rules.inverse_trig import inverse_trig
from sympy.integrals.rubi.rules.hyperbolic import hyperbolic
from sympy.integrals.rubi.rules.inverse_hyperbolic import inverse_hyperbolic
from sympy.integrals.rubi.rules.special_functions import special_functions
#from sympy.integrals.rubi.rules.derivative import derivative
#from sympy.integrals.rubi.rules.piecewise_linear import piecewise_linear
from sympy.integrals.rubi.rules.miscellaneous_integration import miscellaneous_integration
rules = []
rules += integrand_simplification()
rules += linear_products()
rules += quadratic_products()
rules += binomial_products()
rules += trinomial_products()
rules += miscellaneous_algebraic()
rules += exponential()
rules += logarithms()
rules += special_functions()
rules += sine()
rules += tangent()
rules += secant()
rules += miscellaneous_trig()
rules += inverse_trig()
rules += hyperbolic()
rules += inverse_hyperbolic()
#rubi = piecewise_linear(rubi)
rules += miscellaneous_integration()
rubi = ManyToOneReplacer(*rules)
return rubi, rules
_E = rubi_unevaluated_expr(E)
class LoadRubiReplacer:
"""
Class trick to load RUBI only once.
"""
_instance = None
def __new__(cls):
if matchpy is None:
print("MatchPy library not found")
return None
if LoadRubiReplacer._instance is not None:
return LoadRubiReplacer._instance
obj = object.__new__(cls)
obj._rubi = None
obj._rules = None
LoadRubiReplacer._instance = obj
return obj
def load(self):
if self._rubi is not None:
return self._rubi
rubi, rules = get_rubi_object()
self._rubi = rubi
self._rules = rules
return rubi
def to_pickle(self, filename):
import pickle
rubi = self.load()
with open(filename, "wb") as fout:
pickle.dump(rubi, fout)
def to_dill(self, filename):
import dill
rubi = self.load()
with open(filename, "wb") as fout:
dill.dump(rubi, fout)
def from_pickle(self, filename):
import pickle
with open(filename, "rb") as fin:
self._rubi = pickle.load(fin)
return self._rubi
def from_dill(self, filename):
import dill
with open(filename, "rb") as fin:
self._rubi = dill.load(fin)
return self._rubi
@doctest_depends_on(modules=('matchpy',))
def process_final_integral(expr):
"""
Rubi's `rubi_exp` need to be replaced back to SymPy's general `exp`.
Examples
========
>>> from sympy import Function, E, Integral
>>> from sympy.integrals.rubi.rubimain import process_final_integral
>>> from sympy.integrals.rubi.utility_function import rubi_unevaluated_expr
>>> from sympy.abc import a, x
>>> _E = rubi_unevaluated_expr(E)
>>> process_final_integral(Integral(a, x))
Integral(a, x)
>>> process_final_integral(_E**5)
exp(5)
"""
if expr.has(_E):
expr = expr.replace(_E, E)
return expr
@doctest_depends_on(modules=('matchpy',))
def rubi_powsimp(expr):
"""
This function is needed to preprocess an expression as done in matchpy
`x^a*x^b` in matchpy auotmatically transforms to `x^(a+b)`
Examples
========
>>> from sympy.integrals.rubi.rubimain import rubi_powsimp
>>> from sympy.abc import a, b, x
>>> rubi_powsimp(x**a*x**b)
x**(a + b)
"""
lst_pow = []
lst_non_pow = []
if isinstance(expr, Mul):
for i in expr.args:
if isinstance(i, (Pow, rubi_exp, sym_exp)):
lst_pow.append(i)
else:
lst_non_pow.append(i)
return powsimp(Mul(*lst_pow))*Mul(*lst_non_pow)
return expr
@doctest_depends_on(modules=('matchpy',))
def rubi_integrate(expr, var, showsteps=False):
"""
Rule based algorithm for integration. Integrates the expression by applying
transformation rules to the expression.
Returns `Integrate` if an expression cannot be integrated.
Parameters
==========
expr : integrand expression
var : variable of integration
Returns Integral object if unable to integrate.
"""
rubi = LoadRubiReplacer().load()
expr = expr.replace(sym_exp, rubi_exp)
expr = process_trig(expr)
expr = rubi_powsimp(expr)
if isinstance(expr, (int, Integer, float, Float)):
return S(expr)*var
if isinstance(expr, Add):
results = 0
for ex in expr.args:
results += rubi.replace(Integral(ex, var))
return process_final_integral(results)
results = util_rubi_integrate(Integral(expr, var))
return process_final_integral(results)
@doctest_depends_on(modules=('matchpy',))
def util_rubi_integrate(expr, showsteps=False, max_loop=10):
rubi = LoadRubiReplacer().load()
expr = process_trig(expr)
expr = expr.replace(sym_exp, rubi_exp)
for i in range(max_loop):
results = expr.replace(
lambda x: isinstance(x, Integral),
lambda x: rubi.replace(x, max_count=10)
)
if expr == results:
return results
return results
@doctest_depends_on(modules=('matchpy',))
def get_matching_rule_definition(expr, var):
"""
Prints the list or rules which match to `expr`.
Parameters
==========
expr : integrand expression
var : variable of integration
"""
rubi = LoadRubiReplacer()
matcher = rubi.matcher
miter = matcher.match(Integral(expr, var))
for fun, e in miter:
print("Rule matching: ")
print(inspect.getsourcefile(fun))
code, lineno = inspect.getsourcelines(fun)
print("On line: ", lineno)
print("\n".join(code))
print("Pattern matching: ")
pattno = int(re.match(r"^\s*rule(\d+)", code[0]).group(1))
print(matcher.patterns[pattno-1])
print(e)
print()