Te sugerimos que revises esta respuesta en un ambiente controlado antes de enviarlo a producción, un saludo.
Use una variable existencialmente cuantificada, como lo haría con setof
:
?- aggregate(count, X^permutation([1,2,3,4], X), N).
N = 24.
En SWI-Prolog existe una versión mucho más eficiente, que además evita bloquear el almacén global. Entonces, simplemente usando nb_setval y nb_getval, obtiene al menos 3 veces el rendimiento (más en subprocesos múltiples). Hace poco tiempo otra pregunta fue sobre el conteo de soluciones. Al ser la base de la agregación, es un punto de parada obvio mientras se aprende Prolog. Para evaluar la ganancia de eficiencia que obtenemos usando estas llamadas monohilo semánticamente equivalentes:
count_solutions(Goal, N) :-
assert(count_solutions_store(0)),
repeat,
( call(Goal),
retract(count_solutions_store(SoFar)),
Updated is SoFar + 1,
assert(count_solutions_store(Updated)),
fail
; retract(count_solutions_store(N))
), !.
:- dynamic count_solutions_store/1.
% no declaration required here
count_solutions_nb(Goal, N) :-
nb_setval(count_solutions_store, 0),
repeat,
( call(Goal),
nb_getval(count_solutions_store, SoFar),
Updated is SoFar + 1,
nb_setval(count_solutions_store, Updated),
fail
; nb_getval(count_solutions_store, N)
), !.
parent(jane,dick).
parent(michael,dick).
parent(michael,asd).
numberofchildren(Parent, N) :-
count_solutions_nb(parent(Parent, _), N).
many_solutions :-
between(1, 500000, _).
time_iso :-
time(count_solutions(many_solutions, N)),
write(N), nl.
time_swi :-
time(count_solutions_nb(many_solutions, N)),
writeln(N).
En mi sistema, obtengo
?- [count_sol].
% count_sol compiled 0,00 sec, 244 bytes
true.
?- time_iso.
tim% 1,000,006 inferences, 2,805 CPU in 2,805 seconds (100% CPU, 356510 Lips)
500000
true.
?- time_swi.
% 2,000,010 inferences, 0,768 CPU in 0,768 seconds (100% CPU, 2603693 Lips)
500000
true.
También hay aggregate_all/3
:
?- aggregate_all(count, permutation([1, 2, 3, 4], _), Total).
Total = 24.
Sin embargo, en lo que respecta al tiempo de ejecución y los desbordamientos de pila, parece funcionar igual de bien para su findall
+length
solución:
?- N is 10^7, time(aggregate_all(count, between(1, N, _), Total)).
% 10,000,022 inferences, 5.075 CPU in 5.089 seconds (100% CPU, 1970306 Lips)
N = Total, Total = 10000000.
?- N is 10^7, time((findall(X, between(1, N, _), L), length(L, Total))).
% 10,000,013 inferences, 4.489 CPU in 4.501 seconds (100% CPU, 2227879 Lips)
N = 10000000,
L = [_G30000569, _G30000566, _G30000545|...],
Total = 10000000.
?- N is 10^8, aggregate_all(count, between(1, N, _), Total).
ERROR: Out of global stack
?- N is 10^8, findall(X, between(1, N, _), L), length(L, Total).
ERROR: Out of global stack
Puedes contar las soluciones usando assert
/retract
esto es bastante lento pero evita el problema de “fuera de pila”:
?- assert(counter(0)), N is 10^8, between(1, N, _),
retract(counter(C)), C1 is C + 1, assert(counter(C1)), fail
; retract(counter(C)).
C = 100000000.
Valoraciones y comentarios
Recuerda que tienes la capacidad de explicar tu experiencia .