Diese Bibliothek ist eine Erweiterung für die beliebte Bibliothek von Math.js. Es fügt eine integral
Funktion hinzu, die in der Lage ist, die Integrale einfacher mathematischer Funktionen zu finden. Es ist auch flexibel in den verwendeten Integrationsregeln, sodass benutzerdefinierte Regeln anstelle oder zusätzlich zu den Standardregeln verwendet werden können.
Beachten Sie, dass diese Software weiterhin als Beta angesehen wird. Wenn Sie also auf Fehler oder grobe Kanten stoßen, geben Sie bitte ein Problem ein!
Verwenden Sie Folgendes, um das Paket zu installieren:
npm install mathjs-simple-integral
Verwenden Sie Folgendes, um die Erweiterung mit Math.js zu registrieren:
math . import ( require ( 'mathjs-simple-integral' ) ) ;
Dadurch wird math.integral
Die grundlegende Verwendung dieser Erweiterung ist sehr einfach: Geben Sie einfach den Integrand (entweder als Node
oder eine Zeichenfolge) und die Variable der Integration (entweder als SymbolNode
oder eine Zeichenfolge) an:
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'
Wenn integral
das Integral des angegebenen Ausdrucks nicht finden kann, wird ein Fehler verurteilt:
math . integral ( 'e^(x^2)' ) ; // Error: Unable to find integral of "e ^ (x ^ 2)" with respect to "x"
Standardmäßig läuft integral
math.simplify
für die Ausgabe, da der Integrationsprozess einige unhandliche Ausdrücke erzeugen kann. Es ist jedoch möglich, eine rohe, nicht festgelegte Ausgabe von integral
zu erhalten, indem ein options
mit einer simplify
auf false
auf den optionalen dritten Parameter eingestellt wird:
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))'
In dieser Implementierung werden die Integrationsregeln als eine Funktion definiert, die als Parameter (1) expr
dauert, wobei der Ausdruck integriert wird. (2) context
, der Kontext der Integration; und (3) subIntegral
, eine Funktion, die versucht, eine Unterexpression oder umgeschriebene Form des Integrals zu integrieren. Die Integrationsregel gibt dann das berechnete Integral oder null
zurück, wenn es keine finden konnte. Zusätzlich zu vielen bereits implementierten Standardintegrationen (befindet sich bei math.integral.rules
) können ein benutzerdefinierter Satz von Integrationsregeln angegeben werden.
Angenommen, wir haben eine benutzerdefinierte Funktion myUpperGamma
hinzugefügt, die die obere unvollständige Gamma -Funktion darstellt, und wir möchten nun Unterstützung für die Integration hinzufügen, insbesondere wir möchten diese Regel implementieren: integral("myUpperGamma(s,x)", "x") = x*myUpperGamma(s,x) - myUpperGamma(s+1, x)
(Überprüfen Sie hier). Lassen Sie uns zunächst diese Regel als Funktion schreiben:
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
}
Nachdem wir unsere benutzerdefinierte Integrationsregel haben, können wir sie der Liste der Standardregeln hinzufügen und diese kombinierte Liste verwenden, um Integrale mit myUpperGamma
zu finden!
// 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)'
Nehmen wir nun an, zusätzlich zu myUpperGamma
haben wir eine andere benutzerdefinierte Funktion mySum
: genau wie bei add
wird es eine variable Anzahl von Argumenten akzeptieren und die Argumente zusammen hinzufügen, aber es führt auch eine andere nichtmathematische Funktion aus (z. B. jedes Argument vor der Bewertung oder prüfen, ob keines seiner Argumente NaN
sind). Jetzt können wir dem Integrator Regeln hinzufügen, die die Linearität des Integrals über mySum
darstellen:
// 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
}
Beachten Sie, wie wir den subIntegral
Rückruf verwenden, um das Integral aller Begriffe in der Summe zu finden, und gibt dann nur ein Integral für den gesamten mySum
-Ausdruck zurück, wenn alle einzelnen Begriffe integriert werden könnten. Wenn wir jetzt unsere beiden benutzerdefinierten Regeln verwenden, können wir Ausdrücke sowohl in mySum
als auch in myUpperGamma
integrieren:
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))'
Das Optionsobjekt kann einen Immobilien debugPrint
haben, der den Integrator, wenn er auf true
festgelegt ist, "seine Arbeit anzeigen" anweist: dh er wird in die Konsole gedruckt, die alle gestellten Schritte und alle in einer bestimmten Integration angewendeten Regeln angewendet werden. Beispielsweise erzeugt integral("x^2 + sin(pi*x)", "x", {debugPrint: true})
die folgende Ausgabe auf der Konsole:
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))
Die Verwendung von debugPrint
ist ein guter Weg, um zu erfahren, wie die Integrationsregeln interagieren und sich zusammenschließen, um Integrale zu finden, und ist äußerst hilfreich bei der Entwicklung benutzerdefinierter Integrationsregeln.
Der in dieser Implementierung verwendete Integrationsalgorithmus basiert auf einer mäugnem memoisierten Memo-Anpassung an Tiefen. Jedes Muster wird als eine Funktion angegeben, die versucht, entweder das Integral direkt zu berechnen oder den Integranden in einen Ausdruck umzuschreiben oder aufzuteilen, der einfacher zu integrieren ist, und das Integral davon zu berechnen. Der Kern des Integrators ist Regel Agnostic: Standardmäßig verwendet es eine Reihe von Standard -Integrationsregeln, die bei integral.rules
gespeichert sind, obwohl die Verwendung benutzerdefinierter Regeln unterstützt wird (siehe Abschnitt benutzerdefinierte Regeln).
Die Memoisierung von Integrands bietet nicht nur eine Beschleunigung für gemeinsame Integrale von Subexpressionen, sondern verhindert auch unendliche Schleifen, wenn sich zwei Regeln gegenseitig rückgängig machen (z. B. wenn man Exponenten verteilt und der andere diese gemeinsamen Faktoren kombiniert). Dieser Algorithmus ist jedoch immer noch anfällig für eine Regel (oder mehrere interagierende Regeln), die eine unendliche Häufigkeit anwenden können, um eine neue, einzigartige Integrand bei jeder Anwendung zu erzeugen. Eine solche Regel würde dazu führen, dass der Integrator auf unbestimmte Zeit wieder auftritt (oder, bis der gesamte Stapelraum oder der Gedächtnis verzehrt wird).
Aufgrund der Einfachheit dieses Ansatzes (und der relativen frühen Entwicklungsphase dieses Pakets) gibt es in dieser aktuellen Implementierung viele Einschränkungen. Um eine unvollständige Liste zu geben, gibt es derzeit keine Regeln, um Folgendes zu unterstützen:
2 * x * cos(x^2)
3 * x^2 * e^(x^3)
x * ln(x)
x^3 * e^x
cos(x) * tan(x)
erforderlich iste ^ -(x^2)
und dergleichen mit erf
Wenn Sie eine Regel für einen dieser Fälle (oder einen anderen nicht unterstützten Fall) implementieren, senden Sie bitte eine Pull -Anfrage!
Copyright (C) 2018 Joel Hoover ([email protected])
Lizenziert unter der Apache -Lizenz, Version 2.0 (der "Lizenz"); Sie dürfen diese Datei nur in Übereinstimmung mit der Lizenz verwenden. Sie können eine Kopie der Lizenz bei erhalten
http://www.apache.org/licenses/license-2.0
Sofern nicht nach geltendem Recht oder schriftlich zu vereinbart wird, wird die im Rahmen der Lizenz verteilte Software auf "As is" -Basis ohne Gewährleistung oder Bedingungen jeglicher Art ausdrücklich oder impliziert verteilt. Siehe die Lizenz für die spezifischen Sprachberechtigungen und Einschränkungen im Rahmen der Lizenz.