Cette bibliothèque est une extension pour la bibliothèque populaire Math.JS. Il ajoute une fonction integral
capable de trouver les intégrales de fonctions mathématiques simples. Il est également flexible dans les règles d'intégration utilisées, permettant à des règles personnalisées d'être utilisées à la place ou en plus des règles de normes.
Notez que ce logiciel est toujours considéré comme bêta, donc si vous rencontrez un bogue ou des bords rugueux, veuillez soumettre un problème!
Pour installer le package, utilisez ce qui suit:
npm install mathjs-simple-integral
Pour enregistrer l'extension avec math.js, utilisez ce qui suit:
math . import ( require ( 'mathjs-simple-integral' ) ) ;
Cela ajoutera la fonction math.integral
à Math.js.
L'utilisation de base de cette extension est très facile: fournissez simplement l'intégrand (soit en tant que Node
ou une chaîne) et la variable d'intégration (soit en tant que SymbolNode
ou une chaîne):
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
n'est pas en mesure de trouver l'intégrale de l'expression donnée, elle lancera une erreur:
math . integral ( 'e^(x^2)' ) ; // Error: Unable to find integral of "e ^ (x ^ 2)" with respect to "x"
Par défaut, integral
exécute math.simplify
sur la sortie, car le processus d'intégration peut produire des expressions lourdes. Cependant, il est possible d'obtenir une sortie brute et non simplifiée de integral
en transmettant un objet options
avec simplify
Set sur false
au troisième paramètre facultatif:
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))'
Dans cette implémentation, les règles d'intégration sont définies comme une fonction qui prend comme paramètres (1) expr
, l'expression à intégrer; (2) context
, contexte de l'intégration; et (3) subIntegral
, une fonction qui essaie d'intégrer une sous-expression ou une forme réécrite de l'intégrale. La règle d'intégration renvoie ensuite l'intégrale calculée ou null
si elle n'a pas pu en trouver une. En plus de nombreuses intégations standard déjà implémentées (situées sur math.integral.rules
), un ensemble personnalisé de règles d'intégration peut être spécifié.
Par exemple, supposons que nous ayons ajouté une fonction personnalisée myUpperGamma
représentant la fonction gamma incomplète supérieure, et nous voulons maintenant ajouter le support pour l'intégrer, en particulier nous voulons implémenter cette règle: integral("myUpperGamma(s,x)", "x") = x*myUpperGamma(s,x) - myUpperGamma(s+1, x)
(vérifiez ici). Tout d'abord, écrivons cette règle en fonction:
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
}
Maintenant que nous avons notre règle d'intégration personnalisée, nous pouvons l'ajouter à la liste des règles standard et utiliser cette liste combinée pour trouver des intégrales impliquant 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)'
Supposons maintenant qu'en plus de myUpperGamma
, nous avons une autre fonction personnalisée mySum
: tout comme add
, il acceptera un nombre variable d'arguments et ajoutera les arguments ensemble, mais il remplira également une autre fonction non mathématique (comme la journalisation de chaque argument avant l'évaluation, ou vérifier pour s'assurer qu'aucun de ses arguments n'est NaN
). Maintenant, nous pouvons ajouter des règles à l'intégrateur qui représentent la linéarité de l'intégrale sur 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
}
Remarquez comment nous utilisons le rappel subIntegral
pour trouver l'intégrale de tous les termes de la somme, puis renvoie une intégrale pour toute l'expression mySum
que si tous les termes individuels ne pouvaient être intégrés. Maintenant, si nous utilisons nos deux règles personnalisées, nous pouvons intégrer des expressions à mySum
et 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))'
L'objet Options peut avoir une debugPrint
immobilier qui, si elle est définie sur true
, demandera à l'intégrateur de "montrer son travail": c'est-à-dire qu'il imprimera à la console toutes les étapes prises et toutes les règles appliquées dans une intégration particulière. Par exemple, integral("x^2 + sin(pi*x)", "x", {debugPrint: true})
produit la sortie suivante sur la 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))
L'utilisation debugPrint
est un bon moyen d'apprendre comment les règles d'intégration interagissent et combinent pour trouver des intégrales, et est extrêmement utile lors du développement de règles d'intégration personnalisées.
L'algorithme d'intégration utilisé par cette implémentation est basé sur une correspondance de modèle de recherche d'abord en profondeur. Chaque modèle est spécifié comme une fonction qui tente de calculer directement l'intégrale, soit de réécrire ou de diviser l'intégrand en une expression plus facile à intégrer, et de calculer l'intégrale de cela. Le noyau de l'intégrateur est agnostique de règle: par défaut, il utilise un ensemble de règles d'intégration standard stockées sur integral.rules
, bien que l'utilisation de règles personnalisées soit prise en charge (voir la section Règles personnalisées).
La mémorisation des intégrands offre non seulement une accélération pour les intégrales communes des sous-expressions, mais empêche également les boucles infinies si deux règles se défoncent (comme si l'on se multiplie des exposants, et l'autre combine ces facteurs communs). Cependant, cet algorithme est toujours sensible à une règle (ou à plusieurs règles en interaction) qui peuvent appliquer un nombre infini de fois produisant une nouvelle intégand unique à chaque application; Une telle règle ferait que l'intégrateur se reproduit indéfiniment (ou, jusqu'à ce que tout l'espace ou la mémoire soit consommée).
En raison de la simplicité de cette approche (et du stade précoce relatif du développement de ce package), il existe de nombreuses limites dans cette implémentation actuelle. Pour donner une liste incomplète, il n'y a actuellement aucune règle pour soutenir ce qui suit:
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)
et similaires en utilisant erf
Si vous implémentez une règle pour gérer l'un de ces cas (ou tout autre cas non pris en charge Currenly), veuillez soumettre une demande de traction!
Copyright (c) 2018 Joel Hoover ([email protected])
Licencié sous la licence Apache, version 2.0 (la "licence"); Vous ne pouvez pas utiliser ce fichier sauf conforme à la licence. Vous pouvez obtenir une copie de la licence à
http://www.apache.org/licenses/license-2.0
Sauf exiger la loi applicable ou convenu par écrit, les logiciels distribués en vertu de la licence sont distribués sur une base «tel quel», sans garantie ou conditions d'aucune sorte, expresse ou implicite. Voir la licence pour la langue spécifique régissant les autorisations et les limitations sous la licence.