FICO
FICO Xpress Optimization Examples Repository
FICO Optimization Community FICO Xpress Optimization Home
Back to examples browserPrevious exampleNext example

Els - An economic lot-sizing problem solved by cut-and-branch and branch-and-cut heuristics

Description
The version 'xbels' of this example shows how to implement cut-and-branch (= cut generation at the root node of the MIP search) and 'xbelsc' implements a branch-and-cut (= cut generation at the MIP search tree nodes) algorithm using the cut manager.


Source Files
By clicking on a file name, a preview is opened at the bottom of this page.
xbels.java[download]
xbelsc.java[download]





xbelsc.java

/********************************************************
 * Xpress-BCL Java Example Problems
 * ================================
 *
 * file xbelsc.java
 * ````````````````
 * Economic lot sizing, ELS, problem, solved by adding
 * (l,S)-inequalities) in a branch-and-cut heuristic
 * (using the cut manager).
 *
 * ELS considers production planning over a horizon
 * of T periods. In period t, t=1,...,T, there is a
 * given demand DEMAND[t] that must be satisfied by
 * production prod[t] in period t and by inventory
 * carried over from previous periods. There is a
 * set-up up cost SETUPCOST[t] associated with
 * production in period t. The unit production cost
 * in period t is PRODCOST[t]. There is no inventory
 * or stock-holding cost.
 *
 *** This model cannot be run with a Community Licence ***
 *
 * (c) 2008-2024 Fair Isaac Corporation
 * author: S.Heipcke, 2005, rev. Mar. 2011
 ********************************************************/

import com.dashoptimization.*;
import java.util.*;

public class xbelsc {
  static final double EPS = 1e-6;
  static final int T = 6; /* Number of time periods */

  /****DATA****/
  static final int[] DEMAND = {1, 3, 5, 3, 4, 2}; /* Demand per period */

  static final int[] SETUPCOST = {17, 16, 11, 6, 9, 6}; /* Setup cost / period */
  static final int[] PRODCOST = {5, 3, 2, 1, 3, 1}; /* Prod. cost / period */
  static int[][] D; /* Total demand in periods t1 - t2 */

  static XPRBvar[] prod; /* Production in period t */
  static XPRBvar[] setup; /* Setup in period t */

  static class myobj {
    XPRBprob prob;
    double tol;
  }
  ;

  /**************************************************************************/
  /*  Cut generation algorithm:                                             */
  /*    get the solution values                                             */
  /*    identify and set up violated constraints                            */
  /*    add cuts to the problem                                             */
  /**************************************************************************/
  static class CutMgrCallback implements XPRScutMgrListener {
    public int XPRScutMgrEvent(XPRSprob oprob, Object data) {
      int t, l;
      boolean res;
      int ncut; /* Counter for cuts */
      double[] solprod, solsetup; /* Solution values for var.s prod & setup */
      double ds;
      XPRBexpr le;
      ArrayList<XPRBcut> cutlist;
      XPRBcut[] cuts;
      myobj mo;

      mo = (myobj) data;

      ncut = 0;
      cutlist = new ArrayList<XPRBcut>();
      try {
        /* Get the solution values */
        mo.prob.beginCB(oprob);
        mo.prob.sync(XPRB.XPRS_SOL);

        solprod = new double[T];
        solsetup = new double[T];
        for (t = 0; t < T; t++) {
          solprod[t] = prod[t].getSol();
          solsetup[t] = setup[t].getSol();
        }

        /* Search for violated constraints: */
        for (l = 0; l < T; l++) {
          for (ds = 0.0, t = 0; t <= l; t++) {
            if (solprod[t] < D[t][l] * solsetup[t] + mo.tol) ds += solprod[t];
            else ds += D[t][l] * solsetup[t];
          }

          /* Add the violated inequality: the minimum of the actual production
             prod[t] and the maximum potential production D[t][l]*setup[t]
             in periods 0 to l must at least equal the total demand in periods
             0 to l.
             sum(t=1:l) min(prod[t], D[t][l]*setup[t]) >= D[0][l]
          */
          if (ds < D[0][l] - mo.tol) {
            le = new XPRBexpr();
            for (t = 0; t <= l; t++) {
              if (solprod[t] < D[t][l] * solsetup[t] + mo.tol) le.add(prod[t]);
              else le.add(setup[t].mul(D[t][l]));
            }
            cutlist.add(mo.prob.newCut(le.gEql(D[0][l])));
            ncut++;
          }
        }

        /* Add cuts to the problem */
        if (ncut > 0) {
          cuts = new XPRBcut[ncut];
          for (t = 0; t < ncut; t++) cuts[t] = (XPRBcut) cutlist.get(t);
          mo.prob.addCuts(cuts);
          System.out.println(
              "Cuts added: "
                  + ncut
                  + " (depth "
                  + oprob.getIntAttrib(XPRS.NODEDEPTH)
                  + ", node "
                  + oprob.getIntAttrib(XPRS.NODES)
                  + "), obj. "
                  + oprob.getDblAttrib(XPRS.LPOBJVAL));
        }
        mo.prob.endCB();
      } catch (XPRSprobException e) {
        System.out.println("Error  " + e.getCode() + ": " + e.getMessage());
      }
      return 0;
    }
  }

  /***********************************************************************/

  static void modEls(XPRBprob p) throws XPRSexception {
    int s, t, k;
    XPRBexpr cobj, le;

    D = new int[T][T];
    for (s = 0; s < T; s++) for (t = 0; t < T; t++) for (k = s; k <= t; k++) D[s][t] += DEMAND[k];

    /****VARIABLES****/
    prod = new XPRBvar[T];
    setup = new XPRBvar[T];
    for (t = 0; t < T; t++) {
      prod[t] = p.newVar("prod" + (t + 1));
      setup[t] = p.newVar("setup" + (t + 1), XPRB.BV);
    }

    /****OBJECTIVE****/
    cobj = new XPRBexpr();
    for (t = 0; t < T; t++) /* Minimize total cost */
      cobj.add(setup[t].mul(SETUPCOST[t]).add(prod[t].mul(PRODCOST[t])));
    p.setObj(cobj);

    /****CONSTRAINTS****/
    /* Production in period t must not exceed the total demand for the
    remaining periods; if there is production during t then there
    is a setup in t */
    for (t = 0; t < T; t++) p.newCtr("Production", prod[t].lEql(setup[t].mul(D[t][T - 1])));

    /* Production in periods 0 to t must satisfy the total demand
    during this period of time */
    for (t = 0; t < T; t++) {
      le = new XPRBexpr();
      for (s = 0; s <= t; s++) le.add(prod[s]);
      p.newCtr("Demand", le.gEql(D[0][t]));
    }
  }

  /***********************************************************************/
  static void treeCutGen(XPRBprob p) throws XPRSexception {
    XPRSprob oprob;
    myobj mo;
    CutMgrCallback cb;
    double feastol;
    int starttime, t;

    starttime = XPRB.getTime();

    oprob = p.getXPRSprob(); /* Get Optimizer problem */

    oprob.setIntControl(XPRS.LPLOG, 0);
    oprob.setIntControl(XPRS.MIPLOG, 3);

    oprob.setIntControl(XPRS.CUTSTRATEGY, 0); /* Disable automatic cuts */
    oprob.setIntControl(XPRS.PRESOLVE, 0); /* Switch presolve off */
    oprob.setIntControl(XPRS.EXTRAROWS, 5000); /* Reserve extra rows */

    feastol = oprob.getDblControl(XPRS.FEASTOL); /* Get zero tolerance */
    feastol *= 10;

    mo = new myobj();
    mo.prob = p;
    mo.tol = feastol;
    p.setCutMode(1);
    cb = new CutMgrCallback();
    oprob.addCutMgrListener(cb, mo);

    p.mipOptimize(""); /* Solve the MIP */
    System.out.println(
        "("
            + (XPRB.getTime() - starttime) / 1000.0
            + " sec) MIP status "
            + p.getMIPStat()
            + ", best solution: "
            + p.getObjVal());

    /* Print out the solution: */
    for (t = 0; t < T; t++)
      System.out.println(
          "Period "
              + (t + 1)
              + ": prod "
              + prod[t].getSol()
              + " (demand: "
              + DEMAND[t]
              + ", cost: "
              + PRODCOST[t]
              + "), setup "
              + setup[t].getSol()
              + " (cost: "
              + SETUPCOST[t]
              + ")");
  }

  /***********************************************************************/

  public static void main(String[] args) throws XPRSprobException, XPRSexception {
    try (XPRBprob p = new XPRBprob("Els"); /* Initialize BCL and create a new problem */
        XPRBexprContext context =
            new XPRBexprContext(); /* Release XPRBexpr instances at end of block. */
        XPRS xprs = new XPRS()) {
        /* Initialize Xpress-Optimizer */

      modEls(p); /* Model the problem */
      treeCutGen(p); /* Solve the problem */
    }
  }
}

Back to examples browserPrevious exampleNext example