% Example with matrices,based on:
%
% Three jugs problem in Minzinc modelled as a shortest path problem.
%
% Problem from Taha "Introduction to Operations Research", page 245
% 
% Model created by Hakan Kjellerstrand, hakank@bonetmail.com
% See also my MiniZinc page: http://www.hakank.org/minizinc

%
% VSC: had to transpose the matrix, and change the constraints....
%

:- style_check( all ).

:- use_module(library(gecode/clpfd)).
:- use_module(library(maplist)).
:- use_module(library(lists)).

main :-
	problem(Z, X, InFlow, OutFlow, N),
	out(Z, X, InFlow, OutFlow, N),
	fail.
main.

problem(Z, X, InFlow, OutFlow, N) :-
	N = 15,
	Start = 1,
	End = 15,
	M = 999,
	d( M, DD ),
	D <== array[1..N,1..N] of DD, % distance
	RHS <== array[1..N] of _, % requirements (right hand statement)
	X <== array[1..N, 1..N] of 0..1, % the resulting matrix, 1 if connected, 0 else
	OutFlow <== array[1..N] of 0..1,
	InFlow <== array[1..N] of 0..1,

% objective to minimize
	Z in 0..M,
	Z #= sum( [I in 1..N, J in 1..N] where D[I,J]<M,
		  D[I,J]*X[I,J]),

% solve minimize z;
% alternative solve statements which may give faster solution
%solve :: int_search([ x[i,j] | i,j in 1..n], first_fail, indomain_min, complete) minimize z;
% solve minimize z;
	minimize(Z),
	

% constraint 
	foreach(I in 1..N,
	    ( I == Start ->
	      RHS[I] <== 1 ;
	      I == End ->
	      RHS[I] <== -1 ;
	      RHS[I] <== 0 )
	   ),


    % must be larger than 0??
   foreach( [I in 1..N, J in 1..N],
	( D[J,I] = M ->
	  X[J,I] #= 0 ;
	  true )
      ),
				% outflow constraint
   foreach(I in 1..N,
       OutFlow[I] #= sum(J in 1..N where D[J,I]<M, X[J,I])
      ),
   % inflow constraint
  foreach(J in 1..N,
      InFlow[J] #= sum(I in 1..N where D[J,I]<M, X[J,I])
     ),
   % inflow = outflow
  foreach(I in 1..N,  OutFlow[I]-InFlow[I]#=RHS[I]),

  % labeling
  labeling( [], X).

% data
d(M, [
  M, 1, M, M, M, M, M, M, 1, M, M, M, M, M, M,
  M, M, 1, M, M, M, M, M, M, M, M, M, M, M, M,
  M, M, M, 1, M, M, M, M, 1, M, M, M, M, M, M,
  M, M, M, M, 1, M, M, M, M, M, M, M, M, M, M,
  M, M, M, M, M, 1, M, M, 1, M, M, M, M, M, M,
  M, M, M, M, M, M, 1, M, M, M, M, M, M, M, M,
  M, M, M, M, M, M, M, 1, 1, M, M, M, M, M, M,
  M, M, M, M, M, M, M, M, M, M, M, M, M, M, 1, 
  M, M, M, M, M, M, M, M, M, 1, M, M, M, M, M,
  M, 1, M, M, M, M, M, M, M, M, 1, M, M, M, M,
  M, M, M, M, M, M, M, M, M, M, M, 1, M, M, M,
  M, 1, M, M, M, M, M, M, M, M, M, M, 1, M, M,
  M, M, M, M, M, M, M, M, M, M, M, M, M, 1, M,
  M, 1, M, M, M, M, M, M, M, M, M, M, M, M, 1, 
  M, M, M, M, M, M, M, M, M, M, M, M, M, M, M
]).

/*
% shows the result matrix
output [
       if i = 1 /\ j = 1 then 
         "z: " ++ show(z) ++ "\n" ++
         "inFlow:  " ++ show(inFlow) ++ "\n" ++ "outFlow: " ++ show(outFlow) ++ "\n" ++
         "    1 2 3 4 5 6 7 8 9 0 1 2 3 4 5\n" 
       else "" endif ++
       if j = 1 then show(i) ++ " : " else "" endif ++
       show(x[i,j]) ++ if j = n then "\n" else " " endif
       | i in 1..n, j in 1..n
];

*/

out(Cost, Ts, Ins, Out, N) :-
	format('cost = ~d~n', [Cost]),
	InsL <== list(Ins),
	OutL <== list(Out),
	format('Inputs  =', []), maplist(out, InsL), nl,
	format('Outputs =', []), maplist(out, OutL), nl,
	format('transitions =~n', []),
	foreach(I in 1..N, outl(Ts[_,I]) ).

outl( X ) :-
	L <== X, % evaluate matrix notation to Prolog lists.
	format('  ', []),
	maplist(out, L), nl.

out(0) :- format(' .', []).
out(1) :- format(' 1', []).