Как перемешать динамические факты в Прологе? - PullRequest
0 голосов
/ 02 декабря 2018

У меня есть несколько динамических фактов в Прологе, и я хочу их перемешать (переупорядочить в случайном порядке).Есть ли способ в Прологе, как это сделать?

:- dynamic max/3.
max(1,2,3).
max(1,5,6).
max(3,4,5).
max(2,2,5).

Возможен случайный порядок:

max(2,2,5).
max(1,2,3).
max(3,4,5).
max(1,5,6).

1 Ответ

0 голосов
/ 02 декабря 2018

Поскольку вы упоминаете, что используете SWI-Prolog, возможное решение - использовать его встроенные предикаты nth_clause/3 и clause/3.Идея состоит в том, чтобы получить доступ к предикату, используя прокси-предикат, в данном случае ramdom_max/3.Я также предполагаю, что у вас есть только факты.

:- use_module(library(lists)).
:- use_module(library(random)).

ramdom_max(A, B, C) :-
    predicate_property(max(_,_,_), number_of_clauses(N)),
    numlist(1, N, List),
    random_permutation(List, Permutation),   
    member(Index, Permutation),
    nth_clause(max(_,_,_), Index, Ref),
    clause(max(A,B,C), _, Ref).

Пример вызова:

?- ramdom_max(A, B, C).
A = 1,
B = 2,
C = 3 ;
A = 3,
B = 4,
C = 5 ;
A = 1,
B = 5,
C = 6 ;
A = B, B = 2,
C = 5.

Каждый вызов предиката ramdom_max/3 даст вам другой случайный порядок предложений, но все жеперечисляя все пункты об отслеживании.

Это, однако, является относительно дорогостоящим решением.Но поскольку max/3 является динамическим предикатом, первые цели в теле предложения ramdom_max /3 не могут быть оптимизированы для выполнения только один раз.Давайте проверим количество выводов:

% autoload the time/1 library predicate:
?- time(true).
% 3 inferences, 0.000 CPU in 0.000 seconds (60% CPU, 333333 Lips)
true.

?- time(ramdom_max(A, B, C)).
% 42 inferences, 0.000 CPU in 0.000 seconds (85% CPU, 913043 Lips)
A = 3,
B = 4,
C = 5 ;
% 6 inferences, 0.000 CPU in 0.000 seconds (69% CPU, 272727 Lips)
A = 1,
B = 2,
C = 3 ;
% 4 inferences, 0.000 CPU in 0.000 seconds (69% CPU, 222222 Lips)
A = 1,
B = 5,
C = 6 ;
% 6 inferences, 0.000 CPU in 0.000 seconds (70% CPU, 250000 Lips)
A = B, B = 2,
C = 5.

Стоит сравнить с предложением Лукера в пересмотре комментариев с использованием findall/3.Возможная реализация:

ramdom_max(A, B, C) :-
    findall(max(A,B,C), max(A,B,C), Clauses),
    random_permutation(Clauses, Permutation),   
    member(max(A,B,C), Permutation).

Синхронизированный вызов:

?- time(ramdom_max(A, B, C)).
% 40 inferences, 0.000 CPU in 0.000 seconds (78% CPU, 930233 Lips)
A = 1,
B = 5,
C = 6 ;
% 2 inferences, 0.000 CPU in 0.000 seconds (50% CPU, 200000 Lips)
A = 1,
B = 2,
C = 3 ;
% 2 inferences, 0.000 CPU in 0.000 seconds (45% CPU, 250000 Lips)
A = B, B = 2,
C = 5 ;
% 4 inferences, 0.000 CPU in 0.000 seconds (62% CPU, 250000 Lips)
A = 3,
B = 4,
C = 5.

Производительность примерно такая же в этом очень ограниченном тестировании.Но это также более простое и более портативное решение.Однако, зная немного больше о проблеме, которую вы хотите решить, возможно, вы найдете более эффективные решения.

...