該庫是流行的Math.js庫的擴展。它添加了一個integral
函數,能夠找到簡單數學函數的積分。它在所使用的集成規則中也很靈活,可以使用自定義規則,而不是標準規則。
請注意,該軟件仍然被視為beta,因此,如果您遇到任何錯誤或粗糙邊緣,請提交問題!
要安裝軟件包,請使用以下內容:
npm install mathjs-simple-integral
要使用Math.js註冊擴展名,請使用以下內容:
math . import ( require ( 'mathjs-simple-integral' ) ) ;
這將添加函數math.integral
。
此擴展程序的基本用法非常容易:只需提供積分(作為Node
或字符串)和集成的變量(作為SymbolNode
或字符串):
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'
如果integral
無法找到給定表達式的積分,它將丟棄錯誤:
math . integral ( 'e^(x^2)' ) ; // Error: Unable to find integral of "e ^ (x ^ 2)" with respect to "x"
默認情況下, integral
運行math.simplify
,因為集成過程可以產生一些笨拙的表達式。但是,通過將simplify
設置為false
options
integral
傳遞到可選的第三參數:
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))'
在此實現中,集成規則定義為作為參數(1) expr
的函數,即要集成的表達式; (2) context
,集成的上下文; (3) subIntegral
,該函數試圖集成積分的子表達或重寫形式。然後,集成規則將返回計算的積分,或者如果無法找到一個null
。除了已經實施的許多標準集成(位於math.integral.rules
)外,還可以指定一組自定義的集成規則。
例如,假設我們添加了代表上部不完整伽馬功能的自定義函數myUpperGamma
,現在我們想添加以集成它的支持,尤其是我們希望實現此規則: integral("myUpperGamma(s,x)", "x") = x*myUpperGamma(s,x) - myUpperGamma(s+1, x)
(在此處驗證)。首先,讓我們將此規則寫為一個函數:
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
}
現在我們有了我們的自定義集成規則,我們可以將其添加到標準規則列表中,並使用此組合列表查找涉及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)'
現在假設除了myUpperGamma
外,我們還有另一個自定義函數mySum
:就像add
一樣,它將接受可變數量的參數並將參數添加在一起,但是它也執行了其他一些非數學功能(例如在評估,評估,評估之前記錄每個參數,或檢查以確保其參數都不是NaN
)。現在,我們可以將規則添加到代表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
}
請注意,我們如何使用subIntegral
回調來查找總和中所有術語的積分,然後僅在可以集成所有單個項時才能返回整個mySum
表達式的積分。現在,如果我們使用兩個自定義規則,我們可以將表達式與mySum
和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))'
選項對象可以具有屬性debugPrint
,如果設置為true
,將指示集成商“顯示其工作”:也就是說,它將在控制台上打印所有採取的步驟以及在特定集成中應用的所有規則。例如, integral("x^2 + sin(pi*x)", "x", {debugPrint: true})
在控制台上產生以下輸出:
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))
使用debugPrint
是學習集成規則如何相互作用和結合以找到積分的好方法,並且在製定自定義集成規則時非常有幫助。
此實現使用的集成算法基於深度優先搜索的記憶模式匹配。每個模式被指定為試圖直接計算積分的函數,或者將整數重寫或將整體分配為更易於集成的表達式,併計算其積分的積分。集成商的核心是規則不可知:默認情況下,它使用一組存儲在integral.rules
中的標準集成規則,儘管支持使用自定義規則(請參閱“自定義規則”部分)。
集成的記憶不僅為子表達的常見積分加速,而且如果兩個規則相互撤消(例如一個乘以指數,而另一個結合了這些共同因素),則可以防止無限循環。但是,該算法仍然容易受到規則(或幾個相互作用的規則)的影響,該規則可以應用無限次數,從而產生新的,獨特的集成每個應用程序;這樣的規則將導致積分器無限期地重新爆發(或直到所有堆棧空間或內存消耗)。
由於這種方法的簡單性(以及該軟件包的相對早期階段),因此目前的實現存在許多局限性。為了給出不完整的列表,目前沒有任何規則支持以下內容:
2 * x * cos(x^2)
3 * x^2 * e^(x^3)
x * ln(x)
x^3 * e^x
cos(x) * tan(x)
之類的表達式所需erf
整合e ^ -(x^2)
等如果實施一項規則來處理這些案件之一(或任何其他浮雕的案例),請提交拉動請求!
版權(C)2018 Joel Hoover([email protected])
根據Apache許可證(版本2.0(“許可”)獲得許可;除了符合許可外,您不得使用此文件。您可以在
http://www.apache.org/licenses/license-2.0
除非適用法律要求或以書面形式同意,否則根據許可證分配的軟件是按照“原樣”分發的,沒有任何明示或暗示的任何形式的保證或條件。請參閱許可證的許可,以獲取許可條款中的權限和限制。