在 prolog 中断言和使用快速的大型数组
Asserting and using fast, LARGE arrays in prolog
我在 SWI-Prolog 中使用仿函数通过 arg/3 获取随机访问数组。
我正在做的是将样本中的值加载到我创建的仿函数中,并声明该数组以供将来使用。
加载后,随机访问确实是 O(1),正如我使用 time/1 验证的那样。问题是从断言加载仿函数需要很多时间(time/1 表明它与数组的大小成线性关系)。
有什么办法可以将其加快到恒定时间吗?
最小复制代码:
:- dynamic
current_sample/1.
xrange(L,R,X):-
L < R,
( X = L;
X1 is L+1, xrange(X1,R,X)
).
arraybase_from_list__set_arg_from_list([], _, _).
arraybase_from_list__set_arg_from_list([Head|Tail], I, ResArray):-
I1 is I+1,
nb_setarg(I1, ResArray, Head),
arraybase_from_list__set_arg_from_list(Tail, I1, ResArray).
arraybase_from_list(List, ResArray):-
length(List, L),
functor(ResArray, custom_array_data, L),
arraybase_from_list__set_arg_from_list(List, 0, ResArray ).
test_array_create( N ):- % Creates a dummy array of squares of numbers fromo [0,N)
findall( X2, (xrange( 0,N,X), X2 is X*X), XList ),
arraybase_from_list( XList, Arr ),
assert( current_sample(Arr) ).
test_array_get(I,V):- % Unifies V with Ith element of Current sample
I0 is I+1,
current_sample(Arr), % Take turns timing this
arg( I0, Arr, V ). % And then timing this
您在使用 current_sample/1
时看到 线性 开销,因为谓词的参数是从数据库 copied 时谓词叫做。
有几种方法可以消除这种线性开销,将其变成𝒪(1).
好方法
一个好的方法是携带整个数组,显式或隐式地遍历所有需要访问它。
您可以使用 半上下文表示法 隐式地执行此操作(请参阅 dcg),或编写您自己的自定义扩展规则。这类似于 Haskell.
中的 monads
Consider doing this!
更糟糕的方式
一种更糟糕但表面上更简单的方法是使用 全局变量 而不是全局 数据库 来存储术语.
Avoid this!
一些原因:
- 它不可移植
- 它引入了全局状态,使您的谓词难以阅读和调试
- 它不是比简单地使用额外的参数来携带数组(隐式或显式)更有效
- 容易出错
- 等等
我在 SWI-Prolog 中使用仿函数通过 arg/3 获取随机访问数组。 我正在做的是将样本中的值加载到我创建的仿函数中,并声明该数组以供将来使用。
加载后,随机访问确实是 O(1),正如我使用 time/1 验证的那样。问题是从断言加载仿函数需要很多时间(time/1 表明它与数组的大小成线性关系)。 有什么办法可以将其加快到恒定时间吗?
最小复制代码:
:- dynamic
current_sample/1.
xrange(L,R,X):-
L < R,
( X = L;
X1 is L+1, xrange(X1,R,X)
).
arraybase_from_list__set_arg_from_list([], _, _).
arraybase_from_list__set_arg_from_list([Head|Tail], I, ResArray):-
I1 is I+1,
nb_setarg(I1, ResArray, Head),
arraybase_from_list__set_arg_from_list(Tail, I1, ResArray).
arraybase_from_list(List, ResArray):-
length(List, L),
functor(ResArray, custom_array_data, L),
arraybase_from_list__set_arg_from_list(List, 0, ResArray ).
test_array_create( N ):- % Creates a dummy array of squares of numbers fromo [0,N)
findall( X2, (xrange( 0,N,X), X2 is X*X), XList ),
arraybase_from_list( XList, Arr ),
assert( current_sample(Arr) ).
test_array_get(I,V):- % Unifies V with Ith element of Current sample
I0 is I+1,
current_sample(Arr), % Take turns timing this
arg( I0, Arr, V ). % And then timing this
您在使用 current_sample/1
时看到 线性 开销,因为谓词的参数是从数据库 copied 时谓词叫做。
有几种方法可以消除这种线性开销,将其变成𝒪(1).
好方法
一个好的方法是携带整个数组,显式或隐式地遍历所有需要访问它。
您可以使用 半上下文表示法 隐式地执行此操作(请参阅 dcg),或编写您自己的自定义扩展规则。这类似于 Haskell.
中的 monadsConsider doing this!
更糟糕的方式
一种更糟糕但表面上更简单的方法是使用 全局变量 而不是全局 数据库 来存储术语.
Avoid this!
一些原因:
- 它不可移植
- 它引入了全局状态,使您的谓词难以阅读和调试
- 它不是比简单地使用额外的参数来携带数组(隐式或显式)更有效
- 容易出错
- 等等