Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/solr/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 在Mathematica中,找到(重复)列表周期的最佳方法是什么?_Algorithm_Wolfram Mathematica - Fatal编程技术网

Algorithm 在Mathematica中,找到(重复)列表周期的最佳方法是什么?

Algorithm 在Mathematica中,找到(重复)列表周期的最佳方法是什么?,algorithm,wolfram-mathematica,Algorithm,Wolfram Mathematica,在重复列表中查找句点的最佳方法是什么 例如: a = {4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2} 具有重复的{4,5,1,2,3},剩余的{4,5,1,2}匹配,但不完整 算法应足够快,以处理较长的情况,如: b = RandomInteger[10000, {100}]; a = Join[b, b, b, b, Take[b, 27]] { 1,2,1,1, 1,2,1,1, 1,2,1,1, ...} 如果没有像上面那样的重复模式,算法应该

在重复列表中查找句点的最佳方法是什么

例如:

a = {4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2}
具有重复的
{4,5,1,2,3}
,剩余的
{4,5,1,2}
匹配,但不完整

算法应足够快,以处理较长的情况,如:

b = RandomInteger[10000, {100}];
a = Join[b, b, b, b, Take[b, 27]]
{ 1,2,1,1, 1,2,1,1, 1,2,1,1, ...} 

如果没有像上面那样的重复模式,算法应该返回
$Failed

这听起来可能与。这些算法都经过了很好的研究,可能已经在mathematica中实现了。

我不知道如何在mathematica中解决它,但是下面的算法(用python编写)应该可以工作。现在是O(n),所以速度应该不重要

def period(array):
    if len(array) == 0:
        return False
    else:
        s = array[0]
        match = False
        end = 0
        i = 0

        for k in range(1,len(array)):
            c = array[k]

            if not match:
                if c == s:
                    i = 1
                    match = True
                    end = k
            else:
                if not c == array[i]:
                    match = False
                i += 1

        if match:
            return array[:end]
        else:
            return False

# False         
print(period([4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2,1]))
# [4, 5, 1, 2, 3]            
print(period([4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2]))
# False
print(period([4]))
# [4, 2]
print(period([4,2,4]))
# False
print(period([4,2,1]))
# False
print(period([]))

以下假设周期从第一个元素开始,并给出周期长度和周期

findCyclingList[a_?VectorQ] :=
  Module[{repeats1, repeats2, cl, cLs, vec}, 
  repeats1 = Flatten@Differences[Position[a, First[a]]];
  repeats2 = Flatten[Position[repeats1, First[repeats1]]]; 
  If[Equal @@ Differences[repeats2] && Length[repeats2] > 2(* 
   is potentially cyclic - first element appears cyclically *),
   cl = Plus @@@ Partition[repeats1, First[Differences[repeats2]]];
   cLs = Partition[a, First[cl]];
   If[SameQ @@ cLs  (* candidate cycles all actually the same *), 
    vec = First[cLs];
    {Length[vec], vec}, $Failed], $Failed]  ]
测试

b = RandomInteger[50, {100}];
a = Join[b, b, b, b, Take[b, 27]];

findCyclingList[a]

{100, {47, 15, 42, 10, 14, 29, 12, 29, 11, 37, 6, 19, 14, 50, 4, 38, 
  23, 3, 41, 39, 41, 17, 32, 8, 18, 37, 5, 45, 38, 8, 39, 9, 26, 33, 
  40, 50, 0, 45, 1, 48, 32, 37, 15, 37, 49, 16, 27, 36, 11, 16, 4, 28,
   31, 46, 30, 24, 30, 3, 32, 31, 31, 0, 32, 35, 47, 44, 7, 21, 1, 22,
   43, 13, 44, 35, 29, 38, 31, 31, 17, 37, 49, 22, 15, 28, 21, 8, 31, 
  42, 26, 33, 1, 47, 26, 1, 37, 22, 40, 27, 27, 16}}

b1 = RandomInteger[10000, {100}]; 
a1 = Join[b1, b1, b1, b1, Take[b1, 23]];

findCyclingList[a1]

{100, {1281, 5325, 8435, 7505, 1355, 857, 2597, 8807, 1095, 4203, 
  3718, 3501, 7054, 4620, 6359, 1624, 6115, 8567, 4030, 5029, 6515, 
  5921, 4875, 2677, 6776, 2468, 7983, 4750, 7609, 9471, 1328, 7830, 
  2241, 4859, 9289, 6294, 7259, 4693, 7188, 2038, 3994, 1907, 2389, 
  6622, 4758, 3171, 1746, 2254, 556, 3010, 1814, 4782, 3849, 6695, 
  4316, 1548, 3824, 5094, 8161, 8423, 8765, 1134, 7442, 8218, 5429, 
  7255, 4131, 9474, 6016, 2438, 403, 6783, 4217, 7452, 2418, 9744, 
  6405, 8757, 9666, 4035, 7833, 2657, 7432, 3066, 9081, 9523, 3284, 
  3661, 1947, 3619, 2550, 4950, 1537, 2772, 5432, 6517, 6142, 9774, 
  1289, 6352}}
这个案例应该失败,因为它不是周期性的

findCyclingList[Join[b, Take[b, 11], b]]

$Failed

我试着用
重复
,例如
a/。重复[t_uuuu,{2100}]->{t}
但它对我不起作用。

这对你有用吗

period[a_] := 
   Quiet[Check[
      First[Cases[
         Table[
            {k, Equal @@ Partition[a, k]}, 
            {k, Floor[Length[a]/2]}], 
         {k_, True} :> k
         ]], 
      $Failed]]
严格地说,这将在以下情况下失败

a = {1, 2, 3, 1, 2, 3, 1, 2, 3, 4, 5}
尽管这可以通过使用以下方法进行修复:

(Equal @@ Partition[a, k]) && (Equal @@ Partition[Reverse[a], k])

(可能只提前一次计算
反向[a]

我建议这样做。它借用了Verbeia和Brett的答案

Do[
  If[MatchQ @@ Equal @@ Partition[#, i, i, 1, _], Return @@ i],
  {i, #[[ 2 ;; Floor[Length@#/2] ]] ~Position~ First@#}
] /. Null -> $Failed &

它在长周期上的效率不如Vebeia的函数,但在短周期上的效率更快,而且更简单。

请参阅有关其工作原理的代码注释

(* True if a has period p *)
testPeriod[p_, a_] := Drop[a, p] === Drop[a, -p]

(* are all the list elements the same? *)
homogeneousQ[list_List] := Length@Tally[list] === 1
homogeneousQ[{}] := Throw[$Failed] (* yes, it's ugly to put this here ... *)

(* auxiliary for findPeriodOfFirstElement[] *)
reduce[a_] := Differences@Flatten@Position[a, First[a], {1}]

(* the first element occurs every ?th position ? *)
findPeriodOfFirstElement[a_] := Module[{nl},
  nl = NestWhileList[reduce, reduce[a], ! homogeneousQ[#] &];
  Fold[Total@Take[#2, #1] &, 1, Reverse[nl]]
  ]

(* the period must be a multiple of the period of the first element *)
period[a_] := Catch@With[{fp = findPeriodOfFirstElement[a]},
   Do[
    If[testPeriod[p, a], Return[p]],
    {p, fp, Quotient[Length[a], 2], fp}
    ]
   ]

请询问
findPeriodOfFirstElement[]
是否不清楚。我独立地做了这件事(为了好玩!),但现在我看到原理与Verbeia的解决方案相同,只是Brett指出的问题已经解决了

我在和你一起测试

b = RandomInteger[100, {1000}];
a = Flatten[{ConstantArray[b, 1000], Take[b, 27]}];
(请注意较低的整数值:在同一时间段内将有许多重复元素*)


编辑:根据下面的评论,通过使用专门为整数列表编译的自定义位置函数,还可以实现2-3倍的加速(在我的机器上约为2.4倍):

(* Leonid's reduce[] *)

myPosition = Compile[
  {{lst, _Integer, 1}, {val, _Integer}}, 
  Module[{pos = Table[0, {Length[lst]}], i = 1, ctr = 0}, 
    For[i = 1, i <= Length[lst], i++, 
      If[lst[[i]] == val, pos[[++ctr]] = i]
    ]; 
    Take[pos, ctr]
  ], 
  CompilationTarget -> "C", RuntimeOptions -> "Speed"
]

reduce[a_] := Differences@myPosition[a, First[a]]

好的,在这里展示我自己的作品:

ModifiedTortoiseHare[a_List] := Module[{counter, tortoise, hare},
Quiet[
 Check[
  counter = 1;
  tortoise = a[[counter]];
  hare = a[[2 counter]];
  While[(tortoise != hare) || (a[[counter ;; 2 counter - 1]] != a[[2 counter ;; 3 counter - 1]]),
   counter++;
   tortoise = a[[counter]];
   hare = a[[2 counter]];
  ];
 counter,
$Failed]]]
我不确定这是不是100%正确,尤其是像{pattern,pattern,different,pattern,pattern}这样的情况,当有很多重复元素时,它会变得越来越慢,比如:

b = RandomInteger[10000, {100}];
a = Join[b, b, b, b, Take[b, 27]]
{ 1,2,1,1, 1,2,1,1, 1,2,1,1, ...} 

因为它进行了太多昂贵的比较。

如果没有噪音,上述方法会更好。如果您的信号只是近似值,那么傅里叶变换方法可能会很有用。我将用“参数化”设置进行说明,其中基本信号的长度和重复次数、尾随部分的长度以及噪声扰动的界限都是可以使用的变量

noise = 20;
extra = 40;
baselen = 103;
base = RandomInteger[10000, {baselen}];
repeat = 5;
signal = Flatten[Join[ConstantArray[base, repeat], Take[base, extra]]];
noisysignal = signal + RandomInteger[{-noise, noise}, Length[signal]];
我们计算FFT的绝对值。我们把零连在两端。通过与相邻对象进行比较,对象将达到阈值

sigfft = Join[{0.}, Abs[Fourier[noisysignal]], {0}];
现在我们创建两个0-1向量。在一种情况下,我们通过为fft中的每个元素设置一个大于其两个相邻元素几何平均值两倍的1来设置阈值。在另一种情况下,我们使用平均值(算术平均值),但我们将大小限制降低到3/4。这是基于一些实验。我们计算每种情况下的1数。理想情况下,我们会得到每一个100,因为这将是一个“完美”的情况下,没有噪音和尾巴部分的非零的数量

In[419]:= 
thresh1 = 
  Table[If[sigfft[[j]]^2 > 2*sigfft[[j - 1]]*sigfft[[j + 1]], 1, 
    0], {j, 2, Length[sigfft] - 1}];
count1 = Count[thresh1, 1]
thresh2 = 
  Table[If[sigfft[[j]] > 3/4*(sigfft[[j - 1]] + sigfft[[j + 1]]), 1, 
    0], {j, 2, Length[sigfft] - 1}];
count2 = Count[thresh2, 1]

Out[420]= 114

Out[422]= 100
现在,我们通过计算总长度与计数平均值之差,得到“重复次数”值的最佳猜测

approxrepeats = Floor[2*Length[signal]/(count1 + count2)]
Out[423]= 5
我们发现基本信号重复了5次。这可以为精确估计正确的长度(baselen,上图)提供一个开始。为此,我们可以尝试在最后删除元素,看看什么时候FFT更接近于在非零值之间运行4个0

另一种可能用于估计重复次数的方法是在阈值FFT的游程长度编码中查找零的模式数。虽然我还没有真正尝试过,但在如何进行阈值化的细节方面,它看起来可能对错误的选择很有效(我的只是一些似乎有效的实验)

Daniel Lichtblau

#包括
#include <iostream>
#include <vector>
using namespace std;


int period(vector<int> v)
{
    int p=0; // period 0

    for(int i=p+1; i<v.size(); i++)
    {

        if(v[i] == v[0])
        {
            p=i; // new potential period


            bool periodical=true;
            for(int i=0; i<v.size()-p; i++)
            {
                if(v[i]!=v[i+p])
                {
                    periodical=false;
                    break;
                }
            }
            if(periodical) return p;


            i=p; // try to find new period
        }
    }

    return 0; // no period

}


int main()
{

    vector<int> v3{1,2,3,1,2,3,1,2,3};
    cout<<"Period is :\t"<<period(v3)<<endl;


    vector<int> v0{1,2,3,1,2,3,1,9,6};
    cout<<"Period is :\t"<<period(v0)<<endl;

    vector<int> v1{1,2,1,1,7,1,2,1,1,7,1,2,1,1};
    cout<<"Period is :\t"<<period(v1)<<endl;
    return 0;
}
#包括 使用名称空间std; 整数周期(向量v) { int p=0;//句点0
对于(int i=p+1;当第一个元素在一个周期内多次出现时,第一个
If
语句中的检查会导致返回
$Failed
,如:
{1,2,3,1,2,1,2,2,3,3,1,2,1,2}
。我想你的检查应该是差异列表本身是周期性的。哦,好的一点-我不确定现在如何解决这个问题。这个修订版应该是better@Verbeia
a/{Repeated[k_uuu,{2,无穷大}],Shortest[f_uuu]}->{k}
可以工作,但太慢了。第一种方法是使用
FindSequenceFunction[a]
,但我无法找到一个好的方法来通过编程确定从那以后的时间。感谢到目前为止的回复。看起来@Szabolcs解决方案是最好的解决方案。我仍在开发自己的独立解决方案,但速度仍然是原来的两倍。维基百科上有一篇文章,我相信它是相关的。相关:+1代表creative period testing功能、简单性和(潜在)速度。如果实际进行周期测试,则是您的瓶颈。使用更快的解决方案(如我使用的丑陋的解决方案),这也是最快的解决方案。我显然过度复杂了:-)@Szabolcs,高效的东西不可能是丑陋的。(别管其他的,我现在看到了。)经过一些思考,我认为在实际使用中最好定义
homogeneousQ[{x眗}]=True
等。@Mr.Wizard这是一回事,另一件事是哪个算法更快取决于数据中的模式(唯一元素的数量、它们的分布等).对于上面的测试数据,使用此
testPeriod
函数,我的版本比您的快约2倍,但对于