Home > OS >  Prolog: How do I remove symmetrical values in predicates
Prolog: How do I remove symmetrical values in predicates

Time:12-12

I have a question regarding the removal of symmetrical values in my predicates. These predicates are in my database and I used assertz to add them there.

So I have:

foo(a,b).
foo(b,a).
foo(c,d).
foo(e,f).
foo(f,e).

I'm trying to remove

foo(b,a).
foo(f,e).

An I tried to make this rule:

remove :- foo(A,B),foo(B,A),retract(foo(B,A)).

However, this removes all the predicates in my DB and I don't know how to prevent that.

If someone could help me I'd really appreciate it!

Thank you.

CodePudding user response:

There are two distinct semantics for retract/1:

  • immediate update view: upon backtracking, retracted clauses can no longer be seen (they became invisible immediately).
  • logical update view: upon backtracking, retracted clauses can still be seen (they became invisible only on the next predicate call). This update view is the ISO standard.

In the logical update view, for example, when the predicate remove/1 is called:

  • First it sees foo(a,b) and foo(b,a) and hence it retracts foo(b,a).
  • Afterward, upon backtracking, it sees foo(b,a) and foo(a,b) and hence it also retracts foo(a,b).

To solve the problem, you can use the ISO built-in predicate once/1 (which prevents backtracking).

:- dynamic foo/2.

foo(a,b).
foo(b,a). 
foo(c,d).
foo(e,f).
foo(f,e).

remove :- 
    once( ( foo(A, B),
            foo(B, A),
            retract(foo(B, A)) ) ).

To retract only one symmetrical fact, you can ask:

?- listing(foo), remove, listing(foo).
:- dynamic foo/2.

foo(a, b).
foo(b, a). % <== only this fact is retracted!
foo(c, d).
foo(e, f).
foo(f, e).

:- dynamic foo/2.

foo(a, b).
foo(c, d).
foo(e, f).
foo(f, e).

true.

To retract all symmetrical facts, you can define:

remove_all_sym :-
    (   remove
    ->  remove_all_sym
    ;   true ).

Example:

?- listing(foo), remove_all_sym, listing(foo).
:- dynamic foo/2.

foo(a, b).
foo(b, a). % <== this fact is retracted!
foo(c, d).
foo(e, f).
foo(f, e). % <== this fact is retracted!

:- dynamic foo/2.

foo(a, b).
foo(c, d).
foo(e, f).

NOTE A better alternative would be to avoid inserting symmetrical facts into the database:

assert_foo(A, B) :-
    (   foo(B, A)          
    ->  true                
    ;   assertz(foo(A, B)) ).
  • Related