Different executions before and after running trace?

I’m using: SWI-Prolog version 8.0.3 for x86_64-darwin

I’m very grateful, in advance, for any explanation of this behavior from experts. I’ve been playing with abduction lately, trying to apply it to logical operators. My code includes the following predicates, based on the discussion of abduction in Peter Flach’s book Simply Logical:

abduce(P, E) :- abduce(P, [], E, [], _Seen).

% ...
% I'm omitting most the of clauses of abduce/5, as this seems to be the one that's malfunctioning
abduce(P, E, [P | E], S, [P | S]) :-
    abducible(P), !,
    \+ member(\+P, E).
% ...
% there's also is a similar set of clauses for abducing negations, including the following:
abduce_false(P, E, [\+P | E], S0, [\+P | S0]) :-
    abducible(P), !,
    \+ member(P, E).
% ...

abducible(ostrich(_)).
and(A, B) :- A, B.

It seems like Prolog is simply ignoring my calls to member/2 in the above code sometimes. When I fire up the interpreter, I can get this response to a query:

?- abduce(and(ostrich(X), \+ostrich(X)), H) 
H = [\+ostrich(X), ostrich(X)].

This shouldn’t be happening, since the only way to add \+ostrich(X) to the explanation list E is if E doesn’t contain ostrich(X), which it does. When I run the trace, the same query fails! And after I run the trace, I consistently get

?- abduce(and(ostrich(X), \+ostrich(X)), H) 
false.

Also, after doing the trace, abduce/2 behaves correctly with other arguments that would have caused it to misbehave in a similar manner previously. For illustration I’ve copy/pasted (minus most of the trace) my interpreter session below. I can also give more of the omitted details if need be. I’m pretty confident the problem is in the clause quoted above, especially since the predicate begins to behave as expected after a trace.

?- abduce(and(ostrich(X), \+ostrich(X)), H).
H = [\+ostrich(X), ostrich(X)].
?- debug.
Correct to: "edinburgh:debug"? yes
true.
[debug] ?- abduce(and(ostrich(X), \+ostrich(X)), H).
H = [\+ostrich(X), ostrich(X)].
[debug] ?- trace.
true.
[trace] ?- abduce(and(ostrich(X), \+ostrich(X)), H).
Call: (8) abduce(and(ostrich(_7792), \+ostrich(_7792)), _7812) ? creep
Call: (9) abduce(and(ostrich(_7792), \+ostrich(_7792)), [], _7812, [], _8098) ? creep
...
Fail: (8) abduce(and(ostrich(_7792), \+ostrich(_7792)), _7812) ? creep
false.
[trace] ?- notrace.
true.
[debug] ?- abduce(and(ostrich(X), \+ostrich(X)), H).
false.

UPDATE: on a whim I tried explicitly replacing member/2 with what I thought would function the same:

my_member(X, [X|_]).
my_member(X, [_|T]) :- my_member(X, T).

The code now gives the correct answer even before running the trace. So I guess the issue is with the builtin member/2.

1 Like

Hard to tell whether something is wrong and what. The output

Correct to: "edinburgh:debug"? yes

is suspicious. That shouldn’t happen and indicates at a problem with the installation or something similar. Anyway, without the full code and exactly what you did one can only make wild guesses.

I tried reinstalling Prolog. Nothing’s different, as far as I can tell. The output

Correct to: "edinburgh:debug"? yes

seemed to be the result of me using the unknown/2 directive in the code, which also seems to be triggering the behavior.

Demo in SWISH: https://swish.swi-prolog.org/p/abduction_demo.pl

The error doesn’t appear in SWISH, I assume because I can’t call unknown/2. That code with unknown/2 uncommented was producing the odd response to ?- abduce(and(ostrich(X), +ostrich(X)), H).

If you set unknown to fail, it gives a big warning

101 ?- unknown(O, fail).
Warning: Using a non-error value for unknown in the global module
Warning: causes most of the development environment to stop working.
Warning: Please use :- dynamic or limit usage of unknown to a module.
Warning: See http://www.swi-prolog.org/howto/database.html
O = trace.

Don 't. If you still really want to, member/2 is undefined and fails silently. You can use :- use_module(library(lists)). to fix that, but you’ll run into many more problems that are hard to debug.

The unknown flag is something from the past. It still can have some value if we want to use Prolog as a theorem prover on a set of self-contained horn clauses. In that case load the theory into a module and use unknown inside the module.

Whoops. I must have skipped over that in a pile of other warnings I was ignoring. Thanks–guess I’ll avoid unknown for now.