/** * This func generate all possible pattern to be fit in one stock len (or remain stock len) * from the @param{curOrderIndex} to end of orderSets */ public static List <List <BarSet> > calPossibleCutsFor1Stock(int curOrderIndex, List <BarSet> orderSets, double stockLen) { List <List <BarSet> > possiblePatterns = new List <List <BarSet> >(); bool canCut = checkCanCut(orderSets, stockLen); if (!canCut) { // Create array to let father func put bar in possiblePatterns.Add(new List <BarSet>()); return(possiblePatterns); } if (curOrderIndex == orderSets.Count) { return(possiblePatterns); } BarSet curOrderSet = orderSets[curOrderIndex]; int maxBarNum = minInt((int)(stockLen / curOrderSet.len), curOrderSet.num); for (int nBar = 0; nBar <= maxBarNum; nBar++) { // Clone current order except the one at current index List <BarSet> remainOrderSets = new List <BarSet>(); remainOrderSets.AddRange(orderSets); remainOrderSets[curOrderIndex] = new BarSet(curOrderSet.len, curOrderSet.num - nBar); List <List <BarSet> > subPatterns = calPossibleCutsFor1Stock( curOrderIndex + 1, remainOrderSets, stockLen - curOrderSet.len * nBar); int barNum = nBar; foreach (List <BarSet> pttrn in subPatterns) { pttrn.Insert(0, new BarSet(curOrderSet.len, barNum)); } possiblePatterns.AddRange(subPatterns); } return(possiblePatterns); }
/** * Solve most of pattern by linear programming * @returns 1st value is optimized pattern, 2nd value is the remain orders that haven't been solved */ public static Pair <Dictionary <List <BarSet>, int>, List <BarSet> > solveByLinearProgramming(List <BarSet> orderSets, double stockLen) { int nOrder = orderSets.Count; // Convert to Lp solve-friendly format: [arrayLen, x1, x2, 3...] double[] odLenVec = new double[nOrder + 1]; // order length vector double[] odNumVec = new double[nOrder + 1]; // order number vector odLenVec[0] = nOrder; odNumVec[0] = nOrder; for (int i = 0; i < nOrder; i++) { BarSet barSet = orderSets[i]; odLenVec[i + 1] = barSet.len; odNumVec[i + 1] = barSet.num; } double[][] patternMat = genPatternMatrix(odLenVec, odNumVec, stockLen); double[] minPatternNums = new double[nOrder]; // Lpsolve.Init("."); int iter; for (iter = 0; iter < MAX_ITER; iter++) { ; // Solve Linear Programming problem double[][] lpRst = calLP(patternMat, odNumVec); int solFlag = (int)lpRst[0][0]; if (solFlag != (int)Lpsolve.lpsolve_return.OPTIMAL) { Console.WriteLine("Can't solve anymore"); break; } minPatternNums = lpRst[1]; double[] dualCostVector = lpRst[2]; // Solve Knapsack problem double[][] ksRst = calKnapsack(dualCostVector, odLenVec, stockLen); double reducedCost = ksRst[0][0]; double[] newPattern = ksRst[1]; // TODO: use native optimized variable instead if (reducedCost <= 1.000000000001) { // epsilon threshold due to double value error Console.WriteLine("Optimized"); break; } // Cal leaving column int[] lcRst = calLeavingColumn(patternMat, newPattern, minPatternNums); int lcSolFlag = lcRst[0]; int leavingColIndex = lcRst[1]; // Console.WriteLine("Leaving column index: {0}", leavingColIndex); if (lcSolFlag != (int)Lpsolve.lpsolve_return.OPTIMAL) { Console.WriteLine("Can't solve anymore"); break; } // Save new pattern for (int r = 0; r < patternMat.Length; r++) { patternMat[r][leavingColIndex] = newPattern[r]; } } if (iter == MAX_ITER) { Console.WriteLine("Maximum of iter reached! Solution is not quite optimized"); } // ------------ Round up to keep integer part of result ---------------- double[] remainOdNumVec = new double[odNumVec.Length]; odNumVec.CopyTo(remainOdNumVec, 0); for (int r = 0; r < patternMat.Length; r++) { double[] row = patternMat[r]; for (int c = 1; c < row.Length; c++) { remainOdNumVec[r + 1] -= row[c] * Math.Floor(minPatternNums[c]); } } // Console.WriteLine("Leftovers: {0}", string.Join(", ", remainOdNumVec)); // Optimized for the rest of pattern by BruteForce List <BarSet> remainOrderSets = new List <BarSet>(); for (int r = 1; r < remainOdNumVec.Length; r++) { if (remainOdNumVec[r] > 0) { remainOrderSets.Add(new BarSet(odLenVec[r], (int)remainOdNumVec[r])); } } // Prepare result Dictionary <List <BarSet>, int> rstMap = new Dictionary <List <BarSet>, int>(); for (int c = 1; c < nOrder + 1; c++) { // column if ((int)minPatternNums[c] == 0) { // if number of this pattern is zero, skip continue; } List <BarSet> pattern = new List <BarSet>(); for (int r = 0; r < nOrder; r++) { // row if (patternMat[r][c] > 0d) { pattern.Add(new BarSet(odLenVec[r + 1], (int)patternMat[r][c])); } } rstMap.Add(pattern, (int)minPatternNums[c]); } return(new Pair <Dictionary <List <BarSet>, int>, List <BarSet> >(rstMap, remainOrderSets)); }