Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/google-sheets/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
Performance 如何在不触发本地堆栈外异常的情况下计算两个大字符串的每个字符上的一致性?_Performance_Optimization_Prolog_Stack Overflow - Fatal编程技术网

Performance 如何在不触发本地堆栈外异常的情况下计算两个大字符串的每个字符上的一致性?

Performance 如何在不触发本地堆栈外异常的情况下计算两个大字符串的每个字符上的一致性?,performance,optimization,prolog,stack-overflow,Performance,Optimization,Prolog,Stack Overflow,我需要一个子句来计算两个大字符串之间的字符一致性,但忽略'一致性。我有以下代码: fit(GEN1, GEN2, N, N) :- length(GEN1, L1), length(GEN2, L2), 0 is L1*L2. fit([P1|R1], [P2|R2], N, TOTAL) :- member(P1, ['_',a,c,t,g]), member(P2, ['_',a,c,t,g]), append([P1],[P2],T), ( m

我需要一个子句来计算两个大字符串之间的字符一致性,但忽略
'
一致性。我有以下代码:

fit(GEN1, GEN2, N, N) :-
   length(GEN1, L1),
   length(GEN2, L2),
   0 is L1*L2.

fit([P1|R1], [P2|R2], N, TOTAL) :-
   member(P1, ['_',a,c,t,g]),
   member(P2, ['_',a,c,t,g]),
   append([P1],[P2],T),
   (  member(T,[[a,a],[c,c],[t,t],[g,g]])
   -> X is N+1
   ;  X is N
   ),
   fit(R1,R2,X,TOTAL).
其中
GEN1
GEN2
是包含所有字符和大字符串的列表

我已尝试增加堆栈限制,以避免出现
超出本地堆栈的
异常,但收效甚微

问题是,经常在深层递归子句中调用。有没有更好的办法

编辑

当一个或两个列表为空时,该子句需要停止

编辑2

值得一提的是,下面所有答案的测试都是使用64位prolog完成的,带有
--stack limit=32g
选项,因为我的代码没有得到很好的优化,
fit
子句是更大过程的一小部分,但却是我代码的主要问题

编辑3

代码使用更少的资源工作

使用
库(reif)
v2的错误代码运行得更快


有关更多建议的解决方案,请参阅。

似乎没有必要坚持要求您一直使用
“\u actg”
中的字母。一个广义的定义似乎就足够了。使用
库(reif)

fit([],u,N,N)。
适合([[u124;,],],N,N)。
拟合([P1 | R1],[P2 | R2],N,总计):-
如果X是N+1,X=N,
配合(R1、R2、X、总计)。
更新:请确保使用
库(reif)
的v2。原始版本没有编译dif/3

这是一个系统版本,它只能同时对一个参数进行索引:

fit([],u,N,N)。
拟合([P1 | R1],L2,N,总计):-
ifit(L2,[P1 | R1],N,总计)。
ifit([],u,N,N)。
ifit([P2 | R2],[P1 | R1],N,总计):-
如果X是N+1,X=N,
配合(R1、R2、X、总计)。
如果Prolog有library(),您可以执行以下操作

fit(第1代、第2代、第N代):-
集合_all(count,(nth1(P,GEN1,S),nth1(P,GEN2,S),memberchk(S,[a,c,g,t])),N)。
编辑

根据数据统计,只需交换最后两个调用即可获得显著的改进,即
…(nth1(p,GEN1,S)、memberchk(S[a,c,g,t])、nth1(p,GEN2,S))…

编辑

当然是一个紧密的循环,最好是双索引扫描。对于性能,我会这样写

fit_cc(第1代、第2代、第N代):-
拟合(第1代、第2代、第0代、第N代)。
拟合曲线([X | GEN1],[Y | GEN2],C,N):-
(X\=''''/*成员chk(X[a,c,g,t])*/,X=Y
->D是C+1;D=C
),
安装(第1代、第2代、第D代、第N代)。
配合,配合(配合,配合,配合)。

但是库(reif)v2所允许的通用性和正确性,如@false”答案和注释所示,似乎非常值得(相当小的)开销。

如果您总是使用两个已完全实例化的第一个参数调用谓词,那么您可以将其用作函数,不是作为一种关系——看起来你确实是这样——我怀疑只是添加了
在最后一行代码的开头应该足以消除堆栈溢出

为了做得更好,我们使用
memberchk
而不是
member
,注意
append([a],[B],C)
C=[a,B]
完全相同;因此,经过一点改组,我们最终得到了类似的结果

fit( [], [], N, N).

fit( [P1|R1], [P2|R2], N, TOTAL) :-
   memberchk( P1, [a,c,t,g]),
   (  P2 == P1
   -> X is N+1
   ;  X is N
   ),
   %%  !,    %% might need the cut
   fit( R1, R2, X, TOTAL).
我们甚至可能不需要削减,因为
memberchk
已经是确定性的了


(虽然未测试)

添加一个示例查询以生成实际上应该非常快的溢出。但是我们不能只
fit([P | R1],[P | R2],N,Total):-P\=''u'!,X是N+1,适合(R1,R2,X,总计)。fit([| |]],[uu,[uu],N,N)。
?@David:一开始你可能想测试是否有根据,但之后你永远无法使用任何形式的声明性诊断。我允许自己在“false”的答案中添加一些“plunit”测试用例以进行说明。@DavidTonhofer:注意“发布你的答案”按钮。对于间距:在所有子句之间使用空行,因此无法判断下一个子句是否属于同一谓词。@DavidTonhofer:我不喜欢当前的plunit是有原因的,这“看起来像一条规则,但不是一条”。听起来像是O(长度(列表)²)算法虽然使用Capelical的代码运行了几次,但运行效果非常好,使用的资源要少得多,而占用的时间却与错误代码差不多。@RezzDeWitt我想用C压缩列表相当快。而且它只是O(长度(第一个列表))真的。我的错误。请注意
fit([a],[B],1),B=t。
成功,但
B=t,fit([a],[B],1)。
失败。@false我没有使用正确的调用,我只是删除了注释。