/********************************************************
  Xpress-BCL Java Example Problems
  ================================

  file xbdlvriis2iso.java
  ```````````````````````
  Transportation problem (infeasible data).
  Retrieving and printing IIS.
  - Using Optimizer functions to retrieve detailed
    IIS information including isolation rows/bounds -

  (c) 2008 Fair Isaac Corporation
      author: S.Heipcke, Jan. 2008, rev. Mar. 2011
********************************************************/

import java.io.*;
import java.util.*;
import java.text.DecimalFormat;
import com.dashoptimization.*;

public class xbdlvriis2iso
{
 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, 200.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[] = {1230.3, 560.4, 117.1, 592.8, 310.0, 1247.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 XPRB bcl;
 static XPRBprob p;
 static XPRSprob op;

 private static DecimalFormat form = new DecimalFormat ("####.0");

/***********************************************************************/

 static void modDelivery()
 {
  XPRBexpr lobj, lc;
  int s,c,i;
  XPRBvar[][] x;
  XPRBctr[] CSupply, CDemand;
  int numv, numc, numiis, ncol, nrow;
  IntHolder inumv, inumc, inumiis;
  int[] viis, ciis;
  double[] duals, rdcs, bnd, rhs;
  byte[] ctrtype, bndtype, isolationrows, isolationbnds;
  java.lang.String[] cnames, vnames;
  java.lang.String isotype[] = {"N/A", "No ", "Yes"};
 
  bcl = new XPRB();               /* Initialize BCL */
  p = bcl.newProb("Delivery");    /* Create a new problem in BCL */
  XPRS.init();                    /* Initialize Xpress-Optimizer */

/****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 + "_" + c);
     
/****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****/  
  CDemand = new XPRBctr[NCust];
  for(c=0; c<4; c++)              /* Satisfy demand of each customer */
  {
   lc = new XPRBexpr();
   for(s=0;s<5;s++)  lc.add(x[s][c]);
   CDemand[c] = p.newCtr("Demand", lc.gEql(DEMAND[c]));
  }
  for(c=4; c<NCust; c++)          /* Satisfy demand of each customer */
  {
   lc = new XPRBexpr();
   for(s=5;s<NSupp;s++)  lc.add(x[s][c]);
   CDemand[c] = p.newCtr("Demand", lc.gEql(DEMAND[c]));
  }
        
  CSupply = new XPRBctr[NSupp];
  for(s=0;s<5;s++)                /* Keep within supply at each supplier*/
  {
   lc = new XPRBexpr();
   for(c=0; c<4; c++)  lc.add(x[s][c]);
   CSupply[s] = p.newCtr("Supply", lc.lEql(SUPPLY[s]) );
  }          
  for(s=5;s<NSupp;s++)            /* Keep within supply at each supplier*/
  {
   lc = new XPRBexpr();
   for(c=4; c<NCust; c++)  lc.add(x[s][c]);
   CSupply[s] = 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.setSense(XPRB.MINIM);          /* Set objective sense to minimization */
  p.lpOptimize("");                /* Solve the LP-problem */

  System.out.println("LP status: " + p.getLPStat());
  if (p.getLPStat()==XPRB.LP_OPTIMAL)
   System.out.println("Objective: " + p.getObjVal()); /* Get objective value */
  else if (p.getLPStat()==XPRB.LP_INFEAS)
  {
   op = p.getXPRSprob();           /* Retrieve the Optimizer problem */

/**** Get all IIS ****/
   op.IISAll();                   /* Generate all IIS */
                                  /* Get the number of independent IIS  */
   numiis = op.getIntAttrib(XPRS.NUMIIS);
   System.out.println("Number of IIS: " + numiis); 


/**** Obtain variable and constraint names for later use in printout ****/
                                  /* Retrieve variable names */
   ncol=op.getIntAttrib(XPRS.ORIGINALCOLS);    
   vnames = new java.lang.String[ncol];
   op.getNames(2, vnames, 0, ncol-1);
                                  /* Retrieve constraint names */
   nrow=op.getIntAttrib(XPRS.ORIGINALROWS);    
   cnames = new java.lang.String[nrow];
   op.getNames(1, cnames, 0, nrow-1);


/**** Retrieve detailed IIS info (incl. isolations) ****/
   inumc = new IntHolder(); inumv = new IntHolder();
   for(s=1;s<=numiis;s++)
   { 
    op.getIISData(s, inumc, inumv, null, null, null, null,
                  null, null, null, null);
    op.IISIsolations(s);

    numv = inumv.value; numc = inumc.value;
    ciis = new int[numc];
    viis = new int[numv];
    duals = new double[numc];
    rdcs = new double[numv];
    ctrtype = new byte[numc];
    bndtype = new byte[numv];
    isolationrows = new byte[numc];
    isolationbnds = new byte[numv];

    op.getIISData(s, inumc, inumv, ciis, viis, ctrtype, bndtype,
                  duals, rdcs, isolationrows, isolationbnds);    
    System.out.println("IIS " + s + ":  " + numv + " variables, " +
                       numc + " constraints");
    System.out.println("  Name    Type   Sense   Bound   Dual values   In iso. ");
    if (numv>0)
    {                              /* Print all variables in the IIS */
     bnd = new double[1];
     for(i=0;i<numv;i++)
     {
      if (bndtype[i] == 'L') op.getLB(bnd, viis[i], viis[i]);
      else op.getUB(bnd, viis[i], viis[i]);
      System.out.print(vnames[viis[i]] + "   column    " + bndtype[i] + "     ");
      System.out.println(bnd[0] + "       " + rdcs[i] + "         " + isotype[1+(int)isolationbnds[i]] );
     } 
    } 
    if (numc>0)
    {                              /* Print all constraints in the IIS */
     rhs = new double[1];
     for(i=0;i<numc;i++) 
     {
      op.getRHS(rhs, ciis[i], ciis[i]);
      System.out.print(cnames[ciis[i]] + "   row     " + ctrtype[i] + "     ");
      System.out.println(form.format(rhs[0]) + "     " + form.format(duals[i]) + "         " + isotype[1+(int)isolationrows[i]]);
     } 
    } 
   }

  }
 }

/***********************************************************************/

    /**** 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 */
  }
  catch(IOException e)
  {
   System.err.println(e.getMessage());
   System.exit(1);
  }
  modDelivery();         /* Problem formulation and solution */
 }
} 
