// If the solution space is very large, this method will not return. // The most likely result is that it will exceed memory capacity // and then fail. As a result, we shouldn't use this method in // any production optimization. public IEnumerable <ProductionTarget> GetFeasibleTargets(double claySupply, double glazeSupply) { List <ProductionTarget> targets = new List <ProductionTarget>(); // Setup the Gurobi environment & Model GRBEnv env = new GRBEnv(); GRBModel model = new GRBModel(env); // Setup the decision variables GRBVar xS = CreateSmallVasesVariable(claySupply, model); GRBVar xL = CreateLargeVasesVariable(glazeSupply, model); model.Update(); // Create Constraints CreateConstraints(model, xS, xL, claySupply, glazeSupply); // Find the greatest number of small vases we can make var maxSmall = System.Math.Min(claySupply, glazeSupply); // Find the greatest number of large vases we can make var maxLarge = System.Math.Min(claySupply / 4.0, glazeSupply / 2.0); // Find all feasible combinations of small and large vases // Note: There are probably several better ways of doing this // that are more efficient and organic. For example, we could make // a tree that represents all of the possible decisions and let the // optimizer find the solutions from within that tree. var results = new List <ProductionTarget>(); for (int nSmall = 0; nSmall <= maxSmall; nSmall++) { for (int nLarge = 0; nLarge <= maxLarge; nLarge++) { // Force the solution to the target set of values var c1 = model.AddConstr(xS == nSmall, $"xS_Equals_{nSmall}"); var c2 = model.AddConstr(xL == nLarge, $"xL_Equals_{nLarge}"); model.Update(); // See if the solution is feasible with those values model.Optimize(); if (model.IsFeasible()) { results.Add(new ProductionTarget() { Small = nSmall, Large = nLarge }); } model.Remove(c1); model.Remove(c2); model.Update(); } } return(results); }