J:牛顿方法的默示副词
Posted
技术标签:
【中文标题】J:牛顿方法的默示副词【英文标题】:J: Tacit adverb of Newton's method 【发布时间】:2014-12-28 16:52:15 【问题描述】:我在'addons/math/misc/brent.ijs'
中找到了将布伦特方法作为副词的实现。我也想建立一个牛顿法作为副词,但这比建立默示动词要困难得多。
这是牛顿迭代的显式版本:
newton_i =: 1 : '] - u % u d.1'
这样的用法:
2&o. newton_i^:_ (1) NB. (-: 1p1) must be found
1.5708
2 o. 1.5708 NB. after substitution we get almost 0
_3.67321e_6
当然,为了方便:
newton =: 1 : 'u newton_i^:_'
什么是默认等价物?
【问题讨论】:
我认为d.
在这种情况下会阻止你写一个默认副词。
简短的回答是n_i =: d.0 1 (%/@:) (-`) (]`) (`:6)
和newton =: n_i (^:_)
。我稍后会回来explain why(我现在正在打电话)。
@DanBron,非常感谢!在您的消息链接的帮助下,我已经了解了所有内容,除了为什么 (-`) (]`) (`:6)
而不是 (]`) (-`) (`:6)
用于构建 ] - f
fork。
Danylo:因为副词列车是从左到右的(即 LIFO);将f (d.0 1) (%/@:)
视为建立(有效)(f % f d.1)
的黑匣子;那么你得到了black_box (`-) (`])
,它在reverse (LIFO) 中读取,读取为]
,-
,black_box
,然后被执行到火车] - black_box
。不,这里真正的诡计是使用 d.0 1
:) 。这是否清楚,还是您仍然希望我发布正式答案?
Dan,我已经完全理解 f (d.0 1) (%/@:)
的把戏 :) - 确实很酷:我们计算 f
的零和一阶导数,然后在它们之间插入 %
。我也理解了你写这三个副词的顺序。非常感谢!
【参考方案1】:
TL;DR
根据the comments,一个简短的回答;与原始、显式的newton_i
和newton
的默认等效分别是:
n_i =: d.0 1 (%/@:) (]`-`) (`:6)
newton =: n_i (^:_)
一般而言,有关如何获得此类翻译的一些技术,可以在 the J Forums 上找到。
建设
这里的关键见解是 (a) 一个函数与它自己的“零阶导数”相同,并且 (b) 我们可以同时计算 J 中函数的“零阶”和一阶导数,这要归功于语言的面向数组的性质。剩下的就是集邮了。
在一个理想的世界中,给定一个函数f
,我们想生成一个像(] - f % f d. 1)
这样的动词序列。问题是 J 中的隐性状语编程限制我们产生一个动词,它只提到一次输入函数 (f
)。
因此,相反,我们使用了一个偷偷摸摸的技巧:我们同时计算f
的两个导数:“零”导数(这是一个恒等函数)和一阶导数。
load 'trig'
sin NB. Sine function (special case of the "circle functions", o.)
1&o.
sin d. 1 f. NB. First derivative of sine, sin'.
2&o.
sin d. 0 f. NB. "Zeroeth" derivative of sine, i.e. sine.
1&o."0
sin d. 0 1 f. NB. Both, resulting in two outputs.
(1&o. , 2&o.)"0
znfd =: d. 0 1 NB. Packaged up as a re-usable name.
sin znfd f.
(1&o. , 2&o.)"0
然后我们只需在它们之间插入一个除法:
dh =: znfd (%/@) NB. Quotient of first-derivative over 0th-derivattive
sin dh
%/@(sin d.0 1)
sin dh f.
%/@((1&o. , 2&o.)"0)
sin dh 1p1 NB. 0
_1.22465e_16
sin 1p1 NB. sin(pi) = 0
1.22465e_16
sin d. 1 ] 1p1 NB. sin'(pi) = -1
_1
sin dh 1p1 NB. sin(pi)/sin'(pi) = 0/-1 = 0
_1.22465e_16
(%/@)
位于 znfd
的右侧,因为 J 中的隐性副词编程是 LIFO(即从左到右,而“正常”J 是从右到左)。
集邮
正如我所说,剩下的代码只是集邮,使用标准工具构建一个动词序列,从原始输入中减去这个商:
ssub =: (]`-`) (`:6) NB. x - f(x)
+: ssub NB. x - double(x)
] - +:
-: ssub NB. x - halve(x)
] - -:
-: ssub 16 NB. 16 - halve(16)
8
+: ssub 16 NB. 16 - double(16)
_16
*: ssub 16 NB. 16 - square(16)
_240
%: ssub 16 NB. 16 - sqrt(16)
12
因此:
n_i =: znfd ssub NB. x - f'(x)/f(x)
最后,使用^:_
中的"apply until fixed point" feature,我们有:
newton =: n_i (^:_)
瞧。
【讨论】:
非常好的方法和解决方案。 @DanBron,我已经在您的回答中添加了我所理解的解释。你收到了吗? @Danylo,我没有,可能在我收到通知之前被其他用户拒绝了?你想添加一个我可以复制粘贴的答案吗? @DanBron,不,我太懒了。你的解释 here 很棒。 另外,请注意,这可以很容易地扩展到更多变量的函数:n_i =: D.0 1 (%./@:) (]`-`) (`:6)
【参考方案2】:
newton_i =: 1 : '] - u % u d.1'
是半默示的,即默示动词与动词结合时产生(副词在结合时消失)。
newton_i2 =: 1 : '(] - u % u d.1) y'
是完全明确的,因为与动词的绑定不会解析副词。
+ 1 : 'u/'
+/
+ 1 : 'u/ y'
+ (1 : 'u/y')
使半默示副词完全默示并不重要,因为可能没有性能提升,并且它具有在副词区域而不是调用者中解决的相同好处(完全显式副词的情况) .
【讨论】:
以上是关于J:牛顿方法的默示副词的主要内容,如果未能解决你的问题,请参考以下文章