Simplex Algorithm
|
11-16-2023, 11:42 AM
Post: #21
|
|||
|
|||
RE: Simplex Algorithm
simplex_le now have maximize default (d=∞), matched simplex_reduce.
simplex_le(a) ≡ simplex_le(a, ∞) Code: simplex_le(a) := (11-14-2023 11:48 AM)Albert Chan Wrote: 2x + 4y >= 22 > simplex_le([[2,3,4,6],[4,2,5,5],[22,20,40,0]]) \([\frac{320}{7},[0,\frac{10}{7},\frac{3}{7},0,0],\left(\begin{array}{cccccc} \frac{-6}{7} & 1 & 0 & \frac{5}{7} & \frac{-4}{7} & \frac{10}{7} \\ \frac{8}{7} & 0 & 1 & \frac{-2}{7} & \frac{3}{7} & \frac{3}{7} \\ \frac{46}{7} & 0 & 0 & \frac{20}{7} & \frac{40}{7} & \frac{320}{7} \end{array}\right) ]\) |
|||
11-16-2023, 07:15 PM
(This post was last modified: 11-17-2023 07:24 PM by Albert Chan.)
Post: #22
|
|||
|
|||
RE: Simplex Algorithm
ftneek Wrote:[minRatio] algorithm uses this pivoting rule. Selection is too restrictive. Especially since aij, bj can be anything. It is possible code never get a chance of making ratios --> POS return 0 In HP Prime, A[0] = A last element, outside valid pivot selection area. This is the reason canonicalForm() may get into trouble of divide by 0. Yes, it patched with check aij≠0, but still just a patch. With a correct minRatio, this should never happen! Why? Because of added slack/art variables, equation rows are independent. It is impossible to get variables row of all zeros, even after row operations. And, slack/art variables are initially setup with 1's, a positive number. If some other variables are negative, any pivoting will turn them positive. In other words, positive coefficient(s) are always available, for the picking. So, what should be the right algorithm for minRatio? I think maxRatio algorithm is perfect for this! (as in min(x) = -max(-x)) It really is doing maximum ratio, does not care for sign of ratios! Note: maxRatio is a piece of code inside complex2, not itself a function. Bonus: for valid setup, canonicalForm() will never get a divide-by-0. Conversely, divide-by-0 implied matrix was setup wrong, and should be stopped. Note: I just posted latest complex_le code, thus not added here. Code: #cas Update: 1. skip some canonicalForm() calculations, if we know it will just return itself. 2. unbound solution, return [-inf, [], m], to signal no minimum. |
|||
11-17-2023, 07:47 AM
Post: #23
|
|||
|
|||
RE: Simplex Algorithm
The changes you propose to canonicalForm causes test_simplex() to fail on my end. Looks like case 3 fails.
> simplex_test() ["[[-2,-4,1,0,0,-22],[-3,-2,0,1,0,-20],[-4,-5,0,0,1,-40],[6,5,0,0,0,0]] Error: Bad Argument Value"] Check by reverting to: Code: canonicalForm(M, BV):= {1,1,1,1,1,1} I am also using sum(abs(expected - result)) == 0 as you suggested. - neek |
|||
11-17-2023, 11:04 AM
Post: #24
|
|||
|
|||
RE: Simplex Algorithm
Hi, ftneek
Have you updated all changes? I had run your supplied tests before posting, all passed. BTW, your test_simplex() had a hidden character. > test_simplex() → {1,1,1,1,1,test_case_6} > test_case_6() → 1 Copy/paste 1st answer, I get {1,1,1,1,1,test?_case_6} |
|||
11-18-2023, 01:27 AM
Post: #25
|
|||
|
|||
RE: Simplex Algorithm
I suppose the issue was because I only tested the change to canonicalForm at the time, which I think also needed your change to use max ratio pivoting rule to work. Applying all changes your changes for sol, canonicalForm, and minRatio and extra skips to canonicalForm that I saw seem to work. The tests all passed and time(test_simplex()) on my virtual calculator seems to be ~.005s faster.
I will upload a new source file with the changes. For anyone wondering, simplex2() has been renamed to simplex_core(), but the arguments remain the same. The reason is it may be the starting point or core of other simplex algorithms. - neek |
|||
11-18-2023, 10:31 PM
(This post was last modified: 11-19-2023 02:39 AM by ftneek.)
Post: #26
|
|||
|
|||
RE: Simplex Algorithm
I uploaded a new source file. I added simplex_int() command, for integer programming problems. It should work for many examples with standard form input, but let me know if you encounter any that don't work. Also for simplicity I had to modify simplex_core() to return a 4th item, the list of basic variables. Not sure if there was a better option.
Example: min x1-x2 s.t 2x1+x2<=5 -4x1+4x2<=5 x1,x2>=0 and integral (integer) > simplex_int([[2,1,1,0,5],[-4,4,0,1,5],[1,-2,0,0,0]],{3,4},4,0,0,{1,2}) [-3,[1,2,1,1,0],[[1,0,0,0,1,-1/3,1],[0,1,0,0,1,0,2],[0,0,1,0,-3,2/3,1],[0,0,0,1,0,-4/3,1],[0,0,0,0,1,1/3,3]],{1,2,3,4}] Thus min=-3 at x1=1,x2=2 Here's one example that currently doesn't work. I think because some non cas commands are used so decimals might be introduced. Xcas > lpsolve(x1+x2,[1867*x1+1913*x2=3618894],assume=nonnegint,lp_verbose=true) > simplex_int([[1867,1913,1,3618894],[1,1,0,0],[0,0,1,0]],{3},3,1,0,{1,2}) ["No Solution",[],[[0,1,1,3618893/1913,-1410/1913],[1,0,-1913/1867,1/1867,1411/1867],[0,0,46/1867,−6756475144/3571571,-66773/3571571]]] Here's another example that doesn't work, maybe for the same reason. > simplex_int([[2,9,1,0,40],[11,-8,0,1,82],[-3,-13,0,0,0]],{3,4},4,0,0,{1,2}) "Error: Bad Argument Value" - neek |
|||
11-19-2023, 12:57 AM
(This post was last modified: 11-20-2023 11:21 PM by Albert Chan.)
Post: #27
|
|||
|
|||
RE: Simplex Algorithm
(11-11-2023 04:54 AM)ftneek Wrote: Note I think there is a bug with my wrapper simplex() method, sometimes the artificial variable counter is not updated. So far the bad effect is for some systems with artificial variables. But also note that simplex2() works as intended with the correct arguments. I need to determine a correct (and hopefully efficient) way to identify artificial variables without false positives, as that would have a bad effect for systems without artificial variables. It is confusing that artificial variable row is also a valid cost row. Ask simplex() wrapper to figure out from matrix alone is just asking for trouble. From what I read from simplex_core(), art variables must be next to col b, in a bunch. When we are done with art variables, ign=art; art=0, and it work with smaller matrix. We don't really need art variable row, only number of art variables, which already provided. Another improvement is a major speedup for problem with lots of constraints. M := canonicalForm(M, BV) update M by processing a whole list of pivots. But, each iteration only adjust 1 pivot. Instead of len(BV) pivots to process, all we need is one. Assuming pivots were good to begin with (col of 0's, only one 1's), no error checking is needed. It is just a 1 liner: pivot1(m,j,k) := pivot((m[j]:=m[j]/m[j][k]), j,k); An Introduction to Linear Programming and Game Theory 3rd Edition, example 3.6.1 Minimize, with 2 '=' constraint: > a:=[[1,-2,-3,-2,3],[1,-1,2,1,11],[2,-3,1,1,0]] > simplex_le(a, -2) \([14,[19,8,0,0],\left(\begin{array}{ccccc} 0 & 1 & 5 & 3 & 8 \\ 1 & 0 & 7 & 4 & 19 \\ 0 & 0 & 2 & 2 & -14 \end{array}\right) ]\) For conveniece, simplex_le(m, 0) just return m with identity matrix squeezed inside. > b := simplex_le(a, 0) \(\left(\begin{array}{ccccccc} 1 & -2 & -3 & -2 & 1 & 0 & 3 \\ 1 & -1 & 2 & 1 & 0 & 1 & 11 \\ 2 & -3 & 1 & 1 & 0 & 0 & 0 \end{array}\right) \) We use the identity matrix as artificial variables. No art row needed. Less typing, less errors! > simplex(b, 2) \([14,[19,8,0,0,0,0],\left(\begin{array}{ccccccc} 1 & 0 & 7 & 4 & -1 & 2 & 19 \\ 0 & 1 & 5 & 3 & -1 & 1 & 8 \\ 0 & 0 & 2 & 2 & -1 & -1 & -14 \end{array}\right) ]\) simplex(b,2) wrapper called simplex_core(b, [5,6], 6,2,0) simplex(b) ≡ simplex(b, 0) Without art variables, it acted the same as previous versions. > m := [[-2,-4,1,0,0,-22],[-3,-2,0,1,0,-20],[-4,-5,0,0,1,-40],[6,5,0,0,0,0]] > simplex(m) [320/7, [20/7,40/7,46/7,0,0], ...] Code: #cas Update: to detect matrix is has options, I had used dim(dim(a))<2 This assumed dim(plain number)=1, which might be change in the future. New test for detecting options: dim(dim(a)!=2 |
|||
11-19-2023, 07:05 AM
(This post was last modified: 11-19-2023 07:29 AM by ftneek.)
Post: #28
|
|||
|
|||
RE: Simplex Algorithm
I agree, with only 1 pivot changing each iteration we can save a lot of operations. But I think in the beginning it still needs to go over each pivot at least once, and then the rest of the time it can pivot as you suggest. The reason is because simplex_core accepts a system in canonical or standard form. If it is standard form, I think it needs the pivots. For example for ">=" constraints you can just add negative slack variables if you pivot on them and use dual simplex, which is equivalent to multiplying the constraint by -1 and adding slack variable. Artificial variables also require a pivot, as well as choosing non slack/artificial as initial bv.
I still need to look over the other changes to see how it could have an effect. I will just say I probably prefer artificial variables to be set up outside of simplex_core. It can't be done inside of simplex? Or if you make it another function, it would probably be useful in a program for converting from symbolic input to standard form. - neek |
|||
11-19-2023, 04:58 PM
Post: #29
|
|||
|
|||
RE: Simplex Algorithm
(11-19-2023 07:05 AM)ftneek Wrote: I agree, with only 1 pivot changing each iteration we can save a lot of operations. But I think in the beginning it still needs to go over each pivot at least once, and then the rest of the time it can pivot as you suggest. I am not convinced that -1 slack variable will cause problem. This was previous code, pivot only the art variables (assumed always 1's) Code: IF art THEN But, on the safe side, it now go over all pivots. Code: IF art THEN a:=append(a,art_row(v,art)) END Quote:I will just say I probably prefer artificial variables to be set up outside of simplex_core. If you prefer art row added from simplex() side, just move "IF art THEN ... END" there. I personally like core to take care of this details. It allow the same matrix to be used for both. simplex(m, [art=0]) ≡ simplex_core(m, pivots, variables, art, 0) If user doesn't like simplex picked pivots, just use the core with custom pivots. |
|||
11-19-2023, 08:02 PM
Post: #30
|
|||
|
|||
RE: Simplex Algorithm
For now let's be safe on the first pivots. Your changes had a noticeable speed improvement. Hard to tell when adding more tests, but timing only the first 6 seemed to be a lower number than what I remember. I uploaded a new source file with your changes, but I've moved the IF art THEN inside of simplex(). The tests errored when it was inside simplex_core. simplex_core assumes it doesn't need to set anything up. I think we should keep it that way, at least for now.
- neek |
|||
11-20-2023, 12:18 AM
Post: #31
|
|||
|
|||
RE: Simplex Algorithm
I just posted a new file with a fix for the simplex_int command.
> simplex_int([[2,9,1,0,40],[11,-8,0,1,82],[-3,-13,0,0,0]],[3,4],4,0,0,[1,2]) [-58,[2,4,0,92,90],...] max=58 Would you know why this returns no solution, but Xcas is able to solve this problem? Is it just not solvable by cutting plane algorithm? > simplex_int([[1867,1913,1,3618894],[1,1,0,0],[0,0,1,0]],[3],3,1,0,[1,2]) ["No Solution",[],...] Xcas > lpsolve(x1+x2,[1867*x1+1913*x2=3618894],assume=nonnegint,lp_verbose=true) -> 1916, x1=1009,x2=907 I don't think the issue is having only one constraint. For example test 10 has 1 constraint and was able to be solved by simplex_int(), but I haven't figured out the right command to get xcas to solve that problem yet. - neek |
|||
11-20-2023, 02:14 AM
Post: #32
|
|||
|
|||
RE: Simplex Algorithm
(11-20-2023 12:18 AM)ftneek Wrote: I just posted a new file with a fix for the simplex_int command. You beat me to it! I also have simplex_int() bug fixed (culprit is INSERT command), and made code more compact. Code: // first attempt of Gomory's plane cutting algorithm |
|||
11-20-2023, 09:02 AM
Post: #33
|
|||
|
|||
RE: Simplex Algorithm
There seems to be some issue with the code you suggested, at least on my end.
> test_simplex() ["Unable to eval test in loop : [0.333333333333,0.0,4.66666666667,0.0] Error: Bad Argument Value"] - neek |
|||
11-20-2023, 11:42 AM
Post: #34
|
|||
|
|||
RE: Simplex Algorithm
(11-20-2023 09:02 AM)ftneek Wrote: > test_simplex() HP Prime exact randomly turned float is an old bug, not fixed yet. It may be due to memory corruption, you may want to reset calculator. The error message is coming from test_case_7() siimplex_int() first simplex_core() call. > simplex_core([[3,-1,0,1,1],[1,-1,1,0,5],[2,5,0,0,0],[0,0,0,1,0]],{4,3},4,1,0) [2/3,[1/3,0,14/3,0],[[1,-1/3,0,1/3,1/3],[0,-2/3,1,-1/3,14/3],[0,17/3,0,-2/3,-2/3]],{1,3}] |
|||
11-20-2023, 03:34 PM
(This post was last modified: 11-20-2023 04:17 PM by Albert Chan.)
Post: #35
|
|||
|
|||
RE: Simplex Algorithm
Question about simplex_int(a,bv,v,art,ign,integers)
Code: // Step 3: solve with new constraint From documentation, v is the number of variables (true + slack + artificial) Since we keep addding slack variables to a, should (v+1) be more? However, v is only used for simplex_core sol(a,v), so I guess doc is wrong. It may meant to solve v leftmost variables. And, why the +1? What about simplex_int last argument, what is integers? How to setup problem with it? I thought variable v is redundant = matrix columns - 1 Now that I know better, I am replacing art_row(v,art) as artrow(col,art) If v=col-1, both matched. If not, using columns is safer. Below will be on my next update. >artrow(col,art):=append(makelist(k->k>col-art,2,col),0); >artrow(9,2) → [0,0,0,0,0,0,1,1,0] |
|||
11-20-2023, 06:12 PM
(This post was last modified: 11-21-2023 08:08 PM by Albert Chan.)
Post: #36
|
|||
|
|||
RE: Simplex Algorithm
(11-19-2023 04:58 PM)Albert Chan Wrote: I am not convinced that -1 slack variable will cause problem. I am now convinced that it will not cause problem, even if scaled. This is because minRatio and maxRatio calculated in completely opposite way. minRatio(a,b) skipped over a≤0, while maxRatio skipped over a≥0 As long as pivot is non-zero, we are safe, the mistaken pivot will be resolved. Anyway, we can always grab a +1 pivot, there is no reason to worry about -1 ≤ constraint: slack variable of 1 = constraint: art variable of 1 ≥ constraint: slack of -1, art of +1 I also noticed user cannot just grab any cell as pivot, it may produce wrong result. Thus, a wrapper is very important, disallowed randomly picking pivots. If we do want (i,j) as pivot, do a:=pivot1(a,i,j) before picking the next one. I am reverting back to the fast method, without (again) canonicalize all pivots. And, no need to fill artrow, even in simplex_core(), it handles this internally simplex(m, [art=0]) ≡ simplex_core(m, pivots, variables, art, 0) Code: IF art THEN /* add artrow */ With the same logic, simplex_int() now use simplex wrapper. test_case_7(), before and after. Less typing, less errors. < simplex_int([[3,-1,0,1,1],[1,-1,1,0,5],[2,5,0,0,0],[0,0,0,1,0]],{4,3},4,1,0,{1,2}) > simplex_int([[3,-1,0,1,1],[1,-1,1,0,5],[2,5,0,0,0]],1,{1,2}) Or course, the tests now need adjustments. I am including both code and tests. test_simplex() now run 20% faster. > test_simplex() → {1,1,1,1,1,1,1,1,1,1,1} Lets call this version 4 Code: #cas Code: #cas |
|||
11-20-2023, 07:52 PM
(This post was last modified: 11-20-2023 08:35 PM by ftneek.)
Post: #37
|
|||
|
|||
RE: Simplex Algorithm
(11-20-2023 03:34 PM)Albert Chan Wrote: Question about simplex_int(a,bv,v,art,ign,integers) Yes my mistake. Technically 'v' should increase every iteration, not just once. But the user may not care about these extra variable solutions, so for now it's probably not a big deal, but can be fixed. I think I meant to do something like ++v. But I think how the 'v' argument is handled may change in the future, probably when I figure out how to implement "unrestricted" variables (and/or symbolic input). simplex_core works with unrestricted variables, but again for now you have to put it in standard form yourself. Ex: x1 is unrestricted (<=0 or >=0) and integer -> x1=x1'-x1'' where x1',x1''>=0 and integer From user's perspective, the original system only has v variables. But once in standard form we've added columns for slack and artificial variables (and fixed unrestricted variables), so from simplex_core perspective we should have v=col-1. As you say, the only difference v has right now is the number of left most solutions to read. If we had unrestricted variables, the solution user expects != solve original v leftmost variables, we have to recover what the unrestricted variables are from the xi=xi'-xi'' relation. I gave an example a few comments ago, integers is a list of variables with integer restriction. For example x1,x2 integer -> integers:=[1,2] x2,x3 integer -> integers:=[2,3] x1,x3 integer -> integers:=[1,3] x3 integer -> integers:=[3] Last the point I wanted to make was that for >= constraint we do not actually need to add an artificial variable at all since we use dual simplex, we either multiply constraint by -1 and add slack or add negative slack, which is the same thing because you still have to multiply the row by -1 to make the column 'canonical'. Thus for ">=" constraint giving input of negative slack for initial bv is fine if we pivot on it or multiply the row by -1 as the 'pivot' operation. I will look at the rest of the changes a bit later. My main concern is that it could limit the number of ways the user can input a system and get to the same solution. simplex_core is flexible in how the constraints are ordered. - neek |
|||
11-21-2023, 08:36 AM
(This post was last modified: 11-21-2023 08:38 AM by ftneek.)
Post: #38
|
|||
|
|||
RE: Simplex Algorithm
(11-20-2023 06:12 PM)Albert Chan Wrote:(11-19-2023 04:58 PM)Albert Chan Wrote: I am not convinced that -1 slack variable will cause problem. I uploaded a new file with the infinite solution correction you mentioned. But I wasn't able to include this portion of code in simplex_core yet. Code: IF art THEN /* add artrow */ I added a new test 4. It is an example of input that is currently allowed by simplex_core, but the command didn't work when I tried your version, because the -1's are not being pivoted on. This what I mean by limiting the number of ways you can input a system and arrive at the same solution. Current simplex_core > simplex_core([[2,4,-1,0,0,22],[3,2,0,-1,0,20],[4,5,0,0,-1,40],[6,5,0,0,0,0]],{3,4,5},5,0,0) [320/7,[20/7,40/7,46/7,0,0],[[0,0,1,6/7,-8/7,46/7],[1,0,0,-5/7,2/7,20/7],[0,1,0,4/7,-3/7,40/7],[0,0,0,10/7,3/7,-320/7]],{3,1,2}] Your version > simplex_core([[2,4,-1,0,0,22],[3,2,0,-1,0,20],[4,5,0,0,-1,40],[6,5,0,0,0,0]],{3,4,5},5,0,0) [0,[0,0,0,0,0],[[2,4,-1,0,0,22],[3,2,0,-1,0,20],[4,5,0,0,-1,40],[6,5,0,0,0,0]],{3,4,5}] Also, appending an artificial row should not happen inside simplex_core, at least the current way you propose. Reminder, simplex_core is able to continue iteration on a tableau from any stage. For sensitivity analysis, we may consider what happens to the solution if we add a constraint. But just adding a row/bv to the original matrix and applying simplex algorithm again can be expensive for large systems. Instead, we insert the row into the final tableau and continue computation from there. This an example of where your current implementation is wrong, if you are going to set up the artificial row, it should be offset by ign. - neek |
|||
11-21-2023, 02:05 PM
(This post was last modified: 11-21-2023 05:03 PM by Albert Chan.)
Post: #39
|
|||
|
|||
RE: Simplex Algorithm
(11-21-2023 08:36 AM)ftneek Wrote: Reminder, simplex_core is able to continue iteration on a tableau from any stage. I don't know this requirement. Easy fix. '+' = added, '-' = subtracted simplex() Wrote:IF c > art-(n-=1) THEN continue END simplex_core() Wrote:- IF art THEN /* add artrow */ For efficiency sake, simplex_core assumed pivots are all 1's This is why my version 4 get 20% speedup running test_simplex(). We can add another wrapper to turn pivots to 1, say, call this simplex2 Code: simplex2(a,bv,v,art,ign):= ftneek Wrote:Current simplex_core > simplex2([[2,4,-1,0,0,22],[3,2,0,-1,0,20],[4,5,0,0,-1,40],[6,5,0,0,0,0]],{3,4,5},5,0,0) [320/7,[20/7,40/7,46/7,0,0],[[0,0,1,6/7,-8/7,46/7],[1,0,0,-5/7,2/7,20/7],[0,1,0,4/7,-3/7,40/7],[0,0,0,10/7,3/7,-320/7]],{3,1,2}] These make simplex_core() restartable at any stage. And, run very fast. BTW, is above tableau in standard form? Should all constraints be negated? |
|||
11-21-2023, 05:58 PM
Post: #40
|
|||
|
|||
RE: Simplex Algorithm
Minor cosmetic issue.
Instead of returning [min(c), vars, matrix, bv], it might be better do [min(c), matrix, bv, vars] The reason is the limited display of calculator. Yes, we can press SHOW, and scroll for answer, but it is too much trouble. The default , almost always, user see [min(c) ... bv] // literally, "..." With vars moved to the end, user see [min(c) ... vars] What do you think? |
|||
« Next Oldest | Next Newest »
|
User(s) browsing this thread: 7 Guest(s)