/********************************************************
  Xpress-BCL Java Example Problems
  ================================

  file xbcontr1.java
  ``````````````````
  Contract allocation example.
  Combining BCL problem input with problem solving
  in Xpress-Optimizer.

  (c) 2008-2023 Fair Isaac Corporation
      author: S.Heipcke, 2005, rev. Dec. 2011
********************************************************/

import java.io.*;
import com.dashoptimization.*;

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 {
        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 */

        try (XPRBprob p = new XPRBprob("Contract1"); /* Initialize BCL and create a new problem in BCL */
             XPRS xprs = new XPRS()) {               /* 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****/
            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();
                }

        }
    }
}

