Hello,
I am using tabling to improve on the performance of my program. I am facing some problems, and would really appreciate some help.
My program calls a set of entangled reasoners; that call each other, and cause cycles. My approach was to use guards to not allow a goal to call itself through zero or more predicates. The following shows two reasoners that need to call each other, and the guards I have setup to stop cyclic calls.
:- thread_local pending/1.
reasoner_1(Goal):-
% make sure this goal is not being evaluated by reasoner_1/1 earlier in the search tree
\+ pending(reasoner_1(Goal)),
% if not, it is now, so mark it as "pending proof"
assert(pending(reasoner_1(Goal))),
(
% either prove using reasoner_2/1 and release the guard
(
reasoner_2(Goal),
retract(pending(reasoner_1(Goal)))
);
% or in case reasoner_2/1 failed, release the guard and fail
(
(pending(reasoner_1(Goal)) -> retract(pending(reasoner_1(Goal))); true),
fail
)
).
reasoner_2(Goal):-
% make sure this goal is not being evaluated by reasoner_2/1 earlier in the search tree
\+ pending(reasoner_2(Goal)),
% if not, it is now, so mark it as "pending proof"
assert(pending(reasoner_2(Goal))),
(
% either prove using reasoner_1/1 and release the guard
(
reasoner_1(Goal),
retract(pending(reasoner_2(Goal)))
);
% or in case reasoner_1/1 failed, release the guard and fail
(
(pending(reasoner_2(Goal)) -> retract(pending(reasoner_2(Goal))); true),
fail
)
).
The following are example executions.
?- reasoner_1(1).
false.
?- reasoner_1(G).
false.
Months later, I was introduced to the wonder world of tabling. So I added the following two lines to the beginning of the previous code:
:- table reasoner_1/1 as incremental.
:- dynamic([pending/1], [incremental(true)]).
Now, here are sample execution outputs.
?- reasoner_1(1). ERROR: '$idg_changed'/1: No permission to update variant `user:reasoner_1(1)' ERROR: No permission to update variant `user:reasoner_1(1)' ERROR: In: ERROR: [21] assert(pending(reasoner_1(1))) ERROR: [20] reasoner_1(1) at c:/workspace/prolog_development/testing_other_prolog_stuff/tabling/tabling_sequential.pl:9 ERROR: [19] call('$toplevel':<closure>(reasoner_1/1)(1)) at d:/programfiles/swipl/boot/init.pl:395 ERROR: [18] reset('$toplevel':call(...),_5934,_5936) at d:/programfiles/swipl/boot/init.pl:471 ERROR: [17] '$tabling':delim(ret,'$toplevel':call(...),11962876,[]) at d:/programfiles/swipl/boot/tabling.pl:468 ERROR: [16] '$tabling':activate(ret,'$toplevel':call(...),<trie>(0000016663A0E170),11962876) at d:/programfiles/swipl/boot/tabling.pl:454 ERROR: [15] '$tabling':run_leader(ret,'$toplevel':call(...),<trie>(0000016663A0E170),11815544,_6076,_6078) at d:/programfiles/swipl/boot/tabling.pl:439 ERROR: [14] setup_call_catcher_cleanup('$tabling':'$idg_set_current'(_6128,<trie>(0000016663A0E170)),'$tabling':run_leader(ret,...,<trie>(0000016663A0E170),11815544,_6148,_6150),_6116,'$tabling':finished_leader(_6160,_6162,11815544,...)) at d:/programfiles/swipl/boot/init.pl:539 ERROR: [13] '$tabling':create_table(<trie>(0000016663A0E170),ret,user:reasoner_1(1),'$toplevel':call(...)) at d:/programfiles/swipl/boot/tabling.pl:318 ERROR: [12] catch('$tabling':create_table(<trie>(0000016663A0E170),ret,...,...),deadlock,'$tabling':restart_tabling(<closure>(reasoner_1/1),...,...)) at d:/programfiles/swipl/boot/init.pl:457 ERROR: [11] '$tabling':start_tabling(<closure>(reasoner_1/1),user:reasoner_1(1),'$toplevel':call(...)) at d:/programfiles/swipl/boot/tabling.pl:303 ERROR: [10] '$wrap$reasoner_1'(1)1-st clause of '$wrap$reasoner_1'/1 <no source> ERROR: [9] <user> ?- reasoner_1(G). ERROR: '$idg_changed'/1: No permission to update variant `user:reasoner_1(_7164)' ERROR: No permission to update variant `user:reasoner_1(_8328)' ERROR: In: ERROR: [21] assert(pending(reasoner_1(_8380))) ERROR: [20] reasoner_1(_8404) at c:/workspace/prolog_development/testing_other_prolog_stuff/tabling/tabling_sequential.pl:9 ERROR: [19] call('$toplevel':<closure>(reasoner_1/1)(_8438)) at d:/programfiles/swipl/boot/init.pl:395 ERROR: [18] reset('$toplevel':call(...),_8464,_8466) at d:/programfiles/swipl/boot/init.pl:471 ERROR: [17] '$tabling':delim(ret(_8516),'$toplevel':call(...),11962552,[]) at d:/programfiles/swipl/boot/tabling.pl:468 ERROR: [16] '$tabling':activate(ret(_8566),'$toplevel':call(...),<trie>(0000016663A0D590),11962552) at d:/programfiles/swipl/boot/tabling.pl:454 ERROR: [15] '$tabling':run_leader(ret(_8620),'$toplevel':call(...),<trie>(0000016663A0D590),11816216,_8614,_8616) at d:/programfiles/swipl/boot/tabling.pl:439 ERROR: [14] setup_call_catcher_cleanup('$tabling':'$idg_set_current'(_8670,<trie>(0000016663A0D590)),'$tabling':run_leader(...,...,<trie>(0000016663A0D590),11816216,_8690,_8692),_8658,'$tabling':finished_leader(_8702,_8704,11816216,...)) at d:/programfiles/swipl/boot/init.pl:539 ERROR: [13] '$tabling':create_table(<trie>(0000016663A0D590),ret(_8748),user:reasoner_1(_8758),'$toplevel':call(...)) at d:/programfiles/swipl/boot/tabling.pl:318 ERROR: [12] catch('$tabling':create_table(<trie>(0000016663A0D590),...,...,...),deadlock,'$tabling':restart_tabling(<closure>(reasoner_1/1),...,...)) at d:/programfiles/swipl/boot/init.pl:457 ERROR: [9] <user> ERROR: ERROR: Note: some frames are missing due to last-call optimization. ERROR: Re-run your program in debug mode (:- debug.) to get more detail. ^ Exception: (12) catch('$tabling':create_table(<trie>(0000016663A0D590), ret(_6704), user:reasoner_1(_6704), '$toplevel':call(<closure>(reasoner_1/1)(_6704))), deadlock, '$tabling':restart_tabling(<closure>(reasoner_1/1), user:reasoner_1(_6704), '$toplevel':call(<closure>(reasoner_1/1)(_6704)))) ? creep
I have a very conservative programming approach. I try not to mess code too much when adding new stuff, so I thought it is best I leave my guards around while adding tabling; and when things look fine, I dispense with the guards leaving only tabling.
I couldn’t decipher much of the error message which from my limited knowledge looks like it has been written in the old language of Mordor, but I saw a familiar word: “deadlock”. Is mixing my guards with tabling causing this? in which case do I need to remove them before trying tabling?
Thanks.