[comp.lang.prolog] XOR without redundancy and databases

chomicki@aramis.UUCP (04/04/87)

Problem: write a Prolog predicate xor(G1,G2) which will generate
	through backtracking all and only solutions to G1 if there is
	one; otherwise it will generate all and only solutions to G2.
	Each solution should be generated exactly once.
	
In essence, the code should look like:

xor(G1,G2):- G1.
xor(G1,G2):- no_success_in_the_previous_clause, G2.

The problem is how to obtain information about those proof tree
branches that have ultimately failed. Existing bindings and current
refutation bear no trace of them. Prolog interpreter, however, knows
the full computation history. Can we make him talk?

The most obvious answer would be to explicitly use the database
(assert, record etc.) or some other side-effects(file operations).
There is a subtler way which makes use of the concept of the "current
universe of atoms". This universe contains all the atoms known to
the interpreter. They come from three different sources:
	- the text of the program.
	- the computation so far: input etc.
	- the code of the interpreter itself if it is written in Prolog.
The branches of the proof tree may be marked by special atoms
which do not appear anywhere else.

xor(G1,G2) :- pick(String), xor(G1,G2,String).

xor(G1,G2,String):- G1, there_was_once(String).
xor(G1,G2,String):- \+ was_there_once(String), G2.

pick(String) :- new_string(String), \+ was_there_once(String), !.
there_was_once(String):- name(_,String).
was_there_once(String):- current_atom(Atom), name(Atom,String).

new_string([112]).
new_string([112|L]):-new_string(L).

NOTE 1: current_atom/1 which enumerates all the current atoms is
available in Edinburgh and Quintus Prologs.

NOTE 2: We can not directly test for the presence of an atom in the current
universe of atoms. By the very appearance in the goal, the atom
becomes part of this universe! Hence

?- current_atom(abrakadabra).

succeeds even if we substitute the strangest atoms for abrakadabra.
Thus we enumerate the current atoms and compare their string
versions with the original string.

NOTE 3: For every invocation of xor/3 we need a new string which has not
appeared anywhere else as an atom. This string can not be permanently
assigned to a textual appearance of xor. Thus just before the
invocation of xor/3 strings should be generated and tested for uniqueness
(by was_there_once/1) until a brand new atom is found. That would
narrow down the dangerous area to the execution of xor/3 where we
generally know what atoms may appear.
-- 
Jan Chomicki (chomicki@aramis.rutgers.edu)	Phone: (201) 932-3999
Dept.of Computer Science, Rutgers University, New Brunswick, NJ 08903
Usenet: {...harvard,pyramid,seismo,nike}!rutgers!aramis!chomicki
Arpanet: chomicki@aramis.rutgers.edu

lee@mulga.UUCP (04/06/87)

In article <425@aramis.RUTGERS.EDU> chomicki@aramis.RUTGERS.EDU (Jan Chomicki) writes:
>xor(G1,G2) :- pick(String), xor(G1,G2,String).
>
>xor(G1,G2,String):- G1, there_was_once(String).
>xor(G1,G2,String):- \+ was_there_once(String), G2.
>
>pick(String) :- new_string(String), \+ was_there_once(String), !.
>there_was_once(String):- name(_,String).
>was_there_once(String):- current_atom(Atom), name(Atom,String).
>
>new_string([112]).
>new_string([112|L]):-new_string(L).

One problem with this is that nested calls to xor may not work correctly.
The inner call can use the same string and cause it to be put in the
dictionary, even though G1 (from the outer call) fails.  This would
prevent G2 from being called. eg:

?- xor((xor(true, fail), fail), true). 	% xor is a confusing name here

fails when it should succeed (I think).  Just to stop a dozen people
sending in fixes, I guess I should point out that you can get around
this by creating two related strings, both of which must be "new"
then making one "old".  The computation may create the string in other
ways too (though this is unlikely, I guess).

was_there_once/1 could get pretty slow on some systems also (maybe slower
than finding the first solution to G1).

Can anyone confirm that default/2 in Prolog II uses soft cut?
Are there any other systems with soft cut implemented?

	lee