/********************************************************
  Xpress-BCL Java Example Problems
  ================================

  file xbcontr2s.java
  ```````````````````
  Contract allocation example.
  Combining BCL problem input with problem solving 
  and callbacks in Xpress-Optimizer.
  -- Single MIP thread --
  
  (c) 2008 Fair Isaac Corporation
      author: S.Heipcke, 2005, rev. Dec. 2011
********************************************************/

import java.io.*;
import com.dashoptimization.*;

public class xbcontr2s
{
 static final int District = 6;   /* Number of districts */
 static final int Contract = 10;  /* Number of contracts */

/**** DATA ****/
 static final int[] OUTPUT = {50, 40, 10, 20, 70, 50};    
                                  /* Max. output per district */
 static final int[] COST   = {50, 20, 25, 30, 45, 40};    
                                  /* Cost per district */
 static final int[] VOLUME = {20, 10, 30, 15, 20, 30, 10, 50, 10, 20};  
                                  /* Volume of contracts */

 /***********************************************************************/

 static class IntSolCallback implements XPRSintSolListener
 {
  public void XPRSintSolEvent(XPRSprob oprob, Object data)
  {
   int num, d, c;
   XPRBprob bprob;   
   XPRBvar y;

   try {
    bprob = (XPRBprob)data;
    num = oprob.getIntAttrib(XPRS.MIPSOLS);  /* Get number of the solution */
    bprob.sync(XPRB.XPRS_SOL);               /* Update BCL solution values */
  
    System.out.println("Solution " + num + ": Objective value: " +
                       bprob.getObjVal());

    for(d=0;d<District;d++)
     for(c=0;c<Contract;c++)
     {
      y = bprob.getVarByName("q_d"+ (d+1) + "_c" + (c+1));
      if( (y.getColNum()>-1) && (y.getSol() != 0))
       System.out.println(y.getName() + ": " + y.getSol()); 
     }
   }
   catch(XPRSprobException e) {
    System.out.println("Error " + e.getCode() + ": " + e.getMessage());
   }
  }
 }
 
 /***********************************************************************/

 public static void main(String[] args) throws XPRSexception
 {
  int d, c, i, stat, ncol, len;
  double [] sol;
  double val;
  java.lang.String [] names;
  XPRB bcl;
  XPRBprob p;
  XPRSprob op;
  IntSolCallback cb;
  XPRBexpr l1,l2,lobj;
  XPRBvar[][] x;                  /* Variables indicating whether a project 
                                     is chosen */
  XPRBvar[][] y;                  /* Quantities allocated to contractors */

  bcl = new XPRB();               /* Initialize BCL */
  p = bcl.newProb("Contract2");   /* Create a new problem in BCL */
  XPRS.init();                    /* Initialize Xpress-Optimizer */
 
/**** VARIABLES ****/
  x = new XPRBvar[District][Contract];
  y = new XPRBvar[District][Contract];
  for(d=0;d<District;d++)
   for(c=0;c<Contract;c++)
   {
    x[d][c] = p.newVar("x_d"+ (d+1) +"_c" +(c+1), XPRB.BV);
    y[d][c] = p.newVar("q_d"+ (d+1) +"_c" +(c+1), XPRB.SC, 0, OUTPUT[d]);
    y[d][c].setLim(5);
   } 
 
/****OBJECTIVE****/
  lobj = new XPRBexpr();
  for(d=0;d<District;d++)
   for(c=0;c<Contract;c++)
    lobj.add(y[d][c].mul(COST[d]));   
     
  p.setObj(lobj);                  /* Set the objective function */
 
/**** CONSTRAINTS ****/
  for(c=0;c<Contract;c++)
  {
   l1 = new XPRBexpr();
   l2 = new XPRBexpr();  
   for(d=0;d<District;d++)
   {
    l1.add(y[d][c]);
    l2.add(x[d][c]);
   }
   p.newCtr("Size", l1.gEql(VOLUME[c]));  /* "Size": cover the req. volume */
   p.newCtr("Min", l2.gEql(2) );  /* "Min": at least 2 districts / contract */
  }
 
  for(d=0;d<District;d++)         /* Do not exceed max. output  */
  {
   l1 = new XPRBexpr();
   for(c=0;c<Contract;c++)
    l1.add(y[d][c]);
   p.newCtr("Output", l1.lEql(OUTPUT[d]) );
  } 
  
  for(d=0;d<District;d++)         /* If a contract is allocated to a district,
                                     then at least 1 unit is allocated to it */
   for(c=0;c<Contract;c++)
    p.newCtr("XY", x[d][c].lEql(y[d][c]) );

/****SOLVING + OUTPUT****/
     /* Desactivate parallel MIP (for synchronization of BCL and Optimizer) */
  p.getXPRSprob().setIntControl(XPRS.MIPTHREADS, 1);

  cb = new IntSolCallback();
  p.getXPRSprob().addIntSolListener(cb,p);
                                  /* Define an integer solution callback */
  p.mipOptimize("");              /* Solve the MIP problem */

/* Delete the problem */
  p.finalize();              
  p=null;

 }
} 
