Download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/*
 
  Steiner triplets in B-Prolog.
 
  """
  The ternary Steiner problem of order n is to find n(n-1)/6 sets of elements
  in {1,2,...,n} such that each set contains three elements and any two
  sets have at most one element in common.
 
  For example, the following shows a solution for size n=7:
 
      {1,2,3}, {1,4,5}, {1,6,7}, {2,4,6}, {2,5,7}, {3,4,7}, {3,5,6}
 
  Problem taken from:
  C. Gervet: Interval Propagation to Reason about Sets: Definition and
             Implementation of a PracticalLanguage, 
             Constraints, An International Journal, vol.1, pp.191-246, 1997.
  """
 
 
  Note: This model uses arrays of booleans as an representation of sets.
  Compare with the following model with the same principle:
 
 
  Model created by Hakan Kjellerstrand, hakank@gmail.com
  See also my B-Prolog page: http://www.hakank.org/bprolog/
 
*/
 
% Licenced under CC-BY-4.0 : http://creativecommons.org/licenses/by/4.0/
 
go :-
        N = 9,
        steiner(N,Steiner),
        write(Steiner),nl.
 
 
steiner(N,Steiner) :-
 
        % number of sets
        Nb is (N * (N-1)) // 6,
 
        matrix(Sets,[Nb,N]),
        term_variables(Sets,SetsList),
        SetsList :: 0..1,
 
        % atmost 1 element in common
        foreach((S1,I) in (Sets,1..Nb),
                (
                    3 #= sum(S1), % cardinality
                    foreach((S2,J) in (Sets,1..Nb),
                            [Common],
                            (
                                I > J ->
                                    union_card(S1,S2,Common),
                                    Common #=< 1
                            ;
                                    true
                            )
                           )
                )
        ),
 
        labeling([constr,down],SetsList),
         
        % convert to set representation
        Steiner @= [Res : SS in Sets, [Res], boolean_to_set(SS,Res)].
 
         
 
%
% number of common elements in two "sets"
%
union_card(S1,S2,CardCommon) :-
        CardCommon #= sum([(SS1 + SS2 #= 2) : (SS1,SS2) in (S1,S2)]).
 
%
% convert a list of boolean to a "set"
%
boolean_to_set(List,Set) :-
        length(List,Len),
        Set @= [I : (C,I) in (List, 1..Len), C == 1].
 
 
matrix(_, []) :- !.
matrix(L, [Dim|Dims]) :-
        length(L, Dim),
        foreach(X in L, matrix(X, Dims)).