/********************************************************
  Xpress-BCL Java Example Problems
  ================================

  file xbcontr.java
  `````````````````
  Contract allocation example.

  (c) 2008-2023 Fair Isaac Corporation
      author: S.Heipcke, Jan. 2000, rev. Mar. 2011
********************************************************/

import java.io.*;
import com.dashoptimization.*;

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 {
        int d,c;
        XPRB bcl;
        XPRBexpr l1,l2,lobj;
        XPRBvar[][] x;                  /* Variables indicating whether a project
                                           is chosen */
        XPRBvar[][] y;                  /* Quantities allocated to contractors */

        try (XPRBprob p = new XPRBprob("Contract")) { /* Initialize BCL create a new problem */

            /**** 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)
                                System.out.print(y[d][c].getName() + ":" + y[d][c].getSol() + ", ");
                        System.out.println();
                    }
                }
        }
    }
}

