Esta biblioteca es una extensión de la popular biblioteca Math.js. Agrega una función integral
que es capaz de encontrar las integrales de funciones matemáticas simples. También es flexible en las reglas de integración utilizadas, lo que permite que se usen reglas personalizadas en lugar o además de las reglas de estándares.
Tenga en cuenta que este software todavía se considera beta, por lo que si se encuentra con cualquier error o bordes aproximados, ¡envíe un problema!
Para instalar el paquete, use lo siguiente:
npm install mathjs-simple-integral
Para registrar la extensión con Math.js, use lo siguiente:
math . import ( require ( 'mathjs-simple-integral' ) ) ;
Esto agregará la función math.integral
a MATH.JS.
El uso básico de esta extensión es muy fácil: solo proporcione el integrando (ya sea como un Node
o una cadena) y la variable de integración (ya sea como un SymbolNode
o una cadena):
math . integral ( 'x^2' , 'x' ) ; // 'x ^ 3 / 3'
math . integral ( '1/x' , 'x' ) ; // 'log(abs(x))'
math . integral ( 'e^x' , 'x' ) ; // 'e^x'
math . integral ( 'cos(2*x+pi/6)' , 'x' ) ; // 'sin(2 * x + pi / 6) / 2'
Si integral
no puede encontrar la integral de la expresión dada, lanzará un error:
math . integral ( 'e^(x^2)' ) ; // Error: Unable to find integral of "e ^ (x ^ 2)" with respect to "x"
Por defecto, integral
ejecuta math.simplify
en la salida, ya que el proceso de integración puede producir algunas expresiones difíciles de manejar. Sin embargo, es posible obtener una salida sin procesar y no simplificada de integral
pasando un objeto options
con simplify
establecido en false
al tercer parámetro opcional:
math . integral ( 'x^2' , 'x' , { simplify : false } ) ; // '1 / (2 + 1) * x ^ (2 + 1)'
math . integral ( '1/(2*x)' , 'x' , { simplify : false } ) ; // '2 ^ -1 * log(abs(x))'
En esta implementación, las reglas de integración se definen como una función que toma como parámetros (1) expr
, la expresión a integrar; (2) context
, el contexto de la integración; y (3) subIntegral
, una función que intenta integrar una subexpresión o una forma reescrita de la integral. La regla de integración devuelve la integral calculada, o null
si no pudo encontrar una. Además de muchas integración estándar ya implementada (ubicada en math.integral.rules
), se puede especificar un conjunto personalizado de reglas de integración.
Por ejemplo, supongamos que agregamos una función personalizada myUpperGamma
que representa la función gamma incompleta superior, y ahora queremos agregar soporte para integrarlo, particularmente queremos implementar esta regla: integral("myUpperGamma(s,x)", "x") = x*myUpperGamma(s,x) - myUpperGamma(s+1, x)
(verifique aquí). Primero, escribamos esta regla como una función:
var myUpperGammaRule = function ( expr , context , subIntegral ) {
// Ensure we are trying to integrate a FunctionNode
if ( expr . type === "FunctionNode" ) {
// Ensure we are trying to integrate 'myUpperGamma' and that it has 2 arguments
if ( expr . name === "myUpperGamma" && expr . args . length === 2 ) {
// Ensure that the first argument is constant and the second one is
// the variable of integration
if ( context . isConstant ( expr . args [ 0 ] ) && expr . args [ 1 ] . equals ( context . variable ) ) {
// Yay, we matched 'myUpperGamma(s,x)', so we know the integral!
return new OperatorNode ( '-' , 'subtract' , [
new OperatorNode ( '*' , 'multiply' , [
context . variable ,
new FunctionNode ( 'myUpperGamma' , [
expr . args [ 0 ] ,
context . variable
] )
] ) ,
new FunctionNode ( 'myUpperGamma' , [
new OperatorNode ( '+' , 'add' , [
expr . args [ 0 ] ,
new ConstantNode ( 1 )
] ) ,
context . variable
] )
] ) ;
}
}
}
// Our rule, didn't apply :(
// return undefined
}
¡Ahora que tenemos nuestra regla de integración personalizada, podemos agregarla a la lista de reglas estándar y usar esta lista combinada para encontrar integrales que involucren myUpperGamma
!
// Define our integration rules to include our custom rule
var options = { rules : math . integral . rules . concat ( [ myUpperGammaRule ] ) } ;
// Compute integrals of our function!
math . integral ( 'myUpperGamma(a,x)' , 'x' , options ) ;
// 'x*myUpperGamma(a,x) - myUpperGamma(a+1,x)'
math . integral ( 'myUpperGamma(a^2,x) + 13' , 'x' , options ) ;
// 'x*myUpperGamma(a^2,x) - myUpperGamma(a^2+1,x) + 13*x'
math . integral ( 'myUpperGamma(a,5*x+99)' , 'x' , options ) ;
// '((5*x+99) * myUpperGamma(a, 5*x+99) - myUpperGamma(a+1, 5*x+99)) / 5'
math . integral ( 'sqrt(myUpperGamma(a,x)) * sqrt(myUpperGamma(a,x))' , 'x' , options ) ;
// 'x*myUpperGamma(a,x) - myUpperGamma(a+1,x)'
Ahora supongamos que además de myUpperGamma
tenemos otra función personalizada mySum
: al igual que add
, aceptará un número variable de argumentos y agregará los argumentos juntos, pero también realiza alguna otra función no matemática (como registrar cada argumento antes de la evaluación, o verificar para garantizar que ninguno de sus argumentos sea NaN
). Ahora, podemos agregar reglas al integrador que representan la linealidad de la integral sobre mySum
:
// integral(mySum(f(x), g(x), ...), x) = mySum(integral(f(x), x), integral(g(x), x), ...)
function mySumRule ( expr , context , subIntegral ) {
// Ensure we are trying to integrate a FunctionNode
if ( expr . type === "FunctionNode" ) {
// Ensure we are trying to integrate 'mySum'
if ( expr . name === "mySum" ) {
// Try to find integrals of all the terms in the sum
var termIntegrals = expr . args . map ( function ( term ) {
return subIntegral ( term , context , 'sum rule (mySum)' ) ;
} ) ;
// Only if all terms had integrals did we actually find an integral
if ( termIntegrals . every ( function ( termInt ) { return ! ! termInt ; } ) ) {
// Yay, we found the integral!
return new FunctionNode ( 'mySum' , termIntegrals ) ;
}
}
}
// return undefined
}
Observe cómo usamos la devolución de llamada subIntegral
para encontrar la integral de todos los términos en la suma, y luego devuelve una integral para toda la expresión mySum
solo si todos los términos individuales podrían integrarse. Ahora, si usamos nuestras dos reglas personalizadas, podemos integrar expresiones con mySum
y myUpperGamma
:
var options = { rules : math . integral . rules . concat ( [ myUpperGammaRule , mySumRule ] ) } ;
math . integral ( "mySum(3*x^2, x, 1/x, 1)" , "x" , options ) ;
// 'mySum(x^3, x^2/2, log(abs(x)), x)'
math . integral ( "mySum(2*x, myUpperGamma(a,x))" , "x" , options ) ;
// 'mySum(x^2, x*myUpperGamma(a,x) - myUpperGamma(a+1,x))'
El objeto Opciones puede tener una debugPrint
de la propiedad de que, si se establece en true
, instruirá al integrador que "muestre su trabajo": es decir, imprimirá en la consola todos los pasos tomados y todas las reglas aplicadas en una integración particular. Por ejemplo, integral("x^2 + sin(pi*x)", "x", {debugPrint: true})
produce la siguiente salida en la consola:
find integral of (x ^ 2) + (sin(pi * x)) dx
sum rule: find integral of x ^ 2 dx
Computed: (1 / (2 + 1)) * (x ^ (2 + 1))
sum rule: find integral of sin(pi * x) dx
linear substitution: find integral of sin(x) dx
Computed: -(cos(x))
Computed: (-(cos(pi * x))) / (pi * 1)
Computed: ((1 / (2 + 1)) * (x ^ (2 + 1))) + ((-(cos(pi * x))) / (pi * 1))
El uso de debugPrint
es una buena manera de aprender cómo las reglas de integración interactúan y se combinan para encontrar integrales, y es extremadamente útil al desarrollar reglas de integración personalizadas.
El algoritmo de integración utilizado por esta implementación se basa en una coincidencia de patrones de búsqueda de búsqueda en profundidad. Cada patrón se especifica como una función que intenta calcular la integral directamente, o reescribir o dividir el integrando en una expresión que es más fácil de integrar y calcular la integral de eso. El núcleo del integrador es la regla agnóstica: de forma predeterminada, utiliza un conjunto de reglas de integración estándar almacenadas en integral.rules
, aunque se admite el uso de reglas personalizadas (consulte la sección Reglas personalizadas).
La memorización de Integrands ofrece no solo una aceleración para las integrales comunes de las subexpresiones, sino que también previene los bucles infinitos si dos reglas se deshacen entre sí (como si uno multiplique exponentes, y el otro combina estos factores comunes). Sin embargo, este algoritmo todavía es susceptible a una regla (o a varias reglas de interacción) que puede aplicar un número infinito de veces que produce una nueva integr y cada aplicación; Dicha regla haría que el integrador se recurre indefinidamente (o, hasta que se consuma todo el espacio o la memoria de la pila).
Debido a la simplicidad de este enfoque (y la etapa temprana relativa de desarrollo de este paquete), existen muchas limitaciones en esta implementación actual. Para dar una lista incompleta, actualmente no hay reglas para respaldar lo siguiente:
2 * x * cos(x^2)
3 * x^2 * e^(x^3)
x * ln(x)
x^3 * e^x
cos(x) * tan(x)
e ^ -(x^2)
y similares usando erf
Si implementa una regla para manejar uno de estos casos (o cualquier otro caso currenal sin apoyo), ¡envíe una solicitud de extracción!
Copyright (c) 2018 Joel Hoover ([email protected])
Licenciado bajo la licencia Apache, versión 2.0 (la "licencia"); No puede usar este archivo, excepto de conformidad con la licencia. Puede obtener una copia de la licencia en
http://www.apache.org/licenses/license-2.0
A menos que la ley aplicable sea requerida o acordado por escrito, el software distribuido bajo la licencia se distribuye de manera "como es", sin garantías o condiciones de ningún tipo, ya sea expresas o implícitas. Consulte la licencia para los permisos y limitaciones de rigor de idioma específico bajo la licencia.