Symbolic Integrals

Symbolics.jl provides a the Integral operator for defining integrals. These can be used with various functionalities in order to represent integro-differential equations and as a representation for symbolic solving of integrals.

Note

This area is currently under heavy development. More solvers will be available in the near future.

Defining Symbolic Integrals

Note that integration domains are defined using DomainSets.jl.

Symbolics.IntegralType
Integral(domain)

Defines an Integral operator I(ex) which represents the integral of I of the expression ex over the domain. Note that the domain must be a Symbolics.VarDomainPairing where the chosen variable is the variable being integrated over, i.e. Integral(x in domain) means that I is the integral operator with respect to dx.

Examples

I1 = Integral(x in ClosedInterval(1, 5))
I2 = Integral(x in ClosedInterval(1, 5))

@variables a b
I = Integral(x in ClosedInterval(a, b))
@test isequal(I(0), 0)
@test isequal(I(2), 2*(b -a))
source

Solving Symbolic Integrals

Symbolics.jl currently has the following options for solving integrals symbolically:

OptionDescriptionProsCons
SymbolicIntegration.jlPure symbolic integration using the Risch algorithmReturns exact symbolic results with rational coefficients, handles complex expressionsMay not solve all integrals, focused on specific function classes
SymbolicNumericIntegration.jlUses numeric integrators with symbolic regression machine learning methodsCan solve some hard integrals very fast and easilyCan be unreliable in easy cases, will give floats (0.5) instead of rational values (1//2)
SymPy's IntegrateUses SymPy (through SymPy.jl) to integrate the expressionReasonably robust and tested solutionExtremely slow

SymbolicIntegration.jl

SymbolicIntegration.jl provides pure symbolic integration using the Risch algorithm and other symbolic methods. Unlike numerical methods, it returns exact symbolic results with rational coefficients (e.g., 1//2 instead of 0.5). The package implements a flexible framework for symbolic integration that uses Julia's multiple dispatch to select appropriate algorithms for different types of integrands.

The main integration method is RischMethod, which implements the Risch algorithm for integrating:

  • Polynomial functions
  • Rational functions
  • Exponential functions
  • Logarithmic functions
  • Trigonometric functions
  • Combinations of the above

For using SymbolicIntegration.jl, see the SymbolicIntegration.jl repository for more details. Quick examples:

using Symbolics
using SymbolicIntegration

@variables x

# Basic integrations
integrate(x^2, x)           # Returns (1//3)*(x^3)
integrate(1/x, x)           # Returns log(x)
integrate(exp(x), x)        # Returns exp(x)
integrate(1/(x^2 + 1), x)   # Returns atan(x)

# Rational function with complex roots
f = (x^3 + x^2 + x + 2)/(x^4 + 3*x^2 + 2)
integrate(f, x)  # Returns (1//2)*log(2 + x^2) + atan(x)

# Nested transcendental functions
integrate(1/(x*log(x)), x)  # Returns log(log(x))

# Explicit method selection
integrate(sin(x)*cos(x), x, RischMethod())

# Configurable method
risch = RischMethod(use_algebraic_closure=true, catch_errors=false)
integrate(exp(x)/(1 + exp(x)), x, risch)

SymbolicNumericIntegration.jl

SymbolicNumericIntegration.jl is a package for solving symbolic integrals using numerical methods. Specifically, it mixes numerical integration with machine learning symbolic regression in order to discover the basis for the integrals solution, for which it then finds the coefficients and uses differentiation to prove the correctness of the result. While this technique is unusual and new, see the paper for details, it has the advantage of working very differently from the purely symbolic methods, and thus the problems which it finds hard can be entirely different from ones which the purely symbolic methods find hard. That is, while purely symbolic methods have difficulty depending on the complexity of the expression, this method has difficulty depending on the uniqueness of the numerical solution of the expression, and there are many complex expressions which have a very distinct solution behavior and thus can be easy to solve through this method.

One major downside to this method is that, because it works numerically, there can be precision loss in the coefficients. Thus the returned solution may have 0.5 instead of 1//2.

For using SymbolicNumericIntegration.jl, see the SymbolicNumericIntegration.jl documentation for more details. A quick example is:

using Symbolics
using SymbolicNumericIntegration

@variables x a b

integrate(3x^3 + 2x - 5)
# (x^2 + (3 // 4) * (x^4) - (5 // 1) * x, 0, 0)

integrate(exp(a * x), x; symbolic = true)
# (exp(a * x) / a, 0, 0)

integrate(sin(a * x) * cos(b * x), x; symbolic = true, detailed = false)
# (-a * cos(a * x) * cos(b * x) - b * sin(a * x) * sin(b * x)) / (a^2 - (b^2))

SymPy

The function sympy_integrate allows one to call SymPy's integration functionality. While it's generally slow, if you leave your computer on for long enough it can solve some difficult expressions.

Symbolics.sympy_integrateFunction
sympy_integrate(expr, var)

Computes indefinite integral of expr w.r.t. var using SymPy.

Arguments

  • expr: Symbolics expression.
  • var: Symbolics variable.

Returns

Symbolics integral.

Example

@variables x
expr = x^2
result = sympy_integrate(expr, x)
source