Initializing help system before first use

Table constraint: solving a binpacking problem


Type: Programming
Rating: 3 (intermediate)
Description: Implementation of user-defined constraints via a table_constraint
File(s): binpacking_table_constraint.mos


binpacking_table_constraint.mos
(!****************************************************************
   CP example problems
   ===================
   
   file binpacking_table_constraint.mos
   ````````````````````````````````````
   Bin-packing problem : 
    5 types of components: {glass, plastic, steel, wood, copper}
    3 types of bins: {red, blue, green} with capacities red: 5, blue: 5, green: 6
    Constraints:
    - red can contain glass, cooper, wood
    - blue can contain glass, steel, cooper
    - green can contain plastic, copper, wood
    - wood requires plastic; 
    - glass exclusive with copper;
    - red contains at most 1 wood component
    - green contains at most 2 wood components
   Given a component supply of 
    12 of glass, 10 of plastic, 8 of steel, 12 of wood, 8 of copper 
   find the minimum number of bins to satisfy it.   

  *** This model cannot be run with a Community Licence 
      for the provided data instance ***

   (c) 2018 Artelys S.A. and Fair Isaac Corporation
       Creation: Dec. 2018
*****************************************************************!)
model "table_constraint example"
 uses "kalis"
 
 parameters
  N = 30           ! Max number of bins
  MAX_TIME = 15    ! Max time allowed to solver 
 end-parameters

 setparam("KALIS_MAX_COMPUTATION_TIME",MAX_TIME)

 forward procedure print_sol

 declarations 
   ! *** Data ***
   MATERIAL = 1..5 ! Corresponds to ["Glass","Plastic","Steel","Wood","Copper"] 
   INITIAL_SUPPLY : array(MATERIAL) of integer
   BINTYPE = 0..3  ! Corresponds to ["Unassigned", "Red", "Blue", "Green"]
   BINS = 1..N                                ! Set of bins
   CAPACITY : array(BINTYPE) of integer       ! Capacity per type
   WEIGHT : array(BINTYPE) of integer         ! Weights for bin type selection
   
   ! *** Decision variables ***
   var_bin : array(BINS) of cpvar             ! Bin usage
   var_type : array(BINS) of cpvar            ! Bin type
   var_capa : array(BINS) of cpvar            ! Bin capacity
   var_qty_material : array(BINS,MATERIAL) of cpvar ! Qty per material in bins
   objective : cpvar

   strategy : cpbranching                     ! Branching strategy
   
   ! Configuration of the table_constraint
   var_table : array(BINS) of cpvarlist       ! Assignment variables per bin
   list_valid_tuple : set of list of integer  ! Permissible tuples
 end-declarations
 
 ! Initialisation of the data arrays
 INITIAL_SUPPLY::(1..5)[12,10,8,12,8]
 CAPACITY::(0..3)[0,5,5,6]
 WEIGHT::(0..3)[0,1,1,1]
 
! Define the cpvar and their domains  
 forall(i in BINS) do 
   setname(var_bin(i), "use of bin (" + i + ")")
   setdomain(var_bin(i),0,1)
   
   setname(var_type(i), "type of bin (" + i + ")")
   setdomain(var_type(i),BINTYPE)
   
   setname(var_capa(i), "capacity of bin (" + i + ")")
   var_capa(i) = element(CAPACITY,var_type(i))
   forall(m in MATERIAL) do 
     setname(var_qty_material(i,m),  
       "Quantity of material (" + m + ") in bin (" + i + ")")
     setdomain(var_qty_material(i,m),0,max(c in BINTYPE) CAPACITY(c))
   end-do
 end-do
 
 ! Capacity constraint 
 forall(i in BINS) do 
   sum(m in MATERIAL) var_qty_material(i,m) <= var_capa(i)
   var_bin(i) = element(WEIGHT,var_type(i))
 end-do
 
 ! Satisfy of the supply constraint
 forall(m in MATERIAL) 
   sum(i in BINS) var_qty_material(i,m) = INITIAL_SUPPLY(m)

 ! Define a list of valid tuples 
 maxcap:= max(c in BINTYPE) CAPACITY(c)
 forall(type in BINTYPE, qmat_1,qmat_2,qmat_3,
        qmat_4,qmat_5 in 0..maxcap) do
   ! red can contain glass, cooper, wood and at most 1 wood component
   if type = 1 and 
      qmat_2 = 0 and qmat_3 = 0 and qmat_4 <= 1 then
     list_valid_tuple += {[type, qmat_1, qmat_2,qmat_3,qmat_4,qmat_5]}
   ! blue can contain glass, steel, cooper
   elif type = 2 and qmat_2 = 0 and qmat_4 = 0 then
     list_valid_tuple += {[type, qmat_1, qmat_2,qmat_3,qmat_4,qmat_5]}
   ! green can contain plastic, copper, wood and at most 2 wood components
   elif type = 3 and
        qmat_1 = 0 and qmat_3 = 0 and qmat_4 <= 2 then
     list_valid_tuple += {[type, qmat_1, qmat_2,qmat_3,qmat_4,qmat_5]}
   ! unassigned
   elif type = 0 and 
        qmat_1 = 0 and qmat_2 = 0 and qmat_3 = 0 and qmat_4 = 0 and qmat_5 = 0 then
      list_valid_tuple += {[type, qmat_1, qmat_2,qmat_3,qmat_4,qmat_5]}
   end-if
  
   ! wood requires plastic; 
   if qmat_4 >= 1 and qmat_2 >= 1 then
     list_valid_tuple += {[type, qmat_1, qmat_2,qmat_3,qmat_4,qmat_5]}
   end-if
  
   ! glass exclusive with copper; 
   if qmat_1 = 0 or qmat_5 = 0 then
     list_valid_tuple += {[type, qmat_1, qmat_2,qmat_3,qmat_4,qmat_5]}
   end-if
   ! copper excludes plastic.
   if qmat_5 = 0 or qmat_2 = 0 then
     list_valid_tuple += {[type, qmat_1, qmat_2,qmat_3,qmat_4,qmat_5]}
   end-if
 end-do

 ! Definition of table constraint
 forall(i in BINS) do 
  var_table(i) += var_type(i) 
  forall(m in MATERIAL) var_table(i) += var_qty_material(i,m);
  table_constraint(var_table(i), list_valid_tuple)
 end-do

! Define the objective
 setname(objective,"total number of bins")
 setdomain(objective,0,N)
 objective = sum(i in BINS) var_bin(i)

! Propagate the constraints
 if not cp_propagate then
   writeln("Problem is infeasible")
   exit(1)
 end-if

! Define a branching strategy
 strategy := assign_var(KALIS_MAX_DEGREE,KALIS_MAX_TO_MIN)
 cp_set_branching(strategy)

! And solve the problem
 if not cp_minimize(objective) then
   writeln("Problem is infeasible")
   exit(1)
 end-if

! Display solution and solver stats
 print_sol
 cp_show_stats

! **** Solution display ****
 procedure print_sol
   forall(i in BINS | getsol(var_type(i)) > 0) do
      writeln("Bin ",i, " chosen : type=", getsol(var_type(i)), 
        "; capa=", getsol(var_capa(i)),
        "; Glass=", getsol(var_qty_material(i,1)),
        "; Plastic=", getsol(var_qty_material(i,2)),
        "; Steel=", getsol(var_qty_material(i,3)),
        "; Wood=", getsol(var_qty_material(i,4)),
        "; Copper=", getsol(var_qty_material(i,5)))
   end-do
 end-procedure

end-model


© 2001-2025 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.