/********************************************************
 * Xpress-BCL Java Example Problems
 * ================================
 *
 * file xbcontr1.java
 * ``````````````````
 * Contract allocation example.
 * Combining BCL problem input with problem solving
 * in Xpress-Optimizer.
 *
 * (c) 2008-2024 Fair Isaac Corporation
 * author: S.Heipcke, 2005, rev. Dec. 2011
 ********************************************************/

import com.dashoptimization.*;
import java.io.*;

public class xbcontr1 {
  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 XPRSexception, XPRSprobException {
    try (XPRBprob p =
            new XPRBprob("Contract1"); /* Initialize BCL and create a new problem in BCL */
        XPRBexprContext context =
            new XPRBexprContext(); /* Release XPRBexpr instances at end of block. */
        XPRS xprs = new XPRS()) {
        /* Initialize Xpress-Optimizer */
      int d, c, i, stat, ncol, len;
      double[] sol;
      double val;
      java.lang.String[] names;
      XPRSprob op;
      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.loadMat(); /* Load the matrix explicitly */
      op = p.getXPRSprob(); /* Retrieve the Optimizer problem */
      op.mipOptimize(""); /* Solve the MIP problem */

      stat = op.getIntAttrib(XPRS.MIPSTATUS);
      /* Get the global (MIP) status */
      if ((stat == XPRS.MIP_SOLUTION) || (stat == XPRS.MIP_OPTIMAL)) {
          /* Test whether an integer sol. was found */
        val = op.getDblAttrib(XPRS.MIPOBJVAL);
        System.out.println("Objective: " + val);

        ncol = op.getIntAttrib(XPRS.COLS);
        sol = new double[ncol];
        op.getMipSol(sol); /* Get the primal solution values */
        names = new java.lang.String[ncol];
        op.getNames(XPRS.NAMES_COLUMN, names, 0, ncol - 1); /* Get the variable names */

        for (i = 0; i < ncol; i++) /* Print out the solution */
          if (sol[i] != 0) System.out.print(names[i] + ": " + sol[i] + ", ");
        System.out.println();
      }
    }
  }
}
