5

I am developing a program in PROLOG (with restrictions) which is supposed to output a combination of 6 numbers within certain restrictions.

The list must have the numbers from 1 to 4 and will, consequently, repeat 2 other numbers. It is not possible not to have a number from 1 to 4.

Possible examples:     Wrong examples:
1,2,3,4,1,1            1,2,3,2,3,3 //Missing #4
1,3,2,1,4,4            4,3,2,4,2,3 //Missing #1
1,2,3,3,2,4
4,1,3,2,1,4

In order to get this done I created some restrictions like the following:

Numbers = [A1, A2, A3, A4, A5, A6]
nCr(6,4) = 15 restrictions
A1 =\= A2 =\= A3 =\= A4 OR
A1 =\= A2 =\= A3 =\= A5 OR
Etc.

Here's the code I've developed so far:

make

pred(Numbers) :-

       Numbers = [A1, A2, A3, A4, A5, A6],
       domain(Numbers, 1, 4),

       %restrictions
       all_different([A1,A2,A6,A3]) #\/    %A1 =/= A2 =/= A6 =/= A3
        all_different([A1,A2,A6,A4]) #\/    %A1 =/= A2 =/= A6 =/= A4
         all_different([A1,A2,A6,A5]) #\/    %A1 =/= A2 =/= A6 =/= A5
          all_different([A1,A2,A3,A4]) #\/    %A1 =/= A2 =/= A3 =/= A4
           all_different([A1,A2,A3,A5]) #\/    %A1 =/= A2 =/= A3 =/= A5
            all_different([A1,A2,A4,A5]) #\/    %A1 =/= A2 =/= A4 =/= A5
             all_different([A1,A6,A3,A4]) #\/    %A1 =/= A6 =/= A3 =/= A4
              all_different([A1,A6,A3,A5]) #\/    %A1 =/= A6 =/= A3 =/= A5
               all_different([A1,A6,A4,A5]) #\/    %A1 =/= A6 =/= A4 =/= A5
                all_different([A1,A3,A5,A4]) #\/    %A1 =/= A3 =/= A4 =/= A5
                 all_different([A2,A6,A3,A4]) #\/    %A2 =/= A6 =/= A3 =/= A4
                  all_different([A2,A6,A3,A5]) #\/    %A2 =/= A6 =/= A3 =/= A5 
                   all_different([A2,A6,A4,A5]) #\/    %A2 =/= A6 =/= A4 =/= A5
                    all_different([A2,A3,A4,A5]) #\/    %A2 =/= A3 =/= A4 =/= A5 
                     all_different([A6,A3,A4,A5]),    %A6 =/= A3 =/= A4 =/= A5

           labeling([], Numbers).

The logic seems fine to me, but this implementation is not working as it should. There are no solutions which meet the restrictions typed. Can anyone give me a hand?

| ?- pred([A1, A2, A3, A4, A5, A6]).
no
false
  • 10,264
  • 13
  • 101
  • 209
GRoutar
  • 1,311
  • 1
  • 15
  • 38
  • Try to express restrictions at higher level. As you wrote them, it's really unreadable... – CapelliC Dec 12 '14 at 19:09
  • This is subproblem i'm trying to solve in order to develop a bigger program, that's the reason the code isn't pretty yet. I have made some changes anyway. – GRoutar Dec 12 '14 at 19:15
  • @Khabz: when you talk about "restrictions", could it be that you mean constraints? At least this is what I believe to be true when looking at your programmes. – false Dec 12 '14 at 23:02
  • @false: Yes that's what I mean. "Restrições" is the name in Portuguese that's why I usually say restrictions – GRoutar Dec 13 '14 at 00:16
  • @Khabz: It is constraints in Engelish, and contraintes in French – false Dec 13 '14 at 00:18

3 Answers3

6

this query should satisfy your requirements

?- Vs = [_,_,_,_,_,_], Vs ins 1..4,
   [A,B,C,D] ins 1..2, global_cardinality(Vs, [1-A,2-B,3-C,4-D]), label(Vs).
Vs = [1, 1, 2, 2, 3, 4],
A = B, B = 2,
C = D, D = 1 ;
Vs = [1, 1, 2, 2, 4, 3],
A = B, B = 2,
C = D, D = 1 ;
...
false
  • 10,264
  • 13
  • 101
  • 209
CapelliC
  • 59,646
  • 5
  • 47
  • 90
2

Here are two alternative queries using clpfd constraints:

  1. Using the nvalue/2 constraint, available with SICStus Prolog:

    ?- Vs = [_,_,_,_,_,_], domain(Vs,1,4),
       nvalue(4,Vs),
       labeling([],Vs).
    
  2. Using the element/3 constraint, the clpfd sibling of nth1/3 and member/2:

    ?- Vs = [_,_,_,_,_,_], domain(Vs,1,4),
       element(_,Vs,1),element(_,Vs,2),element(_,Vs,3),element(_,Vs,4),
       labeling([],Vs).
    

Both queries give the same solution sequence:

Vs = [1,1,1,2,3,4] ? ;
Vs = [1,1,1,2,4,3] ? ;
Vs = [1,1,1,3,2,4] ? ;
Vs = [1,1,1,3,4,2] ? ;
Vs = [1,1,1,4,2,3] ? ;
Vs = [1,1,1,4,3,2] ? ...

The list above only includes the first few results, there are 1560 in total.

repeat
  • 18,496
  • 4
  • 54
  • 166
1

Please consider a more declarative style of programming. An alternative solution would be the following:

pred(NumberList) :-
    NumberList =[_,_,_,_,_,_],
    member(1, NumberList),
    member(2, NumberList),
    member(3, NumberList),
    member(4, NumberList),
    member(A, [1,2,3,4]),
    member(B, [1,2,3,4]),
    member(A, NumberList),
    member(B, NumberList),
    forall(member(X, NumberList), number(X)).

This clause states that:

  • the list must have a length of 6 elements
  • 1, 2, 3, 4 are all elements of the list
  • there may be other 1,2,3,4's part of the list
  • and all members must be numbers.

The reason the forall is necessary, is that otherwise solutions such as [1,2,3,4,,] would satisfy the pred predicate.

A last note is that 'pred' is not a right name for such a predicate.

  • 2
    forall/2 and number/1 are declarative? – false Dec 12 '14 at 23:03
  • This algorithm also came to my mind (+1 for implementing it), but CapelliC's seems like a better solution. Also, that's copy pasted code with a few alterations, the names in the original aren't random at all. – GRoutar Dec 13 '14 at 00:07