假设我们有一个有限的字母,例如X = [1,2,3,..., n]
和一个映射f
,其中的键X
和值也X
({{ 1}}至X
)。
定义:另一个功能平方根或组成平方根或半迭代是另一个将X
中的键和g
中的值映射到X
,使得X
中所有g[g[x]]==f[x]
的{{1}}。
示例1:如果x
,则X
可以是f = {'A':'A', 'B':'A', 'C':'A'}
的函数平方根。功能平方根不是唯一的。映射g = {'A':'A', 'B':'A', 'C':'B'}
也是它自己的函数平方根。
示例2:地图f
没有功能平方根。实际上,如果我们定义f
,则f = ['A':'B', 'B':'A']
将是g['A'] = 'A'
的固定点,因此它必须是'A'
的固定点。如果定义g
,则需要定义f
,并且g['A'] = 'B'
必须是g['B'] = 'B'
的固定点。因此,有时功能平方根不存在。
我有时是手工计算的,但是现在我想我真的没有一个有效的策略来计算它。
问题: [设计一种有效算法,以根据给定的输入图计算一个函数平方根。
我认为首先确定要保证输入具有函数平方根的情况是公平的。
算法的存在性:始终存在一种蛮力解决方案,即生成从'B'
到f
的所有地图g
并对其进行组合以进行检查如果它们等于X
。
到目前为止,我已经看到一些观察结果,可以减少某些输入的问题:
X
,这样f
就可以定义x
。f[x] == x
和g[x] = x
的每个键y
允许用户定义f[y] == x
。f[x] == x
不应将其他键映射到g[y] = x
的固定点。g
是内射词(没有两个键发送到相同的值),则f
是{{ 1}}在这种情况下,可以根据其cycle decomposition of the permutation计算平方根。查找循环分解可以一次完成,并从该also起平方根。 对于双射平方根可以线性计算(看起来)的事实使我希望可以有某种有效的方法来计算一般情况。如果我的定义正确,那么问题就在于NP,因为给定的f
可以验证f
在线性时间内是X
的成分平方根。对我来说,它闻起来不像NP完全,但我对证明这些减少从一个问题到另一个问题的经验很少。
也可以通过以下方式查看问题。输入映射g
可以看作是一个有限自动机的有向图,其中每个状态的度数为1。计算成分平方根将是找到一个具有相同状态集的自动机,其行为类似于一次跨两步时是原始的。
答案 0 :(得分:2)
问题可以分为两个问题。
如果采用f
,f^2
,f^3
的范围的交集,则...将会得出{{ 1}}作为一个排列。如您在观察4中所指出的,我们可以找到置换的所有平方根。可能有很多这样的选择,但是我们知道在寻找这些选择的过程中我们会做出哪些选择。我们要么将相同长度的循环配对一些旋转,要么重新排序一个奇数长度的循环。如果我们不能做到这一点,那么就没有平方根,并且可以通过做出这两种选择的方式来列举所有产生平方根的方法。
第二个问题是瞬态值,它们形成以Y
结尾的链。链条很容易找到,我们知道它们的终点。如果f
是Y
的平方根,则长度g
或f
的{{1}}的链必须是一对{长度为2k
且2k-1
或g
的{1}}使得第一个的结尾是f
,其中k
是第二个的结尾。这是一个非常强的条件,因为要么这些链都终止于同一长度的奇数周期,而可能较短的链则终止于k
的一半,或者这些链均终止于相同长度的不同周期,并且来自一个长度均匀的循环。
因此,我建议按以下方式解决该问题。
首先将X变成一个图形,其中您有一个从k-1
到g(x)
的有向箭头。查找所有周期和链。所有循环的并集为x
,首先验证p
在x
中具有平方根。之后,检查链条是否可以匹配。如果没有,则没有平方根。
如果您通过了几次健全性检查,则尝试实际将链递归地匹配到包含它们的图部分的工作平方根。如果成功,那么您可以轻松地匹配其余的循环,并且具有平方根。如果失败,则没有平方根。
在大多数情况下,您会发现没有平方根相当快。可能缓慢的方法是递归地匹配链。希望这些决定不会太多,而且很容易做出,但是先验地,指数性地回溯并不是不可能的。
答案 1 :(得分:1)
有一个平方矩阵可以为任何称为Carleman matrix的微分函数创建,定义为:
carleman[j,k] = (dk/dx^k (f(x)^j)) / k!
其中n!
是n
和x=0
的阶乘。例如,e^x
的3x3 Carleman矩阵为:
[
[1, 0, 0],
[1, 1, 0.5],
[1, 1, 2]
]
由于使用了导数,因此在第二行上可以看到e^x
的泰勒展开,在第三行上可以看到(e^x)^2
或e^2x
的泰勒展开,依此类推上。稍后将很重要。
请注意,将矩阵f(x)
和g(x)
的两个Carleman矩阵相乘得到的矩阵为f(g(x))
的Carleman矩阵,因此,如果对f(x)
的矩阵求平方,则获取f(f(x))
的矩阵。这意味着,如果我们可以找到函数的Carleman矩阵的“平方根”,则可以免费获得它的一半迭代的Carleman矩阵。
幸运的是,人们已经找到了解决这一问题的数值方法。一种迭代方法称为Denman-Beavers Method,定义为:
Y[k+1] = (Y[k]*(Z[k]^-1))/2
Z[k+1] = (Z[k]*(Y[k]^-1))/2
将Y[0]
初始化为输入矩阵,并将Z[0]
初始化为n×n单位矩阵。我已经在numerical.js Github库中实现了Carleman矩阵和Denman-Beavers平方根(最多500次迭代)。取e^x
的上述3x3 Carleman矩阵的平方根后,我得到:
[
[1, 0, 0],
[0.5, 0.8944271891673152, 0.22360679791657895],
[0.23606797789307893, 0.8944271883343149, 1.3416407866664737],
]
(请注意,这里的无理数似乎可疑地接近sqrt(5)/10
和4*sqrt(5)/2
,这可能是Denman迭代的结果。)
新的半迭代Carleman矩阵的泰勒展开式将显示在第二行,因此我们可以将e^x
的半迭代近似为
f(x)=0.5+0.8944271883343149x+0.22360679791657895x^{2}
以下是f(f(x))
(蓝色)与e^x
(绿色)的图:
您可以看到x=0.189
处有一条切线,尽管e^x
在超出多项式后逐渐追赶。使用Require.js并使用以下方法安装我的数字库后,该策略基本上可以应用于Javascript中的任何函数:
require(["numerical"], function(numerical) {
console.log((numerical.Matrix.carleman(<function>,
<number of expansion terms>)).sqrt().array[1]);
}
但是请注意,我的泰勒多项式目前在数值上不稳定,它将在4或5个项后爆炸(即将更新),因此不要尝试使用太多的项。