计算组成平方根的有效算法

时间:2019-08-01 18:14:41

标签: algorithm

假设我们有一个有限的字母,例如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


到目前为止,我已经看到一些观察结果,可以减少某些输入的问题:

  1. 每个固定点是一个密钥X,这样f就可以定义x
  2. 映射到固定点f[x] == xg[x] = x的每个键y允许用户定义f[y] == x
  3. 除了满足点(2)中条件的键外,f[x] == x不应将其他键映射到g[y] = x的固定点。
  4. 存在一种有效算法的情况:如果g是内射词(没有两个键发送到相同的值),则f是{{ 1}}在这种情况下,可以根据其cycle decomposition of the permutation计算平方根。查找循环分解可以一次完成,并从该also起平方根。

对于双射平方根可以线性计算(看起来)的事实使我希望可以有某种有效的方法来计算一般情况。如果我的定义正确,那么问题就在于NP,因为给定的f可以验证f在线性时间内是X的成分平方根。对我来说,它闻起来不像NP完全,但我对证明这些减少从一个问题到另一个问题的经验很少。


也可以通过以下方式查看问题。输入映射g可以看作是一个有限自动机的有向图,其中每个状态的度数为1。计算成分平方根将是找到一个具有相同状态集的自动机,其行为类似于一次跨两步时是原始的。

2 个答案:

答案 0 :(得分:2)

问题可以分为两个问题。

如果采用ff^2f^3的范围的交集,则...将会得出{{ 1}}作为一个排列。如您在观察4中所指出的,我们可以找到置换的所有平方根。可能有很多这样的选择,但是我们知道在寻找这些选择的过程中我们会做出哪些选择。我们要么将相同长度的循环配对一些旋转,要么重新排序一个奇数长度的循环。如果我们不能做到这一点,那么就没有平方根,并且可以通过做出这两种选择的方式来列举所有产生平方根的方法。

第二个问题是瞬态值,它们形成以Y结尾的链。链条很容易找到,我们知道它们的终点。如果fY的平方根,则长度gf的{​​{1}}的链必须是一对{长度为2k2k-1g的{​​1}}使得第一个的结尾是f,其中k是第二个的结尾。这是一个非常强的条件,因为要么这些链都终止于同一长度的奇数周期,而可能较短的链则终止于k的一半,或者这些链均终止于相同长度的不同周期,并且来自一个长度均匀的循环。

因此,我建议按以下方式解决该问题。

首先将X变成一个图形,其中您有一个从k-1g(x)的有向箭头。查找所有周期和链。所有循环的并集为x,首先验证px中具有平方根。之后,检查链条是否可以匹配。如果没有,则没有平方根。

如果您通过了几次健全性检查,则尝试实际将链递归地匹配到包含它们的图部分的工作平方根。如果成功,那么您可以轻松地匹配其余的循环,并且具有平方根。如果失败,则没有平方根。

在大多数情况下,您会发现没有平方根相当快。可能缓慢的方法是递归地匹配链。希望这些决定不会太多,而且很容易做出,但是先验地,指数性地回溯并不是不可能的。

答案 1 :(得分:1)

有一个平方矩阵可以为任何称为Carleman matrix的微分函数创建,定义为:

carleman[j,k] = (dk/dx^k (f(x)^j)) / k!

其中n!nx=0的阶乘。例如,e^x的3x3 Carleman矩阵为:

[
  [1, 0, 0],
  [1, 1, 0.5],
  [1, 1, 2]
]

由于使用了导数,因此在第二行上可以看到e^x的泰勒展开,在第三行上可以看到(e^x)^2e^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)/104*sqrt(5)/2,这可能是Denman迭代的结果。)

新的半迭代Carleman矩阵的泰勒展开式将显示在第二行,因此我们可以将e^x的半迭代近似为

f(x)=0.5+0.8944271883343149x+0.22360679791657895x^{2}

以下是f(f(x))(蓝色)与e^x(绿色)的图:

Comparison of functions

您可以看到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个项后爆炸(即将更新),因此不要尝试使用太多的项。