summaryrefslogtreecommitdiff
path: root/packages/glpk
diff options
context:
space:
mode:
authorAlberto Ruiz <aruiz@um.es>2010-02-21 18:26:23 +0000
committerAlberto Ruiz <aruiz@um.es>2010-02-21 18:26:23 +0000
commitf38b4a3076cfae023559ce61cb2a443c809b7a6f (patch)
tree022c127181fb65c34705cdcf44221b4ac89ba50b /packages/glpk
parenta3d1bb34ae7b1f97b7e9900fc38f145094fe4777 (diff)
simple glpk interface
Diffstat (limited to 'packages/glpk')
-rw-r--r--packages/glpk/LICENSE2
-rw-r--r--packages/glpk/Setup.lhs4
-rw-r--r--packages/glpk/examples/simplex1.hs21
-rw-r--r--packages/glpk/examples/simplex2.hs16
-rw-r--r--packages/glpk/examples/simplex3.hs24
-rw-r--r--packages/glpk/examples/simplex4.hs24
-rw-r--r--packages/glpk/glpk.cabal35
-rw-r--r--packages/glpk/lib/Numeric/LinearProgramming.hs211
-rw-r--r--packages/glpk/lib/Numeric/LinearProgramming/glpk.c147
9 files changed, 484 insertions, 0 deletions
diff --git a/packages/glpk/LICENSE b/packages/glpk/LICENSE
new file mode 100644
index 0000000..f2125ec
--- /dev/null
+++ b/packages/glpk/LICENSE
@@ -0,0 +1,2 @@
1Copyright Alberto Ruiz 2010
2GPL license
diff --git a/packages/glpk/Setup.lhs b/packages/glpk/Setup.lhs
new file mode 100644
index 0000000..6b32049
--- /dev/null
+++ b/packages/glpk/Setup.lhs
@@ -0,0 +1,4 @@
1#! /usr/bin/env runhaskell
2
3> import Distribution.Simple
4> main = defaultMain
diff --git a/packages/glpk/examples/simplex1.hs b/packages/glpk/examples/simplex1.hs
new file mode 100644
index 0000000..4609524
--- /dev/null
+++ b/packages/glpk/examples/simplex1.hs
@@ -0,0 +1,21 @@
1-- first example in glpk manual
2
3import Numeric.LinearProgramming
4
5objFun = Maximize [10, 6, 4]
6
7constr = Dense [ [1,1,1] :<: 100
8 , [10,4,5] :<: 600
9 , [2,2,6] :<: 300 ]
10
11-- default bounds
12bnds = [ 1 :>: 0
13 , 2 :>: 0
14 , 3 :>: 0 ]
15
16main = do
17 print $ simplex objFun constr []
18 print $ simplex objFun constr bnds
19 print $ simplex objFun constr [Free 3]
20 print $ simplex objFun constr [ 2 :<: 50 ]
21
diff --git a/packages/glpk/examples/simplex2.hs b/packages/glpk/examples/simplex2.hs
new file mode 100644
index 0000000..76a53df
--- /dev/null
+++ b/packages/glpk/examples/simplex2.hs
@@ -0,0 +1,16 @@
1import Numeric.LinearProgramming
2
3prob = Maximize [1,2,3,4]
4
5constr1 = Sparse [ [1#1, 1#2] :<: 10
6 , [1#3, 1#4] :<: 10
7 ]
8
9constr2 = Dense [ [1,1,0,0] :<: 10
10 , [0,0,1,1] :<: 10
11 ]
12
13main = do
14 print $ simplex prob constr1 []
15 print $ simplex prob constr2 []
16
diff --git a/packages/glpk/examples/simplex3.hs b/packages/glpk/examples/simplex3.hs
new file mode 100644
index 0000000..0f787cb
--- /dev/null
+++ b/packages/glpk/examples/simplex3.hs
@@ -0,0 +1,24 @@
1import Numeric.LinearProgramming
2
3-- $ glpsol --cpxlp /usr/share/doc/glpk-utils/examples/plan.lp -o result.txt
4
5prob = Minimize [0.03, 0.08, 0.17, 0.12, 0.15, 0.21, 0.38]
6
7constr = Dense
8 [ [1,1,1,1,1,1,1] :==: 2000
9 , [0.15, 0.04, 0.02, 0.04, 0.2,0.01, 0.03] :<: 60
10 , [0.03, 0.05, 0.08, 0.02, 0.06, 0.01, 0] :<: 100
11 , [0.02, 0.04, 0.01, 0.02, 0.02, 0, 0] :<: 40
12 , [0.02, 0.03, 0, 0, 0.01, 0, 0] :<: 30
13 , [0.7, 0.75, 0.8, 0.75, 0.8, 0.97, 0] :>: 1500
14 , [0.02, 0.06, 0.08, 0.12, 0.02, 0.01, 0.97] :&: (250,300)
15 ]
16
17bounds = [ 1 :&: (0,200)
18 , 2 :&: (0,2500)
19 , 3 :&: (400,800)
20 , 4 :&: (100,700)
21 , 5 :&: (0,1500) ]
22
23main = print $ simplex prob constr bounds
24
diff --git a/packages/glpk/examples/simplex4.hs b/packages/glpk/examples/simplex4.hs
new file mode 100644
index 0000000..3b9c060
--- /dev/null
+++ b/packages/glpk/examples/simplex4.hs
@@ -0,0 +1,24 @@
1import Numeric.LinearProgramming
2
3-- $ glpsol --cpxlp /usr/share/doc/glpk-utils/examples/plan.lp -o result.txt
4
5prob = Minimize [0.03, 0.08, 0.17, 0.12, 0.15, 0.21, 0.38]
6
7constr = Sparse
8 [ [1#1,1#2,1#3,1#4,1#5,1#6,1#7] :==: 2000
9 , [0.15#1, 0.04#2, 0.02#3, 0.04#4, 0.2#5,0.01#6, 0.03#7] :<: 60
10 , [0.03#1, 0.05#2, 0.08#3, 0.02#4, 0.06#5, 0.01#6] :<: 100
11 , [0.02#1, 0.04#2, 0.01#3, 0.02#4, 0.02#5] :<: 40
12 , [0.02#1, 0.03#2, 0.01#5] :<: 30
13 , [0.7#1, 0.75#2, 0.8#3, 0.75#4, 0.8#5, 0.97#6] :>: 1500
14 , [0.02#1, 0.06#2, 0.08#3, 0.12#4, 0.02#5, 0.01#6, 0.97#7] :&: (250,300)
15 ]
16
17bounds = [ 1 :&: (0,200)
18 , 2 :&: (0,2500)
19 , 3 :&: (400,800)
20 , 4 :&: (100,700)
21 , 5 :&: (0,1500) ]
22
23main = print $ simplex prob constr bounds
24
diff --git a/packages/glpk/glpk.cabal b/packages/glpk/glpk.cabal
new file mode 100644
index 0000000..5df45ca
--- /dev/null
+++ b/packages/glpk/glpk.cabal
@@ -0,0 +1,35 @@
1Name: hmatrix-glpk
2Version: 0.1.0
3License: GPL
4License-file: LICENSE
5Author: Alberto Ruiz
6Maintainer: Alberto Ruiz <aruiz@um.es>
7Stability: experimental
8Homepage: http://code.haskell.org/hmatrix
9Synopsis: Linear Programming based on GLPK
10Description:
11 Simple interface to linear programming functions provided by GLPK.
12
13Category: Math
14tested-with: GHC ==6.10.4
15
16cabal-version: >=1.2
17build-type: Simple
18
19extra-source-files: examples/simplex1.hs
20 examples/simplex2.hs
21 examples/simplex3.hs
22 examples/simplex4.hs
23
24library
25 Build-Depends: base >= 3 && < 5, hmatrix >= 0.8.3
26
27 hs-source-dirs: lib
28
29 Exposed-modules: Numeric.LinearProgramming
30
31 c-sources: lib/Numeric/LinearProgramming/glpk.c
32
33 ghc-options: -Wall
34
35 extra-libraries: glpk
diff --git a/packages/glpk/lib/Numeric/LinearProgramming.hs b/packages/glpk/lib/Numeric/LinearProgramming.hs
new file mode 100644
index 0000000..1b14080
--- /dev/null
+++ b/packages/glpk/lib/Numeric/LinearProgramming.hs
@@ -0,0 +1,211 @@
1{-# LANGUAGE ForeignFunctionInterface #-}
2
3module Numeric.LinearProgramming(
4 Optimization(..),
5 Bound(..),
6 (#),
7 Coeffs(..),
8 Solution(..),
9 simplex,
10) where
11
12import Numeric.LinearAlgebra
13import Data.Packed.Development
14import Foreign(Ptr,unsafePerformIO)
15import Foreign.C.Types(CInt)
16import Data.List((\\),sortBy)
17import Data.Function(on)
18
19--import Debug.Trace
20--debug x = trace (show x) x
21
22-----------------------------------------------------
23
24-- | Coefficient of a variable
25(#) :: Double -> Int -> (Double,Int)
26infixl 5 #
27(#) = (,)
28
29data Bound x = x :<: Double
30 | x :>: Double
31 | x :&: (Double,Double)
32 | x :==: Double
33 | Free x
34 deriving Show
35
36data Solution = Undefined
37 | Feasible (Double, [Double])
38 | Infeasible (Double, [Double])
39 | NoFeasible
40 | Optimal (Double, [Double])
41 | Unbounded
42 deriving Show
43
44data Coeffs = Dense [ Bound [Double] ]
45 | Sparse [ Bound [(Double,Int)] ]
46
47data Optimization = Maximize [Double]
48 | Minimize [Double]
49
50simplex :: Optimization -> Coeffs -> [Bound Int] -> Solution
51
52simplex opt (Dense constr) bnds = extract sg sol where
53 sol = simplexDense (mkConstrD objfun constr) (mkBoundsD constr bnds)
54 (sg, objfun) = case opt of
55 Maximize x -> (1 ,x)
56 Minimize x -> (-1, (map negate x))
57
58simplex opt (Sparse constr) bnds = extract sg sol where
59 sol = simplexSparse m n (mkConstrS objfun constr) (mkBoundsS constr bnds)
60 n = length objfun
61 m = length constr
62 (sg, objfun) = case opt of
63 Maximize x -> (1 ,x)
64 Minimize x -> (-1, (map negate x))
65
66extract :: Double -> Vector Double -> Solution
67extract sg sol = r where
68 z = sg * (sol@>1)
69 v = toList $ subVector 2 (dim sol -2) sol
70 r = case round(sol@>0)::Int of
71 1 -> Undefined
72 2 -> Feasible (z,v)
73 3 -> Infeasible (z,v)
74 4 -> NoFeasible
75 5 -> Optimal (z,v)
76 6 -> Unbounded
77 _ -> error "simplex: solution type unknown"
78
79-----------------------------------------------------
80
81obj :: Bound t -> t
82obj (x :<: _) = x
83obj (x :>: _) = x
84obj (x :&: _) = x
85obj (x :==: _) = x
86obj (Free x) = x
87
88tb :: Bound t -> Double
89tb (_ :<: _) = glpUP
90tb (_ :>: _) = glpLO
91tb (_ :&: _) = glpDB
92tb (_ :==: _) = glpFX
93tb (Free _) = glpFR
94
95lb :: Bound t -> Double
96lb (_ :<: _) = 0
97lb (_ :>: a) = a
98lb (_ :&: (a,_)) = a
99lb (_ :==: a) = a
100lb (Free _) = 0
101
102ub :: Bound t -> Double
103ub (_ :<: a) = a
104ub (_ :>: _) = 0
105ub (_ :&: (_,a)) = a
106ub (_ :==: a) = a
107ub (Free _) = 0
108
109mkBound1 :: Bound t -> [Double]
110mkBound1 b = [tb b, lb b, ub b]
111
112mkBound2 :: Bound t -> (t, [Double])
113mkBound2 b = (obj b, mkBound1 b)
114
115mkBoundsD :: [Bound [a]] -> [Bound Int] -> Matrix Double
116mkBoundsD b1 b2 = fromLists (cb++vb) where
117 c = length (obj (head b1))
118 gv = map obj b2
119 rv = [1..c] \\ gv
120 vb = map snd $ sortBy (compare `on` fst) $ map (mkBound2 . (:>: 0)) rv ++ map mkBound2 b2
121 cb = map mkBound1 b1
122
123mkConstrD :: [Double] -> [Bound [Double]] -> Matrix Double
124mkConstrD f b1 = fromLists (f : map obj b1)
125
126mkBoundsS :: [Bound [(Double, Int)]] -> [Bound Int] -> Matrix Double
127mkBoundsS b1 b2 = fromLists (cb++vb) where
128 c = maximum $ map snd $ concatMap obj b1
129 gv = map obj b2
130 rv = [1..c] \\ gv
131 vb = map snd $ sortBy (compare `on` fst) $ map (mkBound2 . (:>: 0)) rv ++ map mkBound2 b2
132 cb = map mkBound1 b1
133
134mkConstrS :: [Double] -> [Bound [(Double, Int)]] -> Matrix Double
135mkConstrS objfun constr = fromLists (ob ++ co) where
136 ob = map (([0,0]++).return) objfun
137 co = concat $ zipWith f [1::Int ..] (map obj constr)
138 f k = map (g k)
139 g k (c,v) = [fromIntegral k, fromIntegral v,c]
140
141-----------------------------------------------------
142
143foreign import ccall "c_simplex_dense" c_simplex_dense
144 :: CInt -> CInt -> Ptr Double -- coeffs
145 -> CInt -> CInt -> Ptr Double -- bounds
146 -> CInt -> Ptr Double -- result
147 -> IO CInt -- exit code
148
149simplexDense :: Matrix Double -> Matrix Double -> Vector Double
150simplexDense c b = unsafePerformIO $ do
151 s <- createVector (2+cols c)
152 app3 c_simplex_dense mat (cmat c) mat (cmat b) vec s "c_simplex_dense"
153 return s
154
155foreign import ccall "c_simplex_sparse" c_simplex_sparse
156 :: CInt -> CInt -- rows and cols
157 -> CInt -> CInt -> Ptr Double -- coeffs
158 -> CInt -> CInt -> Ptr Double -- bounds
159 -> CInt -> Ptr Double -- result
160 -> IO CInt -- exit code
161
162simplexSparse :: Int -> Int -> Matrix Double -> Matrix Double -> Vector Double
163simplexSparse m n c b = unsafePerformIO $ do
164 s <- createVector (2+n)
165 let fi = fromIntegral
166 app3 (c_simplex_sparse (fi m) (fi n)) mat (cmat c) mat (cmat b) vec s "c_simplex_sparse"
167 return s
168
169glpFR, glpLO, glpUP, glpDB, glpFX :: Double
170glpFR = 0
171glpLO = 1
172glpUP = 2
173glpDB = 3
174glpFX = 4
175
176{- Raw format of coeffs
177
178simplexDense
179
180((3+1) >< 3)
181 [ 10, 6, 4
182 , 1, 1, 1
183 , 10, 4, 5
184 , 2, 2, 6 :: Double]
185
186simplexSparse
187
188(12><3)
189 [ 0.0, 0.0, 10.0
190 , 0.0, 0.0, 6.0
191 , 0.0, 0.0, 4.0
192 , 1.0, 1.0, 1.0
193 , 1.0, 2.0, 1.0
194 , 1.0, 3.0, 1.0
195 , 2.0, 1.0, 10.0
196 , 2.0, 2.0, 4.0
197 , 2.0, 3.0, 5.0
198 , 3.0, 1.0, 2.0
199 , 3.0, 2.0, 2.0
200 , 3.0, 3.0, 6.0 ]
201
202bounds = (6><3)
203 [ glpUP,0,100
204 , glpUP,0,600
205 , glpUP,0,300
206 , glpLO,0,0
207 , glpLO,0,0
208 , glpLO,0,0 ]
209
210-}
211
diff --git a/packages/glpk/lib/Numeric/LinearProgramming/glpk.c b/packages/glpk/lib/Numeric/LinearProgramming/glpk.c
new file mode 100644
index 0000000..0f4ad79
--- /dev/null
+++ b/packages/glpk/lib/Numeric/LinearProgramming/glpk.c
@@ -0,0 +1,147 @@
1typedef struct { double r, i; } doublecomplex;
2
3#define DVEC(A) int A##n, double*A##p
4#define CVEC(A) int A##n, doublecomplex*A##p
5#define DMAT(A) int A##r, int A##c, double*A##p
6#define CMAT(A) int A##r, int A##c, doublecomplex*A##p
7
8#define AT(M,r,co) (M##p[(r)*M##c+(co)])
9
10/*-----------------------------------------------------*/
11
12#include <stdlib.h>
13#include <stdio.h>
14#include <glpk.h>
15#include <math.h>
16
17int c_simplex_dense(DMAT(c), DMAT(b), DVEC(s)) {
18 glp_prob *lp;
19 lp = glp_create_prob();
20 glp_set_obj_dir(lp, GLP_MAX);
21
22 int m = cr-1;
23 int n = cc;
24 glp_add_rows(lp, m);
25 glp_add_cols(lp, n);
26 int * ia = malloc((1+m*n)*sizeof(int));
27 int * ja = malloc((1+m*n)*sizeof(int));
28 double * ar = malloc((1+m*n)*sizeof(double));
29 int i,j,k;
30 k=0;
31 for (i=1;i<=m;i++) {
32 for(j=1;j<=n;j++) {
33 k++;
34 ia[k] = i;
35 ja[k] = j;
36 ar[k] = AT(c,i,j-1);
37 //printf("%d %d %f\n",ia[k],ja[k],ar[k]);
38 }
39 }
40 glp_load_matrix(lp, k, ia, ja, ar);
41 for (j=1;j<=n;j++) {
42 glp_set_obj_coef(lp, j, AT(c,0,j-1));
43 }
44 int t;
45 for (i=1;i<=m;i++) {
46 switch((int)rint(AT(b,i-1,0))) {
47 case 0: { t = GLP_FR; break; }
48 case 1: { t = GLP_LO; break; }
49 case 2: { t = GLP_UP; break; }
50 case 3: { t = GLP_DB; break; }
51 default: { t = GLP_FX; break; }
52 }
53 glp_set_row_bnds(lp, i, t , AT(b,i-1,1), AT(b,i-1,2));
54 }
55 for (j=1;j<=n;j++) {
56 switch((int)rint(AT(b,m+j-1,0))) {
57 case 0: { t = GLP_FR; break; }
58 case 1: { t = GLP_LO; break; }
59 case 2: { t = GLP_UP; break; }
60 case 3: { t = GLP_DB; break; }
61 default: { t = GLP_FX; break; }
62 }
63 glp_set_col_bnds(lp, j, t , AT(b,m+j-1,1), AT(b,m+j-1,2));
64 }
65 glp_term_out(0);
66 glp_simplex(lp, NULL);
67 sp[0] = glp_get_status(lp);
68 sp[1] = glp_get_obj_val(lp);
69 for (k=1; k<=n; k++) {
70 sp[k+1] = glp_get_col_prim(lp, k);
71 }
72
73 glp_delete_prob(lp);
74 free(ia);
75 free(ja);
76 free(ar);
77
78 return 0;
79}
80
81/* ---------------------------------------------------- */
82
83int c_simplex_sparse(int m, int n, DMAT(c), DMAT(b), DVEC(s)) {
84 glp_prob *lp;
85 lp = glp_create_prob();
86 glp_set_obj_dir(lp, GLP_MAX);
87 int i,j,k;
88 int tot = cr - n;
89 glp_add_rows(lp, m);
90 glp_add_cols(lp, n);
91
92 //printf("%d %d\n",m,n);
93
94 // the first n values
95 for (k=1;k<=n;k++) {
96 glp_set_obj_coef(lp, k, AT(c, k-1, 2));
97 //printf("%d %f\n",k,AT(c, k-1, 2));
98 }
99
100 int * ia = malloc((1+tot)*sizeof(int));
101 int * ja = malloc((1+tot)*sizeof(int));
102 double * ar = malloc((1+tot)*sizeof(double));
103
104 for (k=1; k<= tot; k++) {
105 ia[k] = rint(AT(c,k-1+n,0));
106 ja[k] = rint(AT(c,k-1+n,1));
107 ar[k] = AT(c,k-1+n,2);
108 //printf("%d %d %f\n",ia[k],ja[k],ar[k]);
109 }
110 glp_load_matrix(lp, tot, ia, ja, ar);
111
112 int t;
113 for (i=1;i<=m;i++) {
114 switch((int)rint(AT(b,i-1,0))) {
115 case 0: { t = GLP_FR; break; }
116 case 1: { t = GLP_LO; break; }
117 case 2: { t = GLP_UP; break; }
118 case 3: { t = GLP_DB; break; }
119 default: { t = GLP_FX; break; }
120 }
121 glp_set_row_bnds(lp, i, t , AT(b,i-1,1), AT(b,i-1,2));
122 }
123 for (j=1;j<=n;j++) {
124 switch((int)rint(AT(b,m+j-1,0))) {
125 case 0: { t = GLP_FR; break; }
126 case 1: { t = GLP_LO; break; }
127 case 2: { t = GLP_UP; break; }
128 case 3: { t = GLP_DB; break; }
129 default: { t = GLP_FX; break; }
130 }
131 glp_set_col_bnds(lp, j, t , AT(b,m+j-1,1), AT(b,m+j-1,2));
132 }
133 glp_term_out(0);
134 glp_simplex(lp, NULL);
135 sp[0] = glp_get_status(lp);
136 sp[1] = glp_get_obj_val(lp);
137 for (k=1; k<=n; k++) {
138 sp[k+1] = glp_get_col_prim(lp, k);
139 }
140 glp_delete_prob(lp);
141 free(ia);
142 free(ja);
143 free(ar);
144
145 return 0;
146}
147