diff --git a/examples/simplex1.hs b/examples/simplex1.hs
--- a/examples/simplex1.hs
+++ b/examples/simplex1.hs
@@ -9,9 +9,9 @@
                , [2,2,6]  :<=: 300 ]
 
 -- default bounds
-bnds = [ 1 :=>: 0
-       , 2 :=>: 0
-       , 3 :=>: 0 ]
+bnds = [ 1 :>=: 0
+       , 2 :>=: 0
+       , 3 :>=: 0 ]
 
 main = do
     print $ simplex objFun constr []
diff --git a/examples/simplex2.hs b/examples/simplex2.hs
--- a/examples/simplex2.hs
+++ b/examples/simplex2.hs
@@ -10,9 +10,14 @@
                 , [0,1,5] :<=: 20
                 ]
 
+constr3 = General [ [1#1, 1#1, 1#2] :<=: 10
+                  , [1#2, 5#3] :<=: 20
+                  ]
+
 main = do
     print $ simplex prob constr1 []
     print $ simplex prob constr2 []
-    print $ simplex prob constr2 [ 2 :=>: 1, 3 :&: (2,7)]
+    print $ simplex prob constr3 []
+    print $ simplex prob constr2 [ 2 :>=: 1, 3 :&: (2,7)]
     print $ simplex prob constr2 [ Free 2 ]
 
diff --git a/examples/simplex3.hs b/examples/simplex3.hs
--- a/examples/simplex3.hs
+++ b/examples/simplex3.hs
@@ -11,7 +11,7 @@
     , [0.03, 0.05, 0.08, 0.02, 0.06, 0.01, 0]    :<=:  100
     , [0.02, 0.04, 0.01, 0.02, 0.02, 0,    0]    :<=:  40
     , [0.02, 0.03, 0,    0,    0.01, 0,    0]    :<=:  30
-    , [0.7,  0.75, 0.8,  0.75, 0.8,  0.97,  0]   :=>:  1500
+    , [0.7,  0.75, 0.8,  0.75, 0.8,  0.97,  0]   :>=:  1500
     , [0.02, 0.06, 0.08, 0.12, 0.02, 0.01, 0.97] :&: (250,300)
     ]
 
diff --git a/examples/simplex4.hs b/examples/simplex4.hs
--- a/examples/simplex4.hs
+++ b/examples/simplex4.hs
@@ -11,7 +11,7 @@
     , [0.03#1, 0.05#2, 0.08#3, 0.02#4, 0.06#5, 0.01#6]       :<=: 100
     , [0.02#1, 0.04#2, 0.01#3, 0.02#4, 0.02#5]               :<=:  40
     , [0.02#1, 0.03#2, 0.01#5]                               :<=:  30
-    , [0.7#1,  0.75#2, 0.8#3,  0.75#4, 0.8#5,  0.97#6]       :=>:  1500
+    , [0.7#1,  0.75#2, 0.8#3,  0.75#4, 0.8#5,  0.97#6]       :>=:  1500
     , [0.02#1, 0.06#2, 0.08#3, 0.12#4, 0.02#5, 0.01#6, 0.97#7] :&: (250,300)
     ]
 
diff --git a/examples/simplex5.hs b/examples/simplex5.hs
new file mode 100644
--- /dev/null
+++ b/examples/simplex5.hs
@@ -0,0 +1,27 @@
+import Numeric.LinearProgramming
+
+-- This is a linear program from the paper "Picking vs. Guessing Secrets: A Game-theoretic Analysis"
+
+gamma = 100000 :: Double
+sigma = 1 :: Double
+n = 64 :: Int
+cost_fun :: Int -> Double
+cost_fun i = (fromIntegral i) / (fromIntegral n)
+size_fun :: Int -> Double
+size_fun i = 2^(fromIntegral i)
+
+prob = Minimize $ map cost_fun [1..n]
+bnds = [i :&: (0,1) | i <- [1..n]]
+
+constr1 = [[1 # i | i <- [1..n]] :==: 1] ++
+          [[1/(size_fun i) # i,
+            -1/(size_fun (i+1)) # i+1] :>=: 0 | i <- [1..n-1]] ++
+          [(
+            [gamma#i | i <- [1..k]] ++
+            (concat [[sigma*(size_fun i) # j | j <- [1..i-1]] | i <- [1..k]]) ++
+            [((size_fun i) - 1)/2 # i | i <- [1..k]])
+           :<=: (sigma * (foldr (+) 0 (map size_fun [1..k]))) | k <- [1..n]]
+
+main = do
+  print $ simplex prob (General constr1) bnds -- NoFeasible
+  print $ exact   prob (General constr1) bnds -- solution found
diff --git a/hmatrix-glpk.cabal b/hmatrix-glpk.cabal
--- a/hmatrix-glpk.cabal
+++ b/hmatrix-glpk.cabal
@@ -1,5 +1,5 @@
 Name:               hmatrix-glpk
-Version:            0.4.0.2
+Version:            0.4.1.0
 License:            GPL
 License-file:       LICENSE
 Author:             Alberto Ruiz
@@ -20,9 +20,10 @@
                         examples/simplex2.hs
                         examples/simplex3.hs
                         examples/simplex4.hs
+                        examples/simplex5.hs
 
 library
-    Build-Depends:      base <5, hmatrix >= 0.16
+    Build-Depends:      base <5, hmatrix >= 0.16, containers >= 0.5.4.0
 
     hs-source-dirs:     src
 
diff --git a/src/C/glpk.c b/src/C/glpk.c
--- a/src/C/glpk.c
+++ b/src/C/glpk.c
@@ -10,67 +10,71 @@
 
 /*-----------------------------------------------------*/
 
-int c_simplex_sparse(int m, int n, DMAT(c), DMAT(b), DVEC(s)) {
-    glp_prob *lp;
-    lp = glp_create_prob();
-    glp_set_obj_dir(lp, GLP_MAX);
-    int i,j,k;
-    int tot = cr - n;
-    glp_add_rows(lp, m);
-    glp_add_cols(lp, n);
-
-    //printf("%d %d\n",m,n);
-
-    // the first n values
-    for (k=1;k<=n;k++) {
-        glp_set_obj_coef(lp, k, AT(c, k-1, 2));
-        //printf("%d %f\n",k,AT(c, k-1, 2));
-    }
-
-    int * ia = malloc((1+tot)*sizeof(int));
-    int * ja = malloc((1+tot)*sizeof(int));
-    double * ar = malloc((1+tot)*sizeof(double));
-
-    for (k=1; k<= tot; k++) {
-        ia[k] = rint(AT(c,k-1+n,0));
-        ja[k] = rint(AT(c,k-1+n,1));
-        ar[k] =      AT(c,k-1+n,2);
-        //printf("%d %d %f\n",ia[k],ja[k],ar[k]);
-    }
-    glp_load_matrix(lp, tot, ia, ja, ar);
-
-    int t;
-    for (i=1;i<=m;i++) {
-    switch((int)rint(AT(b,i-1,0))) {
-        case 0: { t = GLP_FR; break; }
-        case 1: { t = GLP_LO; break; }
-        case 2: { t = GLP_UP; break; }
-        case 3: { t = GLP_DB; break; }
-       default: { t = GLP_FX; break; }
-    }
-    glp_set_row_bnds(lp, i, t , AT(b,i-1,1), AT(b,i-1,2));
-    }
-    for (j=1;j<=n;j++) {
-    switch((int)rint(AT(b,m+j-1,0))) {
-        case 0: { t = GLP_FR; break; }
-        case 1: { t = GLP_LO; break; }
-        case 2: { t = GLP_UP; break; }
-        case 3: { t = GLP_DB; break; }
-       default: { t = GLP_FX; break; }
-    }
-    glp_set_col_bnds(lp, j, t , AT(b,m+j-1,1), AT(b,m+j-1,2));
-    }
-    glp_term_out(0);
-    glp_simplex(lp, NULL);
-    sp[0] = glp_get_status(lp);
-    sp[1] = glp_get_obj_val(lp);
-    for (k=1; k<=n; k++) {
-        sp[k+1] = glp_get_col_prim(lp, k);
-    }
-    glp_delete_prob(lp);
-    free(ia);
-    free(ja);
-    free(ar);
+#define C_X_SPARSE(X)                                           \
+  int c_##X##_sparse(int m, int n, DMAT(c), DMAT(b), DVEC(s)) { \
+    glp_prob *lp;                                               \
+    lp = glp_create_prob();                                     \
+    glp_set_obj_dir(lp, GLP_MAX);                               \
+    int i,j,k;                                                  \
+    int tot = cr - n;                                           \
+    glp_add_rows(lp, m);                                        \
+    glp_add_cols(lp, n);                                        \
+                                                                \
+    /*printf("%d %d\n",m,n);*/                                  \
+                                                                \
+    /* the first n values */                                    \
+    for (k=1;k<=n;k++) {                                        \
+      glp_set_obj_coef(lp, k, AT(c, k-1, 2));                   \
+      /*printf("%d %f\n",k,AT(c, k-1, 2)); */                   \
+    }                                                           \
+                                                                \
+    int * ia = malloc((1+tot)*sizeof(int));                     \
+    int * ja = malloc((1+tot)*sizeof(int));                     \
+    double * ar = malloc((1+tot)*sizeof(double));               \
+                                                                \
+    for (k=1; k<= tot; k++) {                                   \
+      ia[k] = rint(AT(c,k-1+n,0));                              \
+      ja[k] = rint(AT(c,k-1+n,1));                              \
+      ar[k] =      AT(c,k-1+n,2);                               \
+      /*printf("%d %d %f\n",ia[k],ja[k],ar[k]);*/               \
+    }                                                           \
+    glp_load_matrix(lp, tot, ia, ja, ar);                       \
+                                                                \
+    int t;                                                      \
+    for (i=1;i<=m;i++) {                                        \
+      switch((int)rint(AT(b,i-1,0))) {                          \
+      case 0: { t = GLP_FR; break; }                            \
+      case 1: { t = GLP_LO; break; }                            \
+      case 2: { t = GLP_UP; break; }                            \
+      case 3: { t = GLP_DB; break; }                            \
+      default: { t = GLP_FX; break; }                           \
+      }                                                         \
+      glp_set_row_bnds(lp, i, t , AT(b,i-1,1), AT(b,i-1,2));    \
+    }                                                           \
+    for (j=1;j<=n;j++) {                                        \
+      switch((int)rint(AT(b,m+j-1,0))) {                        \
+      case 0: { t = GLP_FR; break; }                            \
+      case 1: { t = GLP_LO; break; }                            \
+      case 2: { t = GLP_UP; break; }                            \
+      case 3: { t = GLP_DB; break; }                            \
+      default: { t = GLP_FX; break; }                           \
+      }                                                         \
+      glp_set_col_bnds(lp, j, t , AT(b,m+j-1,1), AT(b,m+j-1,2));        \
+    }                                                                   \
+    glp_term_out(0);                                                    \
+    glp_##X(lp, NULL);                                                  \
+      sp[0] = glp_get_status(lp);                                       \
+      sp[1] = glp_get_obj_val(lp);                                      \
+      for (k=1; k<=n; k++) {                                            \
+        sp[k+1] = glp_get_col_prim(lp, k);                              \
+      }                                                                 \
+      glp_delete_prob(lp);                                              \
+      free(ia);                                                         \
+      free(ja);                                                         \
+      free(ar);                                                         \
+                                                                        \
+      return 0;                                                         \
+  }                                                                     \
 
-    return 0;
-}
+C_X_SPARSE(simplex);
+C_X_SPARSE(exact);
diff --git a/src/Numeric/LinearProgramming.hs b/src/Numeric/LinearProgramming.hs
--- a/src/Numeric/LinearProgramming.hs
+++ b/src/Numeric/LinearProgramming.hs
@@ -49,6 +49,14 @@
                 ]
 @
 
+Note that when using sparse constraints, coefficients cannot appear more than once in each constraint. You can alternatively use General which will automatically sum any duplicate coefficients when necessary.
+
+@
+constr3 = General [ [1\#1, 1\#1, 1\#2] :<=: 10
+                  , [1\#2, 5\#3] :<=: 20
+                  ]
+@
+
 By default all variables are bounded as @x_i >= 0@, but this can be
 changed:
 
@@ -67,6 +75,8 @@
 
 module Numeric.LinearProgramming(
     simplex,
+    exact,
+    sparseOfGeneral,
     Optimization(..),
     Constraints(..),
     Bounds,
@@ -82,13 +92,14 @@
 import Foreign.C.Types
 import Data.List((\\),sortBy,nub)
 import Data.Function(on)
+import qualified Data.Map.Strict as Map
 
 --import Debug.Trace
 --debug x = trace (show x) x
 
 -----------------------------------------------------
 
--- | Coefficient of a variable for a sparse representation of constraints.
+-- | Coefficient of a variable for a sparse and general representations of constraints.
 (#) :: Double -> Int -> (Double,Int)
 infixl 5 #
 (#) = (,)
@@ -108,18 +119,29 @@
               | Unbounded
               deriving Show
 
-data Constraints = Dense  [ Bound [Double] ]
-                 | Sparse [ Bound [(Double,Int)] ]
+data Constraints = Dense   [ Bound [Double] ]
+                 | Sparse  [ Bound [(Double,Int)] ]
+                 | General [ Bound [(Double,Int)] ]
 
 data Optimization = Maximize [Double]
                   | Minimize [Double]
 
 type Bounds = [Bound Int]
 
+-- | Convert a system of General constraints to one with unique coefficients. 
+sparseOfGeneral :: Constraints -> Constraints
+sparseOfGeneral (General cs) =
+    Sparse $ map (\bl -> 
+                      let cl = obj bl in
+                      let cl_unique = foldr (\(c,t) m -> Map.insertWith (+) t c m) Map.empty cl in
+                      withObj bl (Map.foldrWithKey' (\t c l -> (c#t) : l) [] cl_unique)) cs
+sparseOfGeneral _ = error "sparseOfGeneral: a general system of constraints was expected"
+
 simplex :: Optimization -> Constraints -> Bounds -> Solution
 
-simplex opt (Dense  []) bnds = simplex opt (Sparse []) bnds
-simplex opt (Sparse []) bnds = simplex opt (Sparse [Free [0#1]]) bnds
+simplex opt (Dense   []) bnds = simplex opt (Sparse []) bnds
+simplex opt (Sparse  []) bnds = simplex opt (Sparse [Free [0#1]]) bnds
+simplex opt (General []) bnds = simplex opt (Sparse [Free [0#1]]) bnds
 
 simplex opt (Dense constr) bnds = extract sg sol where
     sol = simplexSparse m n (mkConstrD sz objfun constr) (mkBounds sz constr bnds)
@@ -133,6 +155,29 @@
     m = length constr
     (sz, sg, objfun) = adapt opt
 
+simplex opt constr@(General _) bnds = simplex opt (sparseOfGeneral constr) bnds
+
+-- | Simplex method with exact internal arithmetic. See glp_exact in glpk documentation for more information.
+exact :: Optimization -> Constraints -> Bounds -> Solution
+
+exact opt (Dense   []) bnds = exact opt (Sparse []) bnds
+exact opt (Sparse  []) bnds = exact opt (Sparse [Free [0#1]]) bnds
+exact opt (General []) bnds = exact opt (Sparse [Free [0#1]]) bnds
+
+exact opt (Dense constr) bnds = extract sg sol where
+    sol = exactSparse m n (mkConstrD sz objfun constr) (mkBounds sz constr bnds)
+    n = length objfun
+    m = length constr
+    (sz, sg, objfun) = adapt opt
+
+exact opt (Sparse constr) bnds = extract sg sol where
+    sol = exactSparse m n (mkConstrS sz objfun constr) (mkBounds sz constr bnds)
+    n = length objfun
+    m = length constr
+    (sz, sg, objfun) = adapt opt
+
+exact opt constr@(General _) bnds = exact opt (sparseOfGeneral constr) bnds
+
 adapt :: Optimization -> (Int, Double, [Double])
 adapt opt = case opt of
     Maximize x -> (size x, 1 ,x)
@@ -162,6 +207,13 @@
 obj (x :==: _) = x
 obj (Free x)   = x
 
+withObj :: Bound t -> t -> Bound t
+withObj (_ :<=: b) x = (x :<=: b)
+withObj (_ :>=: b) x = (x :>=: b)
+withObj (_ :&: b) x = (x :&: b)
+withObj (_ :==: b) x = (x :==: b)
+withObj (Free _) x = Free x
+
 tb :: Bound t -> Double
 tb (_ :<=: _)  = glpUP
 tb (_ :>=: _)  = glpLO
@@ -233,6 +285,19 @@
 simplexSparse m n c b = unsafePerformIO $ do
     s <- createVector (2+n)
     app3 (c_simplex_sparse (fi m) (fi n)) mat (cmat c) mat (cmat b) vec s "c_simplex_sparse"
+    return s
+
+foreign import ccall unsafe "c_exact_sparse" c_exact_sparse
+    :: CInt -> CInt                  -- rows and cols
+    -> CInt -> CInt -> Ptr Double    -- coeffs
+    -> CInt -> CInt -> Ptr Double    -- bounds
+    -> CInt -> Ptr Double            -- result
+    -> IO CInt                       -- exit code
+
+exactSparse :: Int -> Int -> Matrix Double -> Matrix Double -> Vector Double
+exactSparse m n c b = unsafePerformIO $ do
+    s <- createVector (2+n)
+    app3 (c_exact_sparse (fi m) (fi n)) mat (cmat c) mat (cmat b) vec s "c_exact_sparse"
     return s
 
 glpFR, glpLO, glpUP, glpDB, glpFX :: Double
