该库是流行的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
除非适用法律要求或以书面形式同意,否则根据许可证分配的软件是按照“原样”分发的,没有任何明示或暗示的任何形式的保证或条件。请参阅许可证的许可,以获取许可条款中的权限和限制。