0

I have this code that evaluates a list of numbers and returns lists matching the pattern [G,A],[A,B],[B,C],[C,D],[D,E],[E,F],[F,G]. However, I want the numbers to only to be unique numbers. EG: ([0,2],[2,4],[4,19],[19,3],[3,5],[5,7],[7,0]). The different method returns true or false based on the numbers inputted. However, the code still returns numbers that have more than one similar numbers.

r5(L,R):-
    R = [[G,A],[A,B],[B,C],[C,D],[D,E],[E,F],[F,G]],

    [A,B,C,D,E,F,G] ins 0 .. 27,

    different([A,B,C,D,E,F,G]),

    member([G,A],L),
    member([A,B],L),
    member([B,C],L),
    member([C,D],L),
    member([D,E],L),
    member([E,F],L),
    member([F,G],L),

    label([A,B,C,D,E,F,G]).

This is an example of a portion what it returns:

R = [[0, 2], [2, 0], [0, 2], [2, 5], [5, 9], [9, 2], [2, 0]] ;
R = [[0, 2], [2, 0], [0, 2], [2, 5], [5, 23], [23, 17], [17, 0]] ;
R = [[0, 2], [2, 0], [0, 2], [2, 5], [5, 24], [24, 19], [19, 0]] ;
R = [[0, 2], [2, 0], [0, 2], [2, 5], [5, 26], [26, 12], [12, 0]] ;
R = [[0, 2], [2, 0], [0, 2], [2, 9], [9, 5], [5, 2], [2, 0]] ;
R = [[0, 2], [2, 0], [0, 2], [2, 9], [9, 15], [15, 2], [2, 0]] ;
R = [[0, 2], [2, 0], [0, 2], [2, 9], [9, 15], [15, 17], [17, 0]] ;
R = [[0, 2], [2, 0], [0, 2], [2, 9], [9, 15], [15, 19], [19, 0]] ;
R = [[0, 2], [2, 0], [0, 2], [2, 15], [15, 9], [9, 2], [2, 0]] ;
R = [[0, 2], [2, 0], [0, 2], [2, 21], [21, 1], [1, 12], [12, 0]] ;
R = [[0, 2], [2, 0], [0, 2], [2, 21], [21, 1], [1, 20], [20, 0]] ;
R = [[0, 2], [2, 0], [0, 2], [2, 21], [21, 11], [11, 12], [12, 0]] ;
R = [[0, 2], [2, 0], [0, 2], [2, 21], [21, 11], [11, 17], [17, 0]] ;
R = [[0, 2], [2, 0], [0, 2], [2, 21], [21, 24], [24, 19], [19, 0]] ;
R = [[0, 2], [2, 0], [0, 12], [12, 1], [1, 18], [18, 12], [12, 0]] ;

None of those are valid because they contain repeated numbers. Following are two outputs from further down in the output that are valid:

R = [[0, 2], [2, 9], [9, 4], [4, 8], [8, 23], [23, 17], [17, 0]] ;
R = [[0, 2], [2, 9], [9, 4], [4, 8], [8, 24], [24, 19], [19, 0]] ;

This is the different method:

different(X) :-
    sort(X, Sorted),
    length(X, OriginalLength),
    length(Sorted, SortedLength),
    OriginalLength == SortedLength.

Here is my original call:

r5_3([[0, 2],[2,0],[0, 12],[12,0],[0, 17],[17,0],[0, 19],[19,0],[0, 20],[20,0],[1, 4],[4,1],[1, 12],[12,1],[1, 18],[18,1],[1, 20],[20,1],[1, 21],[21,1],[2, 5],[5,2],[9, 2],[2,9],[2, 15],[15,2],[2, 21],[21,2],[8, 3],[3,8],[10, 3],[3,10],[16, 3],[3,16],[3, 22],[22,3],[25, 3],[3,25],[8, 4],[4,8],[9, 4],[4,9],[4, 23],[23,4],[26, 4],[4,26],[9, 5],[5,9],[5, 23],[23,5],[24, 5],[5,24],[26, 5],[5,26],[14, 6],[6,14],[17, 6],[6,17],[18, 6],[6,18],[24, 6],[6,24],[25, 6],[6,25],[18, 7],[7,18],[19, 7],[7,19],[22, 7],[7,22],[23, 7],[7,23],[26, 7],[7,26],[8, 14],[14,8],[8, 23],[23,8],[8, 24],[24,8],[9, 15],[15,9],[9, 13],[13,9],[16, 10],[10,16],[10, 20],[20,10],[10, 13],[13,10],[10, 27],[27,10],[11, 12],[12,11],[17, 11],[11,17],[11, 21],[21,11],[25, 11],[11,25],[11, 27],[27,11],[18, 12],[12,18],[26, 12],[12,26],[14, 15],[15,14],[16, 14],[14,16],[26, 14],[14,26],[17, 15],[15,17],[19, 15],[15,19],[16, 20],[20,16],[16, 22],[22,16],[17, 23],[23,17],[18, 27],[27,18],[24, 19],[19,24],[19, 27],[27,19],[25, 20],[20,25],[24, 21],[21,24],[13, 21],[21,13],[25, 22],[22,25],[13, 22],[22,13],[27, 13],[13,27]],R).
Jordan.McBride
  • 267
  • 2
  • 7
  • 20
  • 1
    Where is `different/1` defined? Use `all_different([A,B,C,D,E,F,G])`. – lurker Feb 16 '17 at 00:59
  • You say "The different method returns true or false based on the numbers inputted", but prolog doesn't return anything. The predicate either succeeds or fails. – Enigmativity Feb 16 '17 at 01:41
  • 1
    @Enigmativity I added my different method, but if there already exists an all_different/1 method, then there's no use in me re-inventing the wheel. :) – Jordan.McBride Feb 16 '17 at 02:52
  • @Jordan.McBride - I'm guessing you're more used to imperative programming than Prolog. Nonetheless, why do you think that `different` actually lets you know everything is different? – Enigmativity Feb 16 '17 at 03:01
  • @Jordan.McBride - try this `different([]). different([H|T]) :- not(member(H,T)), different(T).` – Enigmativity Feb 16 '17 at 03:03
  • Can you please show an example query? How are you using `L` in the call, `r5(L, R)`? – lurker Feb 16 '17 at 16:41
  • The title to this question is a little puzzling as well. – lurker Feb 16 '17 at 17:20
  • @Enigmativity For sure. Prolog's pretty foreign to me, but I'm trying to relearn how to think about the problems. Thanks for the help – Jordan.McBride Feb 16 '17 at 22:54
  • @lurker the call would be r5([1,2],[2,1],[3,4],[4,3]],R) (with more data ranging from 0-27) – Jordan.McBride Feb 16 '17 at 22:55
  • @lurker I was having trouble with coming up with a title, so I just wrote what I thought my problem was, because I was assuming that running my different method would return false, and then the program would run past it instead of backwards – Jordan.McBride Feb 16 '17 at 23:01
  • 3
    @Jordan.McBride - Prolog is an excellent language to learn in order to make yourself think differently about coding. When you get that ah-ha moment you'll end up loving it. I'm in no way an expert or even good at Prolog, but it remains one of my very favourite languages. – Enigmativity Feb 16 '17 at 23:29
  • 1
    @Jordan.McBride can you comment regarding what's missing in the answer I provided? – lurker Feb 17 '17 at 11:54
  • @Jordan.McBride in the question, you write: *"This is an example of a portion what it returns:"* but you never show what **it** is. Please include the exact query you used. At least, describe your **`L`** argument: what is its **length**? What are its **elements**? – Will Ness Feb 17 '17 at 21:33
  • @WillNess when I replaced my method with the `all_different` method it works. I can add my call to my answer, but this user error has now been fixed :) – Jordan.McBride Feb 17 '17 at 23:12

1 Answers1

3

all_different/1 is part of the CLP(FD) library. Your different/1 will only work if you do your label/1 before calling different/1.

So you could either use all_different/1 (preferred) with your current implementation, or you could re-arrange your code as follows:

r5(L,R):-
    R = [[G,A],[A,B],[B,C],[C,D],[D,E],[E,F],[F,G]],

    [A,B,C,D,E,F,G] ins 0 .. 27,

    % all_different([A,B,C,D,E,F,G]), % preferred in place of 'different/1' below

    label([A,B,C,D,E,F,G]),        

    different([A,B,C,D,E,F,G]),

    member([G,A],L),
    member([A,B],L),
    member([B,C],L),
    member([C,D],L),
    member([D,E],L),
    member([E,F],L),
    member([F,G],L).


The purpose of L in the original code is a little unclear. A more general solution might look something like this:
:- use_module(library(clpfd)).

% Define consecutive intervals consisting of Length intervals
%  with elements from 0 to MaxNumber
consecutive_intervals(MaxNumber, Length, Intervals):-
    length(Elements, Length),             % Establish the number of elements
    Elements ins 0 .. Max,                % Establish the range of each element
    all_different(Elements),              % Each element is different
    list_intervals(Elements, Intervals),  % Define consecutive intervals
    label(Elements).

% list_intervals(List, Intervals)
%    Intervals is a complete list of consecutive intervals with elements from List
list_intervals([X1,X2|Xs], [[X1,X2]|T]) :-
    list_intervals([X2|Xs], X1, T).
list_intervals([X2], X1, [[X2,X1]]).
list_intervals([X2,X3|Xs], X1, [[X2,X3]|T]) :-
    list_intervals([X3|Xs], X1, T).

The number of solutions is large, but here's an small, abbreviated example:

?- consecutive_intervals(4, 3, R).
R = [[0, 1], [1, 2], [2, 0]] ;
R = [[0, 1], [1, 3], [3, 0]] ;
R = [[0, 1], [1, 4], [4, 0]] ;
R = [[0, 2], [2, 1], [1, 0]] ;
R = [[0, 2], [2, 3], [3, 0]] ;
R = [[0, 2], [2, 4], [4, 0]] ;
...
R = [[4, 3], [3, 0], [0, 4]] ;
R = [[4, 3], [3, 1], [1, 4]] ;
R = [[4, 3], [3, 2], [2, 4]] ;
false.
lurker
  • 56,987
  • 9
  • 69
  • 103
  • 1
    Why all these `member/2` goals? One fixed choice seems to be enough. – false Feb 16 '17 at 15:43
  • 1
    @false I was just explaining to the OP why they were seeing the results they were seeing. I wasn't trying to provide the optimum solution. I'll update when I get the chance to offer an improvement. – lurker Feb 16 '17 at 16:37
  • @lurker The purpose of L is that its only a select few of the pairs that exist in the range of 0->27. I'm sure that I'm doing it inefficiently. – Jordan.McBride Feb 16 '17 at 22:57
  • 1
    based on OP's previous question and comments, `L` is a list of ~ 150 pairs of numbers, it turns out (now) in range 0..27, from which they want to select a sequence of pairs "connected at edges". this would make `label` not needed, when `all_different` is used. Sample call: `r5([[1,2],[3,4],[4,5],[5,6],[6,7],[7,8],[8,9],[9,0],[2,3],[9,1],[9,2],[9,3],[9,4],[8,2]],X).`. The question is really unclear. – Will Ness Feb 17 '17 at 21:45