diff options
author | Alberto Ruiz <aruiz@um.es> | 2010-02-23 18:22:57 +0000 |
---|---|---|
committer | Alberto Ruiz <aruiz@um.es> | 2010-02-23 18:22:57 +0000 |
commit | e0605467b60f65478d0f5cc8f82ba14a99168f7b (patch) | |
tree | 876e81ae0ee77f4cd01f5729ab35902ec9980789 /packages/glpk/lib/Numeric/LinearProgramming.hs | |
parent | 5587a094afa3e24698cd38301c805e6ee5876c73 (diff) |
error checking for simplex
Diffstat (limited to 'packages/glpk/lib/Numeric/LinearProgramming.hs')
-rw-r--r-- | packages/glpk/lib/Numeric/LinearProgramming.hs | 98 |
1 files changed, 54 insertions, 44 deletions
diff --git a/packages/glpk/lib/Numeric/LinearProgramming.hs b/packages/glpk/lib/Numeric/LinearProgramming.hs index fff304f..a888214 100644 --- a/packages/glpk/lib/Numeric/LinearProgramming.hs +++ b/packages/glpk/lib/Numeric/LinearProgramming.hs | |||
@@ -10,13 +10,13 @@ Stability : provisional | |||
10 | 10 | ||
11 | This module provides an interface to the standard simplex algorithm. | 11 | This module provides an interface to the standard simplex algorithm. |
12 | 12 | ||
13 | For example, the following linear programming problem | 13 | For example, the following LP problem |
14 | 14 | ||
15 | @maximize 4 x_1 + 3 x_2 - 2 x_3 + 7 x_4 | 15 | @maximize 4 x_1 - 3 x_2 + 2 x_3 |
16 | subject to | 16 | subject to |
17 | 17 | ||
18 | x_1 + x_2 <= 10 | 18 | 2 x_1 + x_2 <= 10 |
19 | x_3 + x_4 <= 10 | 19 | x_3 + 5 x_4 <= 20 |
20 | 20 | ||
21 | and | 21 | and |
22 | 22 | ||
@@ -26,31 +26,33 @@ can be solved as follows: | |||
26 | 26 | ||
27 | @import Numeric.LinearProgramming | 27 | @import Numeric.LinearProgramming |
28 | 28 | ||
29 | prob = Maximize [4, 3, -2, 7] | 29 | prob = Maximize [4, -3, 2] |
30 | 30 | ||
31 | constr1 = Sparse [ [1\#1, 1\#2] :<: 10 | 31 | constr1 = Sparse [ [2#1, 1#2] :<: 10 |
32 | , [1\#3, 1\#4] :<: 10 | 32 | , [1#2, 5#3] :<: 20 |
33 | ] | 33 | ] |
34 | |||
35 | 34 | ||
36 | \> simplex prob constr1 [] | 35 | \> simplex prob constr1 [] |
37 | Optimal (110.0,[10.0,0.0,0.0,10.0])@ | 36 | Optimal (28.0,[5.0,0.0,4.0])@ |
38 | 37 | ||
39 | The coefficients of the constraint matrix can also be given in dense format: | 38 | The coefficients of the constraint matrix can also be given in dense format: |
40 | 39 | ||
41 | @constr2 = Dense [ [1,1,0,0] :<: 10 | 40 | @constr2 = Dense [ [2,1,0] :<: 10 |
42 | , [0,0,1,1] :<: 10 | 41 | , [0,1,5] :<: 20 |
43 | ]@ | 42 | ]@ |
44 | 43 | ||
45 | By default all variables are bounded as @x_i <= 0@, but this can be | 44 | By default all variables are bounded as @x_i >= 0@, but this can be |
46 | changed: | 45 | changed: |
47 | 46 | ||
48 | @\> simplex prob constr2 [2 :>: 1, 4 :&: (2,7)] | 47 | @\> simplex prob constr2 [ 2 :>: 1, 3 :&: (2,7)] |
49 | Optimal (88.0,[9.0,1.0,0.0,7.0]) | 48 | Optimal (22.6,[4.5,1.0,3.8]) |
50 | 49 | ||
51 | \> simplex prob constr2 [Free 3] | 50 | \> simplex prob constr2 [Free 2] |
52 | Unbounded@ | 51 | Unbounded@ |
53 | 52 | ||
53 | The given bound for a variable completely replaces the default, | ||
54 | so @0 <= x_i <= b@ must be explicitly given as @i :&: (0,b)@. | ||
55 | |||
54 | -} | 56 | -} |
55 | 57 | ||
56 | module Numeric.LinearProgramming( | 58 | module Numeric.LinearProgramming( |
@@ -94,7 +96,7 @@ data Solution = Undefined | |||
94 | | Optimal (Double, [Double]) | 96 | | Optimal (Double, [Double]) |
95 | | Unbounded | 97 | | Unbounded |
96 | deriving Show | 98 | deriving Show |
97 | 99 | ||
98 | data Constraints = Dense [ Bound [Double] ] | 100 | data Constraints = Dense [ Bound [Double] ] |
99 | | Sparse [ Bound [(Double,Int)] ] | 101 | | Sparse [ Bound [(Double,Int)] ] |
100 | 102 | ||
@@ -105,19 +107,25 @@ type Bounds = [Bound Int] | |||
105 | 107 | ||
106 | simplex :: Optimization -> Constraints -> Bounds -> Solution | 108 | simplex :: Optimization -> Constraints -> Bounds -> Solution |
107 | 109 | ||
110 | simplex opt (Dense []) bnds = simplex opt (Sparse [Free [0#1]]) bnds | ||
111 | simplex opt (Sparse []) bnds = simplex opt (Sparse [Free [0#1]]) bnds | ||
112 | |||
108 | simplex opt (Dense constr) bnds = extract sg sol where | 113 | simplex opt (Dense constr) bnds = extract sg sol where |
109 | sol = simplexDense (mkConstrD objfun constr) (mkBoundsD constr bnds) | 114 | sol = simplexDense (mkConstrD sz objfun constr) (mkBounds sz constr bnds) |
110 | (sg, objfun) = case opt of | 115 | (sz, sg, objfun) = adapt opt |
111 | Maximize x -> (1 ,x) | ||
112 | Minimize x -> (-1, (map negate x)) | ||
113 | 116 | ||
114 | simplex opt (Sparse constr) bnds = extract sg sol where | 117 | simplex opt (Sparse constr) bnds = extract sg sol where |
115 | sol = simplexSparse m n (mkConstrS objfun constr) (mkBoundsS constr bnds) | 118 | sol = simplexSparse m n (mkConstrS sz objfun constr) (mkBounds sz constr bnds) |
116 | n = length objfun | 119 | n = length objfun |
117 | m = length constr | 120 | m = length constr |
118 | (sg, objfun) = case opt of | 121 | (sz, sg, objfun) = adapt opt |
119 | Maximize x -> (1 ,x) | 122 | |
120 | Minimize x -> (-1, (map negate x)) | 123 | adapt :: Optimization -> (Int, Double, [Double]) |
124 | adapt opt = case opt of | ||
125 | Maximize x -> (size x, 1 ,x) | ||
126 | Minimize x -> (size x, -1, (map negate x)) | ||
127 | where size x | null x = error "simplex: objective function with zero variables" | ||
128 | | otherwise = length x | ||
121 | 129 | ||
122 | extract :: Double -> Vector Double -> Solution | 130 | extract :: Double -> Vector Double -> Solution |
123 | extract sg sol = r where | 131 | extract sg sol = r where |
@@ -168,31 +176,33 @@ mkBound1 b = [tb b, lb b, ub b] | |||
168 | mkBound2 :: Bound t -> (t, [Double]) | 176 | mkBound2 :: Bound t -> (t, [Double]) |
169 | mkBound2 b = (obj b, mkBound1 b) | 177 | mkBound2 b = (obj b, mkBound1 b) |
170 | 178 | ||
171 | mkBoundsD :: [Bound [a]] -> [Bound Int] -> Matrix Double | 179 | mkBounds :: Int -> [Bound [a]] -> [Bound Int] -> Matrix Double |
172 | mkBoundsD b1 b2 = fromLists (cb++vb) where | 180 | mkBounds n b1 b2 = fromLists (cb++vb) where |
173 | c = length (obj (head b1)) | ||
174 | gv = map obj b2 | 181 | gv = map obj b2 |
175 | rv = [1..c] \\ gv | 182 | rv | null gv || minimum gv >= 0 && maximum gv <= n = [1..n] \\ gv |
183 | | otherwise = error $ "simplex: bounds: variables "++show gv++" not in 1.."++show n | ||
176 | vb = map snd $ sortBy (compare `on` fst) $ map (mkBound2 . (:>: 0)) rv ++ map mkBound2 b2 | 184 | vb = map snd $ sortBy (compare `on` fst) $ map (mkBound2 . (:>: 0)) rv ++ map mkBound2 b2 |
177 | cb = map mkBound1 b1 | 185 | cb = map mkBound1 b1 |
178 | 186 | ||
179 | mkConstrD :: [Double] -> [Bound [Double]] -> Matrix Double | 187 | mkConstrD :: Int -> [Double] -> [Bound [Double]] -> Matrix Double |
180 | mkConstrD f b1 = fromLists (f : map obj b1) | 188 | mkConstrD n f b1 | ok = fromLists (f : cs) |
181 | 189 | | otherwise = error $ "simplex: dense constraints require "++show n | |
182 | mkBoundsS :: [Bound [(Double, Int)]] -> [Bound Int] -> Matrix Double | 190 | ++" variables, given " ++ show ls |
183 | mkBoundsS b1 b2 = fromLists (cb++vb) where | 191 | where |
184 | c = maximum $ map snd $ concatMap obj b1 | 192 | cs | null b1 = error $ "simplex: dense: empty constraints" |
185 | gv = map obj b2 | 193 | | otherwise = map obj b1 |
186 | rv = [1..c] \\ gv | 194 | ls = map length cs |
187 | vb = map snd $ sortBy (compare `on` fst) $ map (mkBound2 . (:>: 0)) rv ++ map mkBound2 b2 | 195 | ok = all (==n) ls |
188 | cb = map mkBound1 b1 | 196 | |
189 | 197 | mkConstrS :: Int -> [Double] -> [Bound [(Double, Int)]] -> Matrix Double | |
190 | mkConstrS :: [Double] -> [Bound [(Double, Int)]] -> Matrix Double | 198 | mkConstrS n objfun b1 = fromLists (ob ++ co) where |
191 | mkConstrS objfun constr = fromLists (ob ++ co) where | ||
192 | ob = map (([0,0]++).return) objfun | 199 | ob = map (([0,0]++).return) objfun |
193 | co = concat $ zipWith f [1::Int ..] (map obj constr) | 200 | co = concat $ zipWith f [1::Int ..] cs |
201 | cs | null b1 = error $ "simplex: sparse: empty constraints" | ||
202 | | otherwise = map obj b1 | ||
194 | f k = map (g k) | 203 | f k = map (g k) |
195 | g k (c,v) = [fromIntegral k, fromIntegral v,c] | 204 | g k (c,v) | v >=1 && v<= n = [fromIntegral k, fromIntegral v,c] |
205 | | otherwise = error $ "simplex: sparse constraints: variable "++show v++" not in 1.."++show n | ||
196 | 206 | ||
197 | ----------------------------------------------------- | 207 | ----------------------------------------------------- |
198 | 208 | ||
@@ -262,6 +272,6 @@ bounds = (6><3) | |||
262 | , glpLO,0,0 | 272 | , glpLO,0,0 |
263 | , glpLO,0,0 | 273 | , glpLO,0,0 |
264 | , glpLO,0,0 ] | 274 | , glpLO,0,0 ] |
265 | 275 | ||
266 | -} | 276 | -} |
267 | 277 | ||