Hide navigation sidebar
Hide table of contents sidebar
Back to top
Toggle table of contents sidebar

# Multiscenario.java

    // Copyright 2025, Gurobi Optimization, LLC

    // Facility location: a company currently ships its product from 5 plants
    // to 4 warehouses. It is considering closing some plants to reduce
    // costs. What plant(s) should the company close, in order to minimize
    // transportation and fixed costs?
    //
    // Since the plant fixed costs and the warehouse demands are uncertain, a
    // scenario approach is chosen.
    //
    // Note that this example is similar to the Facility.java example. Here we
    // added scenarios in order to illustrate the multi-scenario feature.
    //
    // Based on an example from Frontline Systems:
    // http://www.solver.com/disfacility.htm
    // Used with permission.

    import com.gurobi.gurobi.*;

    public class Multiscenario {

      public static void main(String[] args) {
        try {

          // Warehouse demand in thousands of units
          double Demand[] = new double[] { 15, 18, 14, 20 };

          // Plant capacity in thousands of units
          double Capacity[] = new double[] { 20, 22, 17, 19, 18 };

          // Fixed costs for each plant
          double FixedCosts[] =
            new double[] { 12000, 15000, 17000, 13000, 16000 };

          // Transportation costs per thousand units
          double TransCosts[][] =
            new double[][] { { 4000, 2000, 3000, 2500, 4500 },
                             { 2500, 2600, 3400, 3000, 4000 },
                             { 1200, 1800, 2600, 4100, 3000 },
                             { 2200, 2600, 3100, 3700, 3200 } };

          // Number of plants and warehouses
          int nPlants = Capacity.length;
          int nWarehouses = Demand.length;

          double maxFixed = -GRB.INFINITY;
          double minFixed = GRB.INFINITY;
          for (int p = 0; p < nPlants; ++p) {
            if (FixedCosts[p] > maxFixed)
              maxFixed = FixedCosts[p];

            if (FixedCosts[p] < minFixed)
              minFixed = FixedCosts[p];
          }

          // Model
          GRBEnv env = new GRBEnv();
          GRBModel model = new GRBModel(env);
          model.set(GRB.StringAttr.ModelName, "multiscenario");

          // Plant open decision variables: open[p] == 1 if plant p is open.
          GRBVar[] open = new GRBVar[nPlants];
          for (int p = 0; p < nPlants; ++p) {
            open[p] = model.addVar(0, 1, FixedCosts[p], GRB.BINARY, "Open" + p);
          }

          // Transportation decision variables: how much to transport from
          // a plant p to a warehouse w
          GRBVar[][] transport = new GRBVar[nWarehouses][nPlants];
          for (int w = 0; w < nWarehouses; ++w) {
            for (int p = 0; p < nPlants; ++p) {
              transport[w][p] = model.addVar(0, GRB.INFINITY, TransCosts[w][p],
                                             GRB.CONTINUOUS, "Trans" + p + "." + w);
            }
          }

          // The objective is to minimize the total fixed and variable costs
          model.set(GRB.IntAttr.ModelSense, GRB.MINIMIZE);

          // Production constraints
          // Note that the right-hand limit sets the production to zero if
          // the plant is closed
          for (int p = 0; p < nPlants; ++p) {
            GRBLinExpr ptot = new GRBLinExpr();
            for (int w = 0; w < nWarehouses; ++w) {
              ptot.addTerm(1.0, transport[w][p]);
            }
            GRBLinExpr limit = new GRBLinExpr();
            limit.addTerm(Capacity[p], open[p]);
            model.addConstr(ptot, GRB.LESS_EQUAL, limit, "Capacity" + p);
          }

          // Demand constraints
          GRBConstr[] demandConstr = new GRBConstr[nWarehouses];
          for (int w = 0; w < nWarehouses; ++w) {
            GRBLinExpr dtot = new GRBLinExpr();
            for (int p = 0; p < nPlants; ++p) {
              dtot.addTerm(1.0, transport[w][p]);
            }
            demandConstr[w] = model.addConstr(dtot, GRB.EQUAL, Demand[w], "Demand" + w);
          }

          // We constructed the base model, now we add 7 scenarios
          //
          // Scenario 0: Represents the base model, hence, no manipulations.
          // Scenario 1: Manipulate the warehouses demands slightly (constraint right
          //             hand sides).
          // Scenario 2: Double the warehouses demands (constraint right hand sides).
          // Scenario 3: Manipulate the plant fixed costs (objective coefficients).
          // Scenario 4: Manipulate the warehouses demands and fixed costs.
          // Scenario 5: Force the plant with the largest fixed cost to stay open
          //             (variable bounds).
          // Scenario 6: Force the plant with the smallest fixed cost to be closed
          //             (variable bounds).

          model.set(GRB.IntAttr.NumScenarios, 7);

          // Scenario 0: Base model, hence, nothing to do except giving the
          //             scenario a name
          model.set(GRB.IntParam.ScenarioNumber, 0);
          model.set(GRB.StringAttr.ScenNName, "Base model");

          // Scenario 1: Increase the warehouse demands by 10%
          model.set(GRB.IntParam.ScenarioNumber, 1);
          model.set(GRB.StringAttr.ScenNName, "Increased warehouse demands");

          for (int w = 0; w < nWarehouses; w++) {
            demandConstr[w].set(GRB.DoubleAttr.ScenNRHS, Demand[w] * 1.1);
          }

          // Scenario 2: Double the warehouse demands
          model.set(GRB.IntParam.ScenarioNumber, 2);
          model.set(GRB.StringAttr.ScenNName, "Double the warehouse demands");

          for (int w = 0; w < nWarehouses; w++) {
            demandConstr[w].set(GRB.DoubleAttr.ScenNRHS, Demand[w] * 2.0);
          }

          // Scenario 3: Decrease the plant fixed costs by 5%
          model.set(GRB.IntParam.ScenarioNumber, 3);
          model.set(GRB.StringAttr.ScenNName, "Decreased plant fixed costs");

          for (int p = 0; p < nPlants; p++) {
            open[p].set(GRB.DoubleAttr.ScenNObj, FixedCosts[p] * 0.95);
          }

          // Scenario 4: Combine scenario 1 and scenario 3 */
          model.set(GRB.IntParam.ScenarioNumber, 4);
          model.set(GRB.StringAttr.ScenNName, "Increased warehouse demands and decreased plant fixed costs");

          for (int w = 0; w < nWarehouses; w++) {
            demandConstr[w].set(GRB.DoubleAttr.ScenNRHS, Demand[w] * 1.1);
          }
          for (int p = 0; p < nPlants; p++) {
            open[p].set(GRB.DoubleAttr.ScenNObj, FixedCosts[p] * 0.95);
          }

          // Scenario 5: Force the plant with the largest fixed cost to stay
          //             open
          model.set(GRB.IntParam.ScenarioNumber, 5);
          model.set(GRB.StringAttr.ScenNName, "Force plant with largest fixed cost to stay open");

          for (int p = 0; p < nPlants; p++) {
            if (FixedCosts[p] == maxFixed) {
              open[p].set(GRB.DoubleAttr.ScenNLB, 1.0);
              break;
            }
          }

          // Scenario 6: Force the plant with the smallest fixed cost to be
          //             closed
          model.set(GRB.IntParam.ScenarioNumber, 6);
          model.set(GRB.StringAttr.ScenNName, "Force plant with smallest fixed cost to be closed");

          for (int p = 0; p < nPlants; p++) {
            if (FixedCosts[p] == minFixed) {
              open[p].set(GRB.DoubleAttr.ScenNUB, 0.0);
              break;
            }
          }

          // Guess at the starting point: close the plant with the highest
          // fixed costs; open all others

          // First, open all plants
          for (int p = 0; p < nPlants; ++p) {
            open[p].set(GRB.DoubleAttr.Start, 1.0);
          }

          // Now close the plant with the highest fixed cost
          System.out.println("Initial guess:");
          for (int p = 0; p < nPlants; ++p) {
            if (FixedCosts[p] == maxFixed) {
              open[p].set(GRB.DoubleAttr.Start, 0.0);
              System.out.println("Closing plant " + p + "\n");
              break;
            }
          }

          // Use barrier to solve root relaxation
          model.set(GRB.IntParam.Method, GRB.METHOD_BARRIER);

          // Solve multi-scenario model
          model.optimize();

          int nScenarios = model.get(GRB.IntAttr.NumScenarios);

          // Print solution for each */
          for (int s = 0; s < nScenarios; s++) {
            int modelSense = GRB.MINIMIZE;

            // Set the scenario number to query the information for this scenario
            model.set(GRB.IntParam.ScenarioNumber, s);

            // collect result for the scenario
            double scenNObjBound = model.get(GRB.DoubleAttr.ScenNObjBound);
            double scenNObjVal = model.get(GRB.DoubleAttr.ScenNObjVal);

            System.out.println("\n\n------ Scenario " + s +
                               " (" +  model.get(GRB.StringAttr.ScenNName) + ")");

            // Check if we found a feasible solution for this scenario
            if (modelSense * scenNObjVal >= GRB.INFINITY)
              if (modelSense * scenNObjBound >= GRB.INFINITY)
                // Scenario was proven to be infeasible
                System.out.println("\nINFEASIBLE");
              else
                // We did not find any feasible solution - should not happen in
                // this case, because we did not set any limit (like a time
                // limit) on the optimization process
                System.out.println("\nNO SOLUTION");
            else {
              System.out.println("\nTOTAL COSTS: " + scenNObjVal);
              System.out.println("SOLUTION:");
              for (int p = 0; p < nPlants; p++) {
                double scenNX = open[p].get(GRB.DoubleAttr.ScenNX);

                if (scenNX > 0.5) {
                  System.out.println("Plant " + p + " open");
                  for (int w = 0; w < nWarehouses; w++) {
                    scenNX = transport[w][p].get(GRB.DoubleAttr.ScenNX);

                    if (scenNX > 0.0001)
                      System.out.println("  Transport " + scenNX +
                                         " units to warehouse " + w);
                  }
                } else
                  System.out.println("Plant " + p + " closed!");
              }
            }
          }

          // Print a summary table: for each scenario we add a single summary
          // line
          System.out.println("\n\nSummary: Closed plants depending on scenario\n");
          System.out.format("%8s | %17s %13s\n", "", "Plant", "|");

          System.out.format("%8s |", "Scenario");
          for (int p = 0; p < nPlants; p++)
            System.out.format(" %5d", p);
          System.out.format(" | %6s  %s\n", "Costs", "Name");

          for (int s = 0; s < nScenarios; s++) {
            int modelSense = GRB.MINIMIZE;

            // Set the scenario number to query the information for this scenario
            model.set(GRB.IntParam.ScenarioNumber, s);

            // Collect result for the scenario
            double scenNObjBound = model.get(GRB.DoubleAttr.ScenNObjBound);
            double scenNObjVal = model.get(GRB.DoubleAttr.ScenNObjVal);

            System.out.format("%-8d |", s);

            // Check if we found a feasible solution for this scenario
            if (modelSense * scenNObjVal >= GRB.INFINITY) {
              if (modelSense * scenNObjBound >= GRB.INFINITY)
                // Scenario was proven to be infeasible
                System.out.format(" %-30s| %6s  %s\n",
                                  "infeasible", "-", model.get(GRB.StringAttr.ScenNName));
              else
                // We did not find any feasible solution - should not happen in
                // this case, because we did not set any limit (like a time
                // limit) on the optimization process
                System.out.format(" %-30s| %6s  %s\n",
                                  "no solution found", "-", model.get(GRB.StringAttr.ScenNName));
            } else {
              for (int p = 0; p < nPlants; p++) {
                double scenNX = open[p].get(GRB.DoubleAttr.ScenNX);
                if (scenNX  > 0.5)
                  System.out.format("%6s", " ");
                else
                  System.out.format("%6s", "x");
              }

              System.out.format(" | %6g  %s\n", scenNObjVal, model.get(GRB.StringAttr.ScenNName));
            }
          }

          // Dispose of model and environment
          model.dispose();
          env.dispose();
        } catch (GRBException e) {
          System.out.println("Error code: " + e.getErrorCode() + ". " +
                             e.getMessage());
        }
      }
    }

Help and Feedback

Press `/` or click to search this documentation | Gurobi website | Gurobi community forum
Go to other Gurobi documentation | Gurobi download | Contact support