Download
/*

  Car sequencing in Picat.

  This model is based on the car sequencing model in
  Pascal Van Hentenryck
  "The OPL Optimization Programming Language", page 184ff.
  (Via other implementations:
     http://www.hakank.org/google_or_tools/car.py
     http://www.hakank.org/minizinc/car.mzn
     http://www.hakank.org/bprolog/car.pl
  )

  Model created by Hakan Kjellerstrand, hakank@gmail.com
  See also my Picat page: http://www.hakank.org/picat/

*/

% Licenced under CC-BY-4.0 : http://creativecommons.org/licenses/by/4.0/

import cp.


main => go.

go =>
        
   NbCars = 6,
   Cars = 1..NbCars,
   NbOptions = 5,
   Options = 1..NbOptions,
   NbSlots = 10,
   Slots = 1..NbSlots,
   Demand = [1, 1, 2, 2, 2, 2],
   Option = [[1, 0, 0, 0, 1, 1],
        [0, 0, 1, 1, 0, 1],
        [1, 0, 0, 0, 1, 0],
        [1, 1, 0, 1, 0, 0],
        [0, 0, 1, 0, 0, 0]],
   Capacity = [[1,2],
          [2,3],
          [1,3],
          [2,5],
          [1,5]],

   % OptionDemand = [],
   % foreach(I in Options)
   %    OD #= sum([ Demand[J]*Option[I,J] : J in Cars]),
   %    OptionDemand := OptionDemand ++ [OD]
   % end,

   OptionDemand = [sum([Demand[J]*Option[I,J] : J in Cars]) : I in Options],

   %
   % decision variables
   %
   Slot = new_list(NbSlots),
   Slot :: 1..NbCars,

   Setup = new_array(NbOptions,NbSlots),
   Setup :: 0..1,

   % To minimize
   Z #= sum([S*Slot[S] : S in Cars]),

   %
   % Constraints
   %
   foreach(C in Cars)
      sum([(Slot[S] #= C) : S in Slots]) #= Demand[C]
   end,

   foreach(O in Options, S in 1..(NbSlots - Capacity[O,2] + 1))
      sum([Setup[O,J] : J in S..S + Capacity[O,2]- 1]) #=< Capacity[O,1]
   end,

   %% This don't work
   % foreach(O in Options, S in Slots)
   %    Setup[O,S] #= Option[O,Slot[S]]
   % end,
   %% Instead one has to use a couple of element/3.
   foreach(O in Options, S in Slots)
      element(S,Slot,SlotS),
      matrix_element(Option,O,SlotS,SS),
      Setup[O,S] #= SS
   end,

   foreach(O in Options, I in 1..OptionDemand[O])
       sum([Setup[O,S] : S in 1..(NbSlots - I * Capacity[O,2])]) #>=
                       (OptionDemand[O] - I * Capacity[O,1])
   end,


   Vars = Slot ++ Setup,
   solve([$min(Z)], Vars),

   writeln(z=Z),
   printf("slot:\n%w\n", Slot),
   printf("setup:\n"),
   foreach(Row in Setup) writeln(Row.to_list()) end,

   nl.


% matrix_element(X, I, J, Val) =>
%    element(I, X, Row),
%    element(J, Row, Val).

matrix_element(X, I, J, Val) =>
   freeze(I, (element(I, X, Row),freeze(J,element(J,Row,Val)))).