Download
/*
* SICSTUS CLPFD DEMONSTRATION PROGRAM
* Purpose : Langford's Number Problem
* Author : Mats Carlsson
*
* | ?- steiner(dual,[],33,bound).
*/
:- module(steiner, [steiner/4]).
:- use_module(library(lists)).
:- use_module(library(clpfd)).
steiner(dual, _Opt, N, Consistency) :-
problem(N, Triples, Consistency),
append(Triples, Vars),
dual_labeling(0, N, Vars),
format_steiner(Triples, N).
steiner(byrow, Opt, N, Consistency) :-
problem(N, Triples, Consistency),
append(Triples, Vars),
labeling(Opt, Vars),
format_steiner(Triples, N).
steiner(bycol, Opt, N, Consistency) :-
problem(N, Triples, Consistency),
transpose(Triples, Transpose),
append(Transpose, Vars),
labeling(Opt, Vars),
format_steiner(Triples, N).
format_steiner(Triples, N) :-
format('Steiner instance of order ~d:\n', [N]),
( foreach(T,Triples)
do format('~t~d~+~t~d~+~t~d~+\n', T)
).
dual_labeling(N, N, _) :- !.
dual_labeling(N1, N3, Vars) :-
N2 is N1+1,
split_by_min(Vars, N2, Cands, Rest, Rest2),
M is N3>>1,
dual_choose(0, M, N2, Cands, Rest2),
dual_labeling(N2, N3, Rest).
split_by_min([], _, []) --> [].
split_by_min([X|L1], N, L2) --> [X],
{fd_min(X, Xmin)},
{Xmin=\=N}, !,
split_by_min(L1, N, L2).
split_by_min([X|L1], N, [X|L2]) -->
split_by_min(L1, N, L2).
dual_choose(M, M, _, Cands, Cands) :- !.
dual_choose(I, M, Val, [Val|Cands], Rest) :-
J is I+1,
dual_choose(J, M, Val, Cands, Rest).
dual_choose(I, M, Val, [X|Cands], [X|Rest]) :-
X #\= Val,
dual_choose(I, M, Val, Cands, Rest).
problem(N, Triples, Consistency) :-
M is N mod 6,
(M=:=1 ; M=:=3), !,
NTrip is N*(N-1)//6,
length(Triples, NTrip),
( foreach([A,B,C],Triples),
foreach([A,B],Tuples),
param(N)
do domain([A,B,C], 1, N),
A #< B, B #< C
),
lex_chain(Tuples,[increasing]),
pair_constraints(Triples, N, Consistency),
card_constraint(Triples, N).
pair_constraints(Triples, N, Consistency) :-
( foreach([A,B,C],Triples),
fromto(Codes,[AB,AC,BC|S],S,[]),
param([N,Consistency])
do scalar_product([N,1], [A,B], #=, AB, [consistency(Consistency)]),
scalar_product([N,1], [A,C], #=, AC, [consistency(Consistency)]),
scalar_product([N,1], [B,C], #=, BC, [consistency(Consistency)])
),
all_distinct(Codes, [consistency(Consistency)]).
card_constraint(Triples, N) :-
M is N>>1,
( for(J,1,N),
foreach(J-M,Cs),
param(M)
do true
),
append(Triples, Vars),
global_cardinality(Vars, Cs).