SPOILER ALERT: for those solving Advent of Code the following will contain a (likely non-idiomatic) solution for part 2 of day 18.
This year, I’ve been trying to learn/relearn Prolog by solving the Advent of Code problems. On today’s problem (day 18) I’ve encountered different behavior between compiled and directly run code.
I’m (ab-)using a dynamic predicate and tabling in the solution. From reading the reference manual this seems to necessitate incremental tabling to properly invalidate the table.
My code is:
:- dynamic([corrupted/2], [incremental(true)]).
initCorrupted(Points) :-
retractall(corrupted(_,_)),
foreach(member(X/Y,Points), assertz(corrupted(X,Y))).
step(X/Y, X2/Y) :-
(X2 is X + 1; X2 is X - 1),
0 =< X2, X2 =< 3,
\+ corrupted(X2,Y).
step(X/Y, X/Y2) :-
(Y2 is Y + 1; Y2 is Y - 1),
0 =< Y2, Y2 =< 3,
\+ corrupted(X,Y2).
:- table pathToGoal/2 as incremental.
pathToGoal(Start,Start).
pathToGoal(Start,End) :-
step(Start,Next),
pathToGoal(Next,End).
binarySearch(Low,Low,_, Low).
binarySearch(Low,High,Points, Res) :-
Mid is (Low + High) // 2,
length(Prefix, Mid),
append(Prefix,_,Points),
initCorrupted(Prefix),
( pathToGoal(0/0,3/3)
-> Low2 is Mid + 1, binarySearch(Low2,High,Points,Res)
; binarySearch(Low,Mid,Points,Res)
).
compute2(Points, Res) :-
length(Points,N),
High is N - 1,
binarySearch(0, High, Points, M),
nth1(M, Points, Res).
run() :-
Points = [ 0/3, 1/2, 2/1, 3/0, 2/2, 1/3, 0/2],
compute2(Points, X/Y),
format('Result: ~d,~d~n', [X,Y]).
Directly running this I get the expected output
$ swipl -g run -g halt aoc18.pl
Result: 3,0
However, when first compiling the code, I get a different result
$ swipl -g run -g halt -o aoc -c aoc18.pl
$ ./aoc
Result: 1,3
This is also the result I get when not declaring the table of pathToGoal
as incremental. Manually abolishing the table in initCorrupted/1
with abolish_table_subgoals(pathToGoal(_,_))
fixes the issue in the compiled code, leading me to believe the table is not properly invalidated.
Is this behavior expected, and I am doing something wrong? Or is this a bug?
PS: I’m also happy to hear about any improvements to make my solution more idiomatic.