Esta biblioteca é uma extensão da popular biblioteca Math.JS. Ele adiciona uma função integral
capaz de encontrar as integrais de funções matemáticas simples. Também é flexível nas regras de integração utilizadas, permitindo que regras personalizadas sejam usadas em vez de ou além das regras de padrões.
Observe que este software ainda é considerado beta; portanto, se você encontrar algum bug ou arestas, envie um problema!
Para instalar o pacote, use o seguinte:
npm install mathjs-simple-integral
Para registrar a extensão no Math.js, use o seguinte:
math . import ( require ( 'mathjs-simple-integral' ) ) ;
Isso adicionará a função math.integral
a Math.JS.
O uso básico desta extensão é muito fácil: basta fornecer o integrando (como um Node
ou uma string) e a variável de integração (como um SymbolNode
ou uma string):
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'
Se integral
não puder encontrar a integral da expressão dada, ele apresentará um erro:
math . integral ( 'e^(x^2)' ) ; // Error: Unable to find integral of "e ^ (x ^ 2)" with respect to "x"
Por padrão, integral
executa math.simplify
na saída, pois o processo de integração pode produzir algumas expressões pesadas. No entanto, é possível obter saída crua e não implicada da integral
, passando um objeto options
com simplify
definido como false
para o terceiro 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))'
Nesta implementação, as regras de integração são definidas como uma função que toma como parâmetros (1) expr
, a expressão a ser integrada; (2) context
, o contexto da integração; e (3) subIntegral
, uma função que tenta integrar uma subexpressão ou forma reescrita da integral. A regra de integração retorna a integral calculada ou null
se não conseguir encontrar uma. Além de muitas integração padrão já implementada (localizada em math.integral.rules
), um conjunto personalizado de regras de integração pode ser especificado.
Por exemplo, suponha que adicionamos uma função personalizada myUpperGamma
representando a função gama incompleta superior, e agora queremos adicionar suporte para integrá -lo, particularmente queremos implementar esta regra: integral("myUpperGamma(s,x)", "x") = x*myUpperGamma(s,x) - myUpperGamma(s+1, x)
(verifique aqui). Primeiro, vamos escrever esta regra como uma função:
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
}
Agora que temos nossa regra de integração personalizada, podemos adicioná -la à lista de regras padrão e usar esta lista combinada para encontrar integrais envolvendo 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)'
Agora, suponha que, além do myUpperGamma
, temos outra função personalizada mySum
: assim como add
, ele aceitará um número variável de argumentos e adicionará os argumentos, mas também desempenha alguma outra função não matemática (como registrar cada argumento antes da avaliação, ou verificando para garantir que nenhum de seus argumentos seja NaN
). Agora, podemos adicionar regras ao integrador que representam a linearidade da 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 como usamos o retorno de chamada subIntegral
para encontrar a integral de todos os termos na soma e, em seguida, retorna uma parte integrante de toda a expressão mySum
apenas se todos os termos individuais puderam ser integrados. Agora, se usarmos as duas regras personalizadas, podemos integrar expressões com mySum
e 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))'
O objeto Options pode ter uma debugPrint
de propriedades que, se definido como true
, instruirá o integrador a "mostrar seu trabalho": ou seja, ele imprimirá no console todas as etapas tomadas e todas as regras aplicadas em uma integração específica. Por exemplo, integral("x^2 + sin(pi*x)", "x", {debugPrint: true})
produz a seguinte saída no console:
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))
O uso debugPrint
é uma boa maneira de aprender como as regras de integração interagem e combinam para encontrar integrais e é extremamente útil ao desenvolver regras de integração personalizada.
O algoritmo de integração usado por esta implementação é baseado em uma correspondência de padrões memorizados pela primeira vez em profundidade. Cada padrão é especificado como uma função que tenta calcular a integral diretamente ou reescrever ou dividir o integração em uma expressão mais fácil de integrar e calcular a integral disso. O núcleo do integrador é a regra agnóstica: por padrão, ele usa um conjunto de regras de integração padrão armazenadas no integral.rules
, embora o uso de regras personalizadas seja suportado (consulte a seção de regras personalizadas).
A memórias de integrando oferece não apenas uma aceleração para integrais comuns de subexpressões, mas também impede loops infinitos se duas regras se desfazer (como se alguém multiplicar os expoentes e o outro combinarem esses fatores comuns). No entanto, esse algoritmo ainda é suscetível a uma regra (ou a várias regras de interação) que podem aplicar um número infinito de vezes que produz um integrando novo e exclusivo a cada aplicativo; Essa regra faria com que o integrador recorrente indefinidamente (ou, até que todo o espaço ou memória da pilha seja consumido).
Devido à simplicidade dessa abordagem (e ao estágio inicial relativo do desenvolvimento deste pacote), existem muitas limitações nessa implementação atual. Para dar uma lista incompleta, atualmente não há regras para apoiar o seguinte:
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)
e erf
Se implementar uma regra para lidar com um desses casos (ou qualquer outro caso currenly não suportado), envie uma solicitação de tração!
Copyright (c) 2018 Joel Hoover ([email protected])
Licenciado sob a licença Apache, versão 2.0 (a "licença"); Você não pode usar esse arquivo, exceto em conformidade com a licença. Você pode obter uma cópia da licença em
http://www.apache.org/license/license-2.0
A menos que exigido pela lei aplicável ou acordada por escrito, o software distribuído pela licença é distribuído "como está", sem garantias ou condições de qualquer tipo, expressa ou implícita. Consulte a licença para o idioma específico que rege as permissões e limitações sob a licença.