private static void Pivot(CompactTableau ct, int k, int l) { double[][] t = ct.t; for (int i = 0; i <= ct.m; i++) { if (i == k) { continue; } for (int j = 0; j <= ct.n; j++) { if (j == l) { continue; } t[i][j] = (t[i][j] * t[k][l] - t[i][l] * t[k][j]) / t[k][l]; } } for (int i = 0; i <= ct.m; i++) { if (i != k) { t[i][l] = -t[i][l] / t[k][l]; } } for (int j = 0; j <= ct.n; j++) { if (j != l) { t[k][j] /= t[k][l]; } } t[k][l] = 1 / t[k][l]; // Change indices. int tmp = ct.ind[ct.n + k]; ct.ind[ct.n + k] = ct.ind[l]; ct.ind[l] = tmp; }
private static int ChooseRow(CompactTableau ct, int l) { int k = -1; double tkmin = double.MaxValue; double[][] t = ct.t; for (int i = 0; i < ct.m; i++) { if (t[i][l] > 0) { double tk = t[i][ct.n] / t[i][l]; if (tk < tkmin) { tkmin = tk; k = i; } } } return k; }
private static int ChooseRowBlandDual(CompactTableau ct) { for (int i = 0; i < ct.m; i++) { if (ct.t[i][ct.n] < 0) { return i; } } return -1; }
private static int ChooseColumnDual(CompactTableau ct, int k) { int l = -1; double tlmin = double.MaxValue; double[][] t = ct.t; for (int j = 0; j < ct.n; j++) { if (t[k][j] < 0) { double tl = t[ct.m][j] / t[k][j]; if (tl < tlmin) { tlmin = tl; l = j; } } } return l; }
// Use this if you like infinite loops. private static int ChooseColumnMax(CompactTableau ct) { int l = 0; double max = Double.MinValue; double tmj; for (int j = 0; j < ct.n; j++) { tmj = ct.t[ct.m][j]; if (tmj > 0 && tmj > max) { max = tmj; l = j; } } return l; }
public static void SolveDual(CompactTableau ct) { SolveDual(ct, null); }
public double[] simplex(CompactTableau ct) { Simplex.SolveFeasible(ct, notify); return ct.MakeSolution(); }
private string XNumber(CompactTableau ct, int j) { if (ct.hasU && ct.ind[j] == ct.ind.Length - 1) { return "u"; } return "x<sub>" + (ct.ind[j] + 1) + "</sub>"; }
public static void SolveFeasible(CompactTableau ct) { SolveFeasible(ct, null); }
private void PrintSimplexHeader(StringBuilder sb, CompactTableau ct) { sb.Append("<tr class='header'>"); for (int j = 0; j < ct.n; j++) { sb.AppendFormat("<td>" + XNumber(ct, j) + "</td>"); } sb.Append("<td class='rhs'>-1</td>"); sb.Append("<td> </td>"); sb.Append("</tr>"); }
private string PrintSimplexTableau(CompactTableau ct) { StringBuilder sb = new StringBuilder(); sb.Append("<table class='simplex-tableau'>"); PrintSimplexHeader(sb, ct); for (int i = 0; i < ct.m; i++) { sb.Append("<tr>"); for (int j = 0; j < ct.n; j++) { sb.AppendFormat("<td>{0:0.###}</td>", ct.t[i][j]); } sb.AppendFormat("<td class='rhs'>{0:0.###}</td>", ct.t[i][ct.n]); sb.AppendFormat("<td class='last'>= -{0}</td>", XNumber(ct, ct.n + i)); sb.Append("</tr>"); } PrintSimplexFooter(sb, ct); sb.Append("</table>"); return sb.ToString(); }
private void PrintSimplexFooter(StringBuilder sb, CompactTableau ct) { sb.Append("<tr class='footer'>"); for (int j = 0; j < ct.n; j++) { sb.AppendFormat("<td>{0:0.###}</td>", ct.t[ct.m][j]); } sb.AppendFormat("<td class='rhs'>{0:0.###}</td>", ct.t[ct.m][ct.n]); sb.Append("<td class='last'>= z</td>"); sb.Append("</tr>"); }
private string PrintDualTableau(CompactTableau ct) { StringBuilder sb = new StringBuilder(); sb.Append("<table class='simplex-dual-tableau'>"); for (int i = 0; i < ct.m; i++) { sb.Append("<tr>"); sb.AppendFormat("<td class='first'>y<sub>{0}</sub></td>", ct.ind[ct.n + i] + 1); for (int j = 0; j < ct.n; j++) { sb.AppendFormat("<td>{0:0.###}</td>", ct.t[i][j]); } sb.AppendFormat("<td class='last'>{0:0.###}</td>", ct.t[i][ct.n]); sb.Append("</tr>"); } sb.Append("<tr>"); sb.Append("<td class='vals first'>-1</td>"); for (int j = 0; j < ct.n; j++) { sb.AppendFormat("<td class='vals'>{0:0.###}</td>", ct.t[ct.m][j]); } sb.AppendFormat("<td class='vals last'>{0:0.###}</td>", ct.t[ct.m][ct.n]); sb.Append("</tr>"); sb.Append("<tr>"); sb.Append("<td class='first'> </td>"); for (int j = 0; j < ct.n; j++) { sb.AppendFormat("<td>= y<sub>{0}</sub></td>", ct.ind[j] + 1); } sb.AppendFormat("<td class='last'>= w</td>"); sb.Append("</tr>"); sb.Append("</table>"); return sb.ToString(); }
private string Print(CompactTableau ct) { return ct.dual ? PrintDualTableau(ct) : PrintSimplexTableau(ct); }
public static CompactTableau CreateDualTableau(SimplexProblem p, Action<string, object> notify) { if (notify != null) { notify("Problem:", p); } int m = p.A[0].Length; int n = p.A.Length; double[][] t = new double[m + 1][]; for (int i = 0; i < m; i++) { t[i] = new double[n + 1]; for (int j = 0; j < n; j++) { t[i][j] = p.A[j][i]; } t[i][n] = p.c[i]; } t[m] = new double[n + 1]; Array.Copy(p.b, t[m], n); int[] ind = new int[n + m]; for (int j = 0; j < n; j++) { ind[j] = m + j; } for (int i = 0; i < m; i++) { ind[n + i] = i; } CompactTableau ct = new CompactTableau(m, n, t, ind, false); ct.dual = true; if (notify != null) { notify("Created dual tableau:", ct); } return ct; }
public static void TransformToFeasible(CompactTableau ct, double[] c) { ct.n--; double[][] t = ct.t; int[] ind = ct.ind; int m = ct.m; int n = ct.n; int uIndex = ind.Length - 1; // Checking the position of the u in the columns. int uPos = -1; for (int i = 0; i <= n; i++) { if (ind[i] == uIndex) { uPos = i; break; } } if (uPos == -1) { throw new InfeasibleProblemException(); } // Removing the column. for (int i = 0; i < m; i++) { for (int j = uPos; j <= n; j++) { t[i][j] = t[i][j + 1]; } } // Removing the extra index. for (int j = uPos; j < uIndex; j++) { ind[j] = ind[j + 1]; } // Solving the new objective function. for (int j = 0; j < n; j++) { t[m][j] = (ind[j] < n) ? c[ind[j]] : 0; } t[m][n] = 0; for (int i = 0; i < m; i++) { if (ind[n + i] < n) { for (int j = 0; j <= n; j++) { t[m][j] -= c[ind[n + i]] * t[i][j]; } } } ct.hasU = false; }
public static void PivotInfeasibleTableau(CompactTableau ct) { int iMin = 0; double iValMin = ct.t[iMin][ct.n]; for (int i = 1; i < ct.m; i++) { if (ct.t[i][ct.n] < iValMin) { iValMin = ct.t[i][ct.n]; iMin = i; } } Pivot(ct, iMin, ct.n - 1); }
private static int ChooseColumnBland(CompactTableau ct) { for (int j = 0; j < ct.n; j++) { if (ct.t[ct.m][j] > 0) { return j; } } return -1; }
public static void SolveDual(CompactTableau ct, Action<string, object> notify) { int iter = 1; while (true) { int k = ChooseRowBlandDual(ct); if (k == -1) { break; // The optimal solution was found. } int l = ChooseColumnDual(ct, k); if (l == -1) { throw new UnboundedProblemException(); } Pivot(ct, k, l); if (notify != null) { notify("After iteration " + iter + ":", ct); } iter++; } }
public double[] simplexDual(CompactTableau ct) { Simplex.SolveDual(ct, notify); return ct.MakeDualSolution(); }