def _rewriter(integral): integrand, symbol = integral if condition(*integral): rewritten = rewrite(*integral) if rewritten != integrand: substep = integral_steps(rewritten, symbol) if not isinstance(substep, DontKnowRule) and substep: return RewriteRule(rewritten, substep, integrand, symbol)
def _proxy_rewriter(criteria): criteria, integral = criteria integrand, symbol = integral args = criteria + list(integral) if condition(*args): rewritten = rewrite(*args) if rewritten != integrand: return RewriteRule(rewritten, integral_steps(rewritten, symbol), integrand, symbol)
def _rewriter(integral): integrand, symbol = integral if condition(*integral): rewritten = rewrite(*integral) if rewritten != integrand: return RewriteRule( rewritten, integral_steps(rewritten, symbol), integrand, symbol)
def _rewriter(integral): integrand, symbol = integral if condition(*integral): rewritten = rewrite(*integral) if rewritten != integrand: substep = integral_steps(rewritten, symbol) if not isinstance(substep, DontKnowRule) and substep: return RewriteRule( rewritten, substep, integrand, symbol)
def integral_steps(integrand, symbol, **options): """Returns the steps needed to compute an integral. This function attempts to mirror what a student would do by hand as closely as possible. SymPy Gamma uses this to provide a step-by-step explanation of an integral. The code it uses to format the results of this function can be found at https://github.com/sympy/sympy_gamma/blob/master/app/logic/intsteps.py. Examples ======== >>> from sympy import exp, sin, cos >>> from sympy.integrals.manualintegrate import integral_steps >>> from sympy.abc import x >>> print(repr(integral_steps(exp(x) / (1 + exp(2 * x)), x))) \ # doctest: +NORMALIZE_WHITESPACE URule(u_var=_u, u_func=exp(x), constant=1, substep=ArctanRule(context=1/(_u**2 + 1), symbol=_u), context=exp(x)/(exp(2*x) + 1), symbol=x) >>> print(repr(integral_steps(sin(x), x))) \ # doctest: +NORMALIZE_WHITESPACE TrigRule(func='sin', arg=x, context=sin(x), symbol=x) >>> print(repr(integral_steps((x**2 + 3)**2 , x))) \ # doctest: +NORMALIZE_WHITESPACE RewriteRule(rewritten=x**4 + 6*x**2 + 9, substep=AddRule(substeps=[PowerRule(base=x, exp=4, context=x**4, symbol=x), ConstantTimesRule(constant=6, other=x**2, substep=PowerRule(base=x, exp=2, context=x**2, symbol=x), context=6*x**2, symbol=x), ConstantRule(constant=9, context=9, symbol=x)], context=x**4 + 6*x**2 + 9, symbol=x), context=(x**2 + 3)**2, symbol=x) Returns ======= rule : namedtuple The first step; most rules have substeps that must also be considered. These substeps can be evaluated using ``manualintegrate`` to obtain a result. """ cachekey = (integrand, symbol) if cachekey in _integral_cache: if _integral_cache[cachekey] is None: # cyclic integral! null_safe will eliminate that path return None else: return _integral_cache[cachekey] else: _integral_cache[cachekey] = None integral = IntegralInfo(integrand, symbol) def key(integral): integrand = integral.integrand if isinstance(integrand, TrigonometricFunction): return TrigonometricFunction elif isinstance(integrand, sympy.Derivative): return sympy.Derivative elif symbol not in integrand.free_symbols: return sympy.Number else: for cls in (sympy.Pow, sympy.Symbol, sympy.exp, sympy.log, sympy.Add, sympy.Mul, sympy.atan, sympy.asin, sympy.acos, sympy.Heaviside): if isinstance(integrand, cls): return cls def integral_is_subclass(*klasses): def _integral_is_subclass(integral): k = key(integral) return k and issubclass(k, klasses) return _integral_is_subclass result = do_one( null_safe(switch(key, { sympy.Pow: do_one(null_safe(power_rule), null_safe(inverse_trig_rule)), sympy.Symbol: power_rule, sympy.exp: exp_rule, sympy.Add: add_rule, sympy.Mul: do_one(null_safe(mul_rule), null_safe(trig_product_rule)), sympy.Derivative: derivative_rule, TrigonometricFunction: trig_rule, sympy.Heaviside: heaviside_rule, sympy.Number: constant_rule })), do_one( null_safe(trig_rule), null_safe(alternatives( rewrites_rule, substitution_rule, condition( integral_is_subclass(sympy.Mul, sympy.Pow), partial_fractions_rule), condition( integral_is_subclass(sympy.Mul, sympy.log, sympy.atan, sympy.asin, sympy.acos), parts_rule), condition( integral_is_subclass(sympy.Mul, sympy.Pow), distribute_expand_rule), trig_powers_products_rule )), null_safe(trig_substitution_rule) ), fallback_rule)(integral) del _integral_cache[cachekey] return result
def integral_steps(integrand, symbol, **options): """Returns the steps needed to compute an integral. This function attempts to mirror what a student would do by hand as closely as possible. SymPy Gamma uses this to provide a step-by-step explanation of an integral. The code it uses to format the results of this function can be found at https://github.com/sympy/sympy_gamma/blob/master/app/logic/intsteps.py. Examples ======== >>> from sympy import exp, sin, cos >>> from sympy.integrals.manualintegrate import integral_steps >>> from sympy.abc import x >>> print(repr(integral_steps(exp(x) / (1 + exp(2 * x)), x))) \ # doctest: +NORMALIZE_WHITESPACE URule(u_var=_u, u_func=exp(x), constant=1, substep=PiecewiseRule(subfunctions=[(ArctanRule(a=1, b=1, c=1, context=1/(_u**2 + 1), symbol=_u), True), (ArccothRule(a=1, b=1, c=1, context=1/(_u**2 + 1), symbol=_u), False), (ArctanhRule(a=1, b=1, c=1, context=1/(_u**2 + 1), symbol=_u), False)], context=1/(_u**2 + 1), symbol=_u), context=exp(x)/(exp(2*x) + 1), symbol=x) >>> print(repr(integral_steps(sin(x), x))) \ # doctest: +NORMALIZE_WHITESPACE TrigRule(func='sin', arg=x, context=sin(x), symbol=x) >>> print(repr(integral_steps((x**2 + 3)**2 , x))) \ # doctest: +NORMALIZE_WHITESPACE RewriteRule(rewritten=x**4 + 6*x**2 + 9, substep=AddRule(substeps=[PowerRule(base=x, exp=4, context=x**4, symbol=x), ConstantTimesRule(constant=6, other=x**2, substep=PowerRule(base=x, exp=2, context=x**2, symbol=x), context=6*x**2, symbol=x), ConstantRule(constant=9, context=9, symbol=x)], context=x**4 + 6*x**2 + 9, symbol=x), context=(x**2 + 3)**2, symbol=x) Returns ======= rule : namedtuple The first step; most rules have substeps that must also be considered. These substeps can be evaluated using ``manualintegrate`` to obtain a result. """ cachekey = (integrand, symbol) if cachekey in _integral_cache: if _integral_cache[cachekey] is None: # cyclic integral! null_safe will eliminate that path return None else: return _integral_cache[cachekey] else: _integral_cache[cachekey] = None integral = IntegralInfo(integrand, symbol) def key(integral): integrand = integral.integrand if isinstance(integrand, TrigonometricFunction): return TrigonometricFunction elif isinstance(integrand, sympy.Derivative): return sympy.Derivative elif symbol not in integrand.free_symbols: return sympy.Number else: for cls in (sympy.Pow, sympy.Symbol, sympy.exp, sympy.log, sympy.Add, sympy.Mul, sympy.atan, sympy.asin, sympy.acos, sympy.Heaviside): if isinstance(integrand, cls): return cls def integral_is_subclass(*klasses): def _integral_is_subclass(integral): k = key(integral) return k and issubclass(k, klasses) return _integral_is_subclass result = do_one( null_safe(switch(key, { sympy.Pow: do_one(null_safe(power_rule), null_safe(inverse_trig_rule), \ null_safe(quadratic_denom_rule)), sympy.Symbol: power_rule, sympy.exp: exp_rule, sympy.Add: add_rule, sympy.Mul: do_one(null_safe(mul_rule), null_safe(trig_product_rule), \ null_safe(heaviside_rule), null_safe(quadratic_denom_rule), \ null_safe(root_mul_rule)), sympy.Derivative: derivative_rule, TrigonometricFunction: trig_rule, sympy.Heaviside: heaviside_rule, sympy.Number: constant_rule })), do_one( null_safe(trig_rule), null_safe(alternatives( rewrites_rule, substitution_rule, condition( integral_is_subclass(sympy.Mul, sympy.Pow), partial_fractions_rule), condition( integral_is_subclass(sympy.Mul, sympy.Pow), cancel_rule), condition( integral_is_subclass(sympy.Mul, sympy.log, sympy.atan, sympy.asin, sympy.acos), parts_rule), condition( integral_is_subclass(sympy.Mul, sympy.Pow), distribute_expand_rule), trig_powers_products_rule, trig_expand_rule )), null_safe(trig_substitution_rule) ), fallback_rule)(integral) del _integral_cache[cachekey] return result
def test_condition(): rl = condition(lambda x: x % 2 == 0, posdec) assert rl(5) == 5 assert rl(4) == 3
def integral_steps(integrand, symbol, **options): """Returns the steps needed to compute an integral. This function attempts to mirror what a student would do by hand as closely as possible. Returns ======= rule : namedtuple The first step; most rules have substeps that must also be considered. These substeps can be evaluated using `manualintegrate` to obtain a result. """ cachekey = (integrand, symbol) if cachekey in _integral_cache: if _integral_cache[cachekey] is None: # cyclic integral! null_safe will eliminate that path return None else: return _integral_cache[cachekey] else: _integral_cache[cachekey] = None integral = IntegralInfo(integrand, symbol) def key(integral): integrand = integral.integrand if isinstance(integrand, TrigonometricFunction): return TrigonometricFunction elif symbol not in integrand.free_symbols: return 'constant' else: for cls in (sympy.Pow, sympy.Symbol, sympy.exp, sympy.Add, sympy.Mul): if isinstance(integrand, cls): return cls result = do_one( null_safe(switch(key, { sympy.Pow: do_one(null_safe(power_rule), null_safe(arctan_rule)), sympy.Symbol: power_rule, sympy.exp: exp_rule, sympy.Add: add_rule, sympy.Mul: do_one(null_safe(mul_rule), null_safe(trig_product_rule)), TrigonometricFunction: trig_rule, 'constant': constant_rule })), null_safe( alternatives( substitution_rule, parts_rule, condition(lambda integral: key(integral) == sympy.Mul, partial_fractions_rule), condition(lambda integral: key(integral) in (sympy.Mul, sympy.Pow), distribute_expand_rule), trig_powers_products_rule ) ), fallback_rule)(integral) _integral_cache[cachekey] = result return result
def test_condition(): rl = condition(lambda x: x%2 == 0, posdec) assert rl(5) == 5 assert rl(4) == 3
def integral_steps(integrand, symbol, **options): """Returns the steps needed to compute an integral. This function attempts to mirror what a student would do by hand as closely as possible. Returns ======= rule : namedtuple The first step; most rules have substeps that must also be considered. These substeps can be evaluated using `manualintegrate` to obtain a result. """ cachekey = (integrand, symbol) if cachekey in _integral_cache: if _integral_cache[cachekey] is None: # cyclic integral! null_safe will eliminate that path return None else: return _integral_cache[cachekey] else: _integral_cache[cachekey] = None integral = IntegralInfo(integrand, symbol) def key(integral): integrand = integral.integrand if isinstance(integrand, TrigonometricFunction): return TrigonometricFunction elif isinstance(integrand, sympy.Derivative): return sympy.Derivative elif symbol not in integrand.free_symbols: return 'constant' else: for cls in (sympy.Pow, sympy.Symbol, sympy.exp, sympy.Add, sympy.Mul): if isinstance(integrand, cls): return cls result = do_one( null_safe( switch( key, { sympy.Pow: do_one(null_safe(power_rule), null_safe(arctan_rule)), sympy.Symbol: power_rule, sympy.exp: exp_rule, sympy.Add: add_rule, sympy.Mul: do_one(null_safe(mul_rule), null_safe(trig_product_rule)), sympy.Derivative: derivative_rule, TrigonometricFunction: trig_rule, 'constant': constant_rule })), null_safe( alternatives( substitution_rule, parts_rule, condition(lambda integral: key(integral) == sympy.Mul, partial_fractions_rule), condition( lambda integral: key(integral) in (sympy.Mul, sympy.Pow), distribute_expand_rule), trig_powers_products_rule)), fallback_rule)(integral) _integral_cache[cachekey] = result return result