0

I have some data declared in a Prolog file that looks like the following:

gen1(grass).
gen1(poison).
gen1(psychic).
gen1(bug).
gen1(rock).

...

gen1((poison, flying)).
gen1((ghost, poison)).
gen1((water, ice)).

...

weak1(grass, poison).
weak1(grass, bug).
weak1(poison, rock).

strong1(grass, rock).
strong1(poison, grass).
strong1(bug, grass).
strong1(poison, bug).
strong1(psychic, poison).
strong1(bug, poison).
strong1(bug, psychic).
strong1(rock, bug).

Note that the data does not define strong1 or weak1 for compound gen1(...). Those are determined by rules which do not contribute to the minimal working example. I mention them because it might be useful to know they exist.

I am trying to find relations between these terms that form a cycle. Here's one sample function:

triangle1(A, B, C) :-
    setof(A-B-C, (
             gen1(A), gen1(B), gen1(C), A \= B, A \= C, B \= C,
              strong1(A, B), strong1(B, C), strong1(C, A)
             ), Tris),
    member(A-B-C, Tris).

This setup does remove duplicates where A, B, and C are in the same order. However, it doesn't remove duplicates in different orders. For example:

?- triangle1(A, B, C),
   member(A, [bug, grass, rock]),
   member(B, [bug, rock, grass]),
   member(C, [bug, rock, grass]).
A = bug,
B = grass,
C = rock ;
A = grass,
B = rock,
C = bug ;
A = rock,
B = bug,
C = grass ;
false.

That query should only return one set of [A, B, C].

I've thought about using sort/2, but there are cases where simply sorting changes the meaning of the answer:

?- triangle1(A, B, C),
   sort([A, B, C], [D, E, F]),
   \+member([D, E, F], [[A, B, C], [B, C, A], [C, A, B]]).
A = D, D = bug,
B = F, F = psychic,
C = E, E = poison .

I also tried < and >, but those don't work on atoms, apparently.

Any thoughts?

(I looked at the similar questions, but have no idea how what I'm doing here compares to what other people are doing)

EDIT: As per comment about minimal working example.

false
  • 10,264
  • 13
  • 101
  • 209
xenrelay
  • 111
  • 1
  • 9
  • You need to read [ask] and then provide us with a [mcve]. – Enigmativity Jan 01 '17 at 06:20
  • @Enigmativity I've actually read that before, and I have tried to comply with it here. I'll acknowledge that the question could be slightly more focused, and the sample data is not the most relevant for the contents of the question. I'll edit the question with better sample data, and that should provide the minimal example, albeit in Literate Programming style. – xenrelay Jan 01 '17 at 14:50

1 Answers1

2

You can try sorting inside the setof/3 call. So you should avoid the generation of triples in wrong order.

I mean: calling setof/3, instead of

A \= B, A \= C, B \= C,

try with

A @< B, A @< C, B \= C,

This way you impose that A is lower than B and lower than C, you avoid duplicates and maintain correct solutions.

The full triangle1/3

triangle1(A, B, C) :-
    setof(A-B-C, (
             gen1(A), gen1(B), gen1(C), A @< B, A @< C, B \= C,
              strong1(A, B), strong1(B, C), strong1(C, A)
             ), Tris),
    member(A-B-C, Tris).
max66
  • 65,235
  • 10
  • 71
  • 111
  • The use of `setof/3` removes duplicates due to multiple paths from one atom to another. This is based on https://stackoverflow.com/questions/16243081/how-can-i-prevent-duplicates-in-prolog , and is particularly handy for compound types. You'll need the full code to understand: https://gist.github.com/proegssilb/4bbc307ffad40e0ee337edc55dc2c4e6 – xenrelay Jan 01 '17 at 14:46
  • @proegssilb - I've tried your full code (reordering clauses or my gprolog ignore a lot of they) with a `triangle1/3` based of `setof/3` and with my `triangle1/3` semplified version; calling `triangle(A, B, C)` I get, in both cases, 854 results that are exactly the same (and in same order). – max66 Jan 01 '17 at 16:24
  • Oh, I'm using SWI Prolog 6.2.6, not GNU Prolog. In SWI Prolog, the rules for `strong/2` and `weak/2` generate double results for cases like `strong(X, (dragon, flying))`, because both `strong(ice, dragon)` and `strong(ice, flying)` are defined (At least, that's what I'm understanding from the GUI Tracer; not even remotely knowledgeable in how Prolog works). – xenrelay Jan 01 '17 at 16:58
  • @proegssilb - sorry: you're right: the rules `strong1(A, (B, C))` and similar are introducing duplicated solution. Good with `bagof/3`. – max66 Jan 01 '17 at 18:13