/********************************************************
  Xpress-BCL Java Example Problems
  ================================

  file xbdelvr.java
  `````````````````
  Transportation problem.

  (c) 2008 Fair Isaac Corporation
      author: S.Heipcke, Jan. 2000, rev. Mar. 2011
********************************************************/

import java.io.*;
import com.dashoptimization.*;

public class xbdelvr {
    static final int NSupp = 10;     /* Number of suppliers */
    static final int NCust = 7;      /* Number of customers */
    static final int MaxArcs = 100;  /* Max. num. of non-zero cost values */

    static final String VANFILE = System.getProperty("XPRBDATA") +
        "/delivery/ifvan.dat";
    static final String COSTFILE = System.getProperty("XPRBDATA") +
        "/delivery/cost.dat";

    /****DATA****/
    /* Supplier:                    London  Luton  B'ham Bristl  Derby Stckpt */
    static final double SUPPLY[] = {140.0, 600.0,  50.0,  10.0, 400.0, 200.0,
                                    /* Supplier: York  Derby Soton Scnthp */
                                    20.0, 90.0,  30.0,  12.0};
    /* Customer:                    London Livpol Doncst   York   Hull Manchr */
    static final double DEMAND[] = {123.3,  56.4,  17.1, 192.8, 310.0,  47.0,
                                    /* Customer:  Shffld */
                                    86.0};

    static double[][] COST;          /* Cost per supplier-customer pair */
    static double[][] IFVAN;         /* Non-zero if route uses vans instead
                                        of lorries */
    static final double VANCAP=40.0; /* Capacity on routes that use vans */

    /***********************************************************************/

    static void modDelivery() throws IOException {
        XPRBexpr lobj, lc;
        int s,c;
        XPRBvar[][] x;

        try (XPRBprob p = new XPRBprob("Delivery")) { /* Initialize BCL and create a new problem */

            /****VARIABLES****/
            x = new XPRBvar[NSupp][NCust];
            for(s=0;s<NSupp;s++)
                for(c=0; c<NCust; c++)
                    x[s][c] = p.newVar("x_s" + s);

            /****OBJECTIVE****/
            lobj = new XPRBexpr();
            for(s=0;s<NSupp;s++)            /* Objective: Minimize total cost */
                for(c=0; c<NCust; c++)
                    lobj.add(x[s][c].mul(COST[s][c]));
            p.setObj(lobj); /* Set objective function */

            /****CONSTRAINTS****/
            for(c=0; c<NCust; c++) {           /* Satisfy demand of each customer */
                lc = new XPRBexpr();
                for(s=0;s<NSupp;s++)  lc.add(x[s][c]);
                p.newCtr("Demand", lc.gEql(DEMAND[c]));
            }

            for(s=0;s<NSupp;s++) {             /* Keep within supply at each supplier*/
                lc = new XPRBexpr();
                for(c=0; c<NCust; c++)  lc.add(x[s][c]);
                p.newCtr("Supply", lc.lEql(SUPPLY[s]) );
            }

            /****BOUNDS****/
            for(s=0;s<NSupp;s++)
                for(c=0; c<NCust; c++)
                    if(IFVAN[s][c]!=0) x[s][c].setUB(VANCAP);

            /****SOLVING + OUTPUT****/
            p.exportProb(XPRB.MPS,"delivery");  /* Write out an MPS file */

            p.setSense(XPRB.MINIM);          /* Set objective sense to minimization */
            p.lpOptimize("");                /* Solve the LP-problem */
            System.out.println("Objective: " + p.getObjVal());  /* Get objective value */

            for(s=0;s<NSupp;s++)             /* Print out the solution values */
                for(c=0; c<NCust; c++)
                    System.out.print(x[s][c].getName() +":"+ x[s][c].getSol() +" ");
            System.out.println();
        }
    }

    /***********************************************************************/

    /**** Initialize the stream tokenizer ****/
    static StreamTokenizer initST(FileReader file) {
        StreamTokenizer st=null;

        st= new StreamTokenizer(file);   /* Initialize the stream tokenizer */
        st.commentChar('!');             /* Use the character '!' for comments */
        st.eolIsSignificant(true);       /* Return end-of-line character */
        st.ordinaryChar(',');            /* Use ',' as separator */
        st.parseNumbers();               /* Read numbers as numbers (not strings)*/
        return st;
    }

    /**** Read multi line data file ****/
    static void readMultiLineFile(String filename, double[][] data) throws IOException {
        FileReader datafile=null;
        StreamTokenizer st;
        int i=0, j=0;

        datafile = new FileReader(filename);
        st = initST(datafile);
        do {
            do {
                st.nextToken();
            } while(st.ttype==st.TT_EOL);    /* Skip empty lines */
            while(st.ttype == st.TT_NUMBER) {
                data[j][i++] = st.nval;
                if(st.nextToken() != ',') { j++; i=0; break;}
                st.nextToken();
            }
        } while( st.ttype == st.TT_EOL );
        datafile.close();
    }

    /**** Read data from files ****/
    static void readData() throws IOException {
        int s,c;

        COST = new double[NSupp][NCust];
        IFVAN = new double[NSupp][NCust];

        /* Initialize data tables to 0: in the van data file some entries that are
         * zero are simply left out (that is, the lines are incomplete) */
        for(s=0;s<NSupp;s++)
            for(c=0; c<NCust; c++) {
                COST[s][c] = 0;
                IFVAN[s][c] = 0;
            }
        /* Read the demand data file */
        readMultiLineFile(COSTFILE,COST);

        /* Read the van data file */
        readMultiLineFile(VANFILE,IFVAN);
    }

    /***********************************************************************/

    public static void main(String[] args) {
        try {
            readData();           /* Data input from file */
            modDelivery();        /* Problem formulation and solution */
        }
        catch(IOException e) {
            System.err.println(e.getMessage());
            System.exit(1);
        }
    }
}
