/********************************************************
 * Xpress-BCL Java Example Problems
 * ================================
 *
 * file xbcontr.java
 * `````````````````
 * Contract allocation example.
 *
 * (c) 2008-2024 Fair Isaac Corporation
 * author: S.Heipcke, Jan. 2000, rev. Mar. 2011
 ********************************************************/

import com.dashoptimization.*;
import java.io.*;

public class xbcontr {
  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 */

  /***********************************************************************/

  public static void main(String[] args) throws IOException {
    try (XPRBprob p = new XPRBprob("Contract"); /* Initialize BCL create a new problem */
        XPRBexprContext context =
            new XPRBexprContext() /* Release XPRBexpr instances at end of block. */) {
      int d, c;
      XPRB bcl;
      XPRBexpr l1, l2, lobj;
      XPRBvar[][] x; /* Variables indicating whether a project
                                               is chosen */
      XPRBvar[][] y; /* Quantities allocated to contractors */

      /**** 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****/
      p.exportProb(XPRB.MPS, "Contract"); /* Output the matrix in MPS format */
      p.setSense(XPRB.MINIM); /* Choose the sense of the optimization */
      p.mipOptimize(""); /* Solve the MIP-problem */

      if ((p.getMIPStat() == XPRB.MIP_SOLUTION) || (p.getMIPStat() == XPRB.MIP_OPTIMAL)) {
          /* Test whether an integer sol. was found */
        System.out.println("Objective: " + p.getObjVal()); /* Get objective value */
        for (d = 0; d < District; d++) {
            /* Print the solution values */
          for (c = 0; c < Contract; c++)
            if (x[d][c].getSol() > 0.5)
              System.out.print(y[d][c].getName() + ":" + y[d][c].getSol() + ", ");
          System.out.println();
        }
      }
    }
  }
}
