/********************************************************
  Xpress-BCL Java Example Problems
  ================================

  file xbexpl2.java
  `````````````````
  Transportation model demonstrating use of index sets.

  (c) 2008 Fair Isaac Corporation
      author: S.Heipcke, Jan. 2000, rev. Dec. 2011
********************************************************/

import java.io.*;
import com.dashoptimization.*;

public class xbexpl2
{
 static final int MaxSuppliers = 100; /* Max. number of suppliers */
 static final int MaxCustomers = 1000;/* Max. number of customers */
 static final int MaxArcs = 10000;    /* Max. number of non-zero cost values */
 static final String DEMANDFILE = System.getProperty("XPRBDATA") + 
   "/trans/ex2dem1.dat";  
                                /* Demand data file (comma-separated format) */
 static final String AVAILFILE = System.getProperty("XPRBDATA") + 
   "/trans/ex2avail.dat"; 
                                /* Supply data file (comma-separated format) */
 static final String COSTFILE = System.getProperty("XPRBDATA") + 
   "/trans/ex2cost.dat";   
                                /* Cost data file (comma-separated format) */

 static XPRBindexSet Suppliers; /* Set of suppliers */
 static XPRBindexSet Customers; /* Set of customers */
 static double[] AVAIL;         /* Availability of products */
 static double[] DEMAND;        /* Demand by customers */

 static class TData {
        int suppl;
        int custm;
        double value;
 };
 
 static TData[] COST = new TData[MaxArcs]; /* Cost per supplier-customer pair*/

 static int NSuppl=0, NCustom=0, NArc=0;   /* Actual numbers of suppliers,
                                              customers, and arcs */

 static XPRB bcl;
 static XPRBprob p;

/***********************************************************************/

 static void modTrans() throws IOException
 {
  XPRBexpr lobj, av[], de[];
  int s,c,a;
  XPRBvar[] x;
 
/****VARIABLES****/
  x = new XPRBvar[NArc];
  for(a=0; a<NArc; a++) x[a]=p.newVar("x");
     
/****OBJECTIVE****/ 
  lobj = new XPRBexpr();
  for(a=0; a<NArc; a++)
   lobj.add(x[a].mul(COST[a].value));
  p.setObj(lobj);                  /* Set objective function */ 

/****CONSTRAINTS****/
    /**** Create all constraints in a single loop ****/
                                   /* Initialize the linear expressions */
  av = new XPRBexpr[NSuppl];
  for(s=0; s<NSuppl; s++) av[s] = new XPRBexpr();
  de = new XPRBexpr[NCustom];
  for(c=0; c<NCustom; c++) de[c] = new XPRBexpr();

  for(a=0; a<NArc; a++)            /* Add terms to expressions one-by-one */
  {
   av[COST[a].suppl].add(x[a]);
   de[COST[a].custm].add(x[a]);
  }                                 
                                   /* Terminate the constraint definition */
  for(s=0; s<NSuppl; s++)  p.newCtr("Avail", av[s].lEql(AVAIL[s]) );
  for(c=0; c<NCustom; c++)  p.newCtr("Demand", de[c].gEql(DEMAND[c]) );

/****SOLVING + OUTPUT****/
  p.exportProb(XPRB.MPS,"trans");  /* Matrix generation & output to MPS file */

  p.lpOptimize("");                /* Solve the LP-problem */
  System.out.println("Objective: " + p.getObjVal());  /* Get objective value */

  for(a=0; a<NArc; a++)            /* Print out the solution values */
  if(x[a].getSol()>0)
   System.out.println(Suppliers.getIndexName(COST[a].suppl) + " (" +
     AVAIL[COST[a].suppl] + ") -> " + Customers.getIndexName(COST[a].custm)
      + " (" + DEMAND[COST[a].custm] + "): " + x[a].getSol());  
}

/***********************************************************************/

    /**** 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 data from files ****/
 static void readData() throws IOException
 {
  FileReader datafile=null;
  StreamTokenizer st;
  int i;
 
        /* Create supplier and customer index sets */
  Suppliers = p.newIndexSet("suppl", MaxSuppliers);
  Customers = p.newIndexSet("custom", MaxCustomers);
  AVAIL = new double[MaxSuppliers];
  DEMAND = new double[MaxCustomers];
  
        /* Read the demand data file */
  datafile = new FileReader(DEMANDFILE);
  st = initST(datafile);
  do
  {
   do
   { 
    st.nextToken();
   } while(st.ttype==st.TT_EOL);    /* Skip empty lines */
   if(st.ttype != st.TT_WORD) break; 
   i=Customers.addElement(st.sval);
   if(st.nextToken() != ',') break;
   if(st.nextToken() != st.TT_NUMBER) break;
   DEMAND[i] = st.nval;
  } while( st.nextToken() == st.TT_EOL );
  datafile.close();
  NCustom = Customers.getSize();

        /* Read the supply data file */
  datafile = new FileReader(AVAILFILE);
  st = initST(datafile);
  do
  {
   do
   { 
    st.nextToken();
   } while(st.ttype==st.TT_EOL);
   if(st.ttype != st.TT_WORD) break; 
   i=Suppliers.addElement(st.sval);
   if(st.nextToken() != ',') break;
   if(st.nextToken() != st.TT_NUMBER) break;
   AVAIL[i] = st.nval;
  } while( st.nextToken() == st.TT_EOL );
  datafile.close();
  NSuppl = Suppliers.getSize();

        /* Read the cost data file */
  NArc = 0;
  datafile = new FileReader(COSTFILE);
  st = initST(datafile);
  do                     /* Read the cost data file and fill the index sets */
  {
   do
   { 
    st.nextToken();
   } while(st.ttype==st.TT_EOL);    /* Skip empty lines */
   if(st.ttype != st.TT_WORD) break;
   COST[NArc]=new TData();   
   COST[NArc].suppl=Suppliers.getIndex(st.sval);
   if(COST[NArc].suppl<0) System.out.println("Supp(" + st.sval + ")");
   if(st.nextToken() != ',') break;
   if(st.nextToken() != st.TT_WORD) break;
   COST[NArc].custm=Customers.getIndex(st.sval);
   if(COST[NArc].custm<0) System.out.println("Cust(" + st.sval + ")");
   if(st.nextToken() != ',') break;
   if(st.nextToken() != st.TT_NUMBER) break;
   COST[NArc++].value = st.nval;
  } while( st.nextToken() == st.TT_EOL );
    datafile.close();

  System.out.println("C: " + NCustom + "  S: " + NSuppl + "  A: " + NArc);
 }

/***********************************************************************/

 public static void main(String[] args)
 {
  bcl = new XPRB();                /* Initialize BCL */
  p = bcl.newProb("Trans");        /* Create a new problem in BCL */ 
  try
  {
   readData();                     /* Data input from file */
   modTrans();                     /* Formulate and solve the problem */
  }
  catch(IOException e)
  {
   System.err.println(e.getMessage());
   System.exit(1);
  }

  p.finalize();                    /* Delete the problem */      
  p=null;
 }
} 
