Optimization Prolog,优化生成

Optimization Prolog,优化生成,optimization,prolog,Optimization,Prolog,我编写了一个prolog程序,它生成二维表格中元素的所有可能位置。给出了元素的数量和表的大小 我的代码: geni(Min, Min, Max) :- Min =< Max. geni(Min, X, Max) :- Max >= Min, MinInc is Min+1, geni(MinInc, X, Max). generate(_, 0, []) :- !. generate(TSize, N, [X|Tail]) :- X=k(X1,Y1), geni(1,X1,TSize

我编写了一个prolog程序,它生成二维表格中元素的所有可能位置。给出了元素的数量和表的大小

我的代码:

geni(Min, Min, Max) :- Min =< Max.
geni(Min, X, Max) :- Max >= Min, MinInc is Min+1, geni(MinInc, X, Max).
generate(_, 0, []) :- !.
generate(TSize, N, [X|Tail]) :- X=k(X1,Y1), geni(1,X1,TSize), 
                                geni(1,Y1,TSize), NDec is N-1, 
                                generate(TSize,NDec, Tail), not(member(X, Tail)).

它工作正常,但当我使用更高的数字时速度太慢。我认为谓词“geni”是好的,但“generate”有问题。如何优化它?

这不是一个完整的答案,但是如果您使用的是SWI Prolog,那么您可以使用
而不是
geni/3
,这可能更快。

这不是一个完整的答案,但是如果您使用的是SWI Prolog,然后,您可以使用可能更快的
between/3
,而不是
geni/3

尽管有任何算法优化,您应该始终使用尾部递归:递归调用必须是谓词中的最后一个,通过这种方式,prolog解释器可以更快地执行循环,而不是真正的递归,因为它可以删除以前函数调用的堆栈帧,知道调用后不会有任何代码,因此不再需要内部变量

尾部递归通常是通过引入一个附加函数(此处为谓词)参数来实现的,该参数用作累加器,在该累加器中,递归运行时累积最终结果,然后在最终递归步骤中,累加器保存完整结果。然后通过递归步骤将其简单地传递回

generate_new(TSize, N, Result) :- generate_new(TSize, N, [], Result).

generate_new(_, 0, Result, Result) :- !.

generate_new(TSize, N, Temp, Result) :-
                    geni(1, X1, TSize),
                    geni(1, Y1, TSize),
                    X = k(X1, Y1),
                    NDec is N - 1,
                    \+ member(X, Temp),
                    generate_new(TSize, NDec, [X|Temp], Result).

尽管有任何算法优化,但您应该始终使用尾部递归:递归调用必须是谓词中的最后一个,这样prolog解释器可以执行更快的循环而不是真正的递归,因为它可以删除以前函数调用的堆栈帧,知道调用后不会有任何代码,因此不再需要内部变量

尾部递归通常是通过引入一个附加函数(此处为谓词)参数来实现的,该参数用作累加器,在该累加器中,递归运行时累积最终结果,然后在最终递归步骤中,累加器保存完整结果。然后通过递归步骤将其简单地传递回

generate_new(TSize, N, Result) :- generate_new(TSize, N, [], Result).

generate_new(_, 0, Result, Result) :- !.

generate_new(TSize, N, Temp, Result) :-
                    geni(1, X1, TSize),
                    geni(1, Y1, TSize),
                    X = k(X1, Y1),
                    NDec is N - 1,
                    \+ member(X, Temp),
                    generate_new(TSize, NDec, [X|Temp], Result).

让我们仔细看看alogrithm是如何工作的。它有三个部分:

1) 生成X

X=k(X1,Y1), geni(1,X1,TSize), 
geni(1,Y1,TSize), 
2) 生尾巴

NDec is N-1, 
generate(TSize,NDec, Tail), 
3) 检查所有匹配项

not(member(X, Tail)).
在每个递归级别上,它的执行方式如下:

1) 生成一个X,2)生成一个尾部,3)检查失败,2)生成另一个尾部,3)检查再次失败

因此,基本上在每个级别上,你的alogrithm都会生成大量的尾部,以找到与当前X匹配的尾部。对于这些尾部中的每一个,在下一个递归级别上必须生成更多的尾部。

因此,只需先生成尾部,然后找到匹配的X

generate(TSize, N, [X|Tail]) :-
    NDec is N-1, generate(TSize,NDec, Tail),
    X=k(X1,Y1), geni(1,X1,TSize), geni(1,Y1,TSize), 
    not(member(X, Tail)).

长话短说:由于回溯方法,首先要做昂贵的事情(如递归)。

让我们仔细看看alogrithm是如何工作的。它有三个部分:

1) 生成X

X=k(X1,Y1), geni(1,X1,TSize), 
geni(1,Y1,TSize), 
2) 生尾巴

NDec is N-1, 
generate(TSize,NDec, Tail), 
3) 检查所有匹配项

not(member(X, Tail)).
在每个递归级别上,它的执行方式如下:

1) 生成一个X,2)生成一个尾部,3)检查失败,2)生成另一个尾部,3)检查再次失败

因此,基本上在每个级别上,你的alogrithm都会生成大量的尾部,以找到与当前X匹配的尾部。对于这些尾部中的每一个,在下一个递归级别上必须生成更多的尾部。

因此,只需先生成尾部,然后找到匹配的X

generate(TSize, N, [X|Tail]) :-
    NDec is N-1, generate(TSize,NDec, Tail),
    X=k(X1,Y1), geni(1,X1,TSize), geni(1,Y1,TSize), 
    not(member(X, Tail)).


长话短说:由于回溯方法,首先要做昂贵的事情(如递归)。

在nxn数组中排列k个元素的可能方法有(n^2)/(n^2-k)!这导致即使对于相对较小的n和k值,也会产生非常大的数值。所以,如果你真的在迭代所有的可能性,你的程序肯定会很慢。在这种情况下,我想解决国际象棋桌和骑士的问题。所有元素都是相等的。它会改变什么吗?你的编辑值得一个新问题,这个问题已经解决了。(我将在那里发布我的答案:)我在编辑中提出了一个新问题。在nxn数组中排列k个元素的可能方法是(n^2)/(n^2-k)!这导致即使对于相对较小的n和k值,也会产生非常大的数值。所以,如果你真的在迭代所有的可能性,你的程序肯定会很慢。在这种情况下,我想解决国际象棋桌和骑士的问题。所有元素都是相等的。它会改变什么吗?你的编辑值得一个新问题,这个问题已经解决了。(我将在那里发布我的答案:)我在编辑中提出了关于这个问题的新问题是的,我使用的是SWI Prolog,但我认为“geni”比“between”稍微慢一点。所以主要的问题是“generate”。是的,我使用的是SWI-Prolog,但我认为“geni”比“between”稍微慢一点。所以主要的问题是“generate”。我是Prolog新手,所以我不知道Prolog解释器到底是如何工作的。我认为问题在于表中的所有元素都是相等的(棋盘中的骑士),而我的程序“认为”元素是不同的。好吧,我的算法得到的结果和你们的完全相同,只是顺序不同而已。看看你自己的结果,它们真的正确吗?例如,如果结果中有‘[k(1,2),k(2,2)]’,那么‘[k(2,2),k(1,2)]’也必须存在吗?在我的程序的其他谓词中没有问题,但不需要两个类似的列表。所以应该有一个,是的。你的算法速度快得难以置信。谢谢但如何避免类似的结果呢?我对Prolog是新手,所以我不知道Prolog解释器到底是如何工作的。我认为问题在于表中的所有元素都是相等的(棋盘中的骑士),而我的程序“认为”元素是不同的。好吧,我的算法得到的结果和你们的完全相同,只是顺序不同而已。看看你的o