diff --git a/casadi-bindings.cabal b/casadi-bindings.cabal
--- a/casadi-bindings.cabal
+++ b/casadi-bindings.cabal
@@ -1,53 +1,32 @@
 name:                casadi-bindings
-version:             2.0.0.1
-synopsis:            low level bindings to CasADi
+version:             2.1.0.0
+synopsis:            mid-level bindings to CasADi
 category:            Numerical, Math
 description:
     Haskell bindings to the CasADi algorithmic differentiation and optimal control library.
     Version numbers correspond to the C++ library version numbers except the very last number
     which may indicate breaking changes.
     .
-    This is a metapackage which also hosts the installation instructions. The purpose is that
-    users of the library will always be able to "cabal install casadi-bindings" and have things
-    Just Work, though you may need to install additional add-on modules manually.
+    This package is a mid-level interface to the low-level bindings `casadi-bindings-core`.
     .
     The `casadi-bindings-internal` package is handwritten and provides some casadi memory management
     wrappers and C++ standard type marsahalling.
     .
-    The rest of the modules like `casadi-bindings-core`, `casadi-bindings-ipopt-interface`, etc
-    are autogenerated from casadi's swig interface and correspond exactly to the casadi C++ API.
+    The module `casadi-bindings-core` is autogenerated
+    from casadi's swig interface and corresponds to the casadi C++ API
+    (though some functions will be missing).
     .
     For high-level bindings, see my <https://github.com/ghorn/dynobud dynobud> project
     .
     The current instructions for getting started on Debian/Ubuntu:
     .
-    Install libcasadi-shared from <https://github.com/casadi/casadi/releases/latest https://github.com/casadi/casadi/releases/latest>,
-    first download it from that website, then:
-    .
-    >> dpkg -i libcasadi-shared.deb
-    .
-    >> cabal update; cabal install casadi-bindings
-    .
-    to install the ipopt interface:
-    .
-    >> apt-get install coinor-libipopt-dev
-    .
-    >> cabal install casadi-bindings-ipopt-interface
-    .
-    Temporary note: there is something wrong with casadi and ipopt related
-    to <http://list.coin-or.org/pipermail/ipopt/2014-April/003670.html http://list.coin-or.org/pipermail/ipopt/2014-April/003670.html>,
-    and <https://github.com/casadi/casadi/issues/1075 https://github.com/casadi/casadi/issues/1075>.
-    At the moment this .cabal package works for me as is, but YMMV
-    .
-    For the snopt interface, you may have to do something like
+    Install casadi from source or with apt-get for debian or homebrew for osx (IN PROGRESS)
     .
-    > cabal install casadi-bindings-snopt-interface --extra-lib-dirs='/home/me/snopt/lib'
+    >> apt-get install libcasadi*
     .
-    to find the snopt libraries
+    Then cabal install this package
     .
-    I only officially support debian/ubuntu right now, but I have gotten it working on OSX
-    in the past. Everything is done with pkg-config and LD_LIBRARY_PATH, so there's no reason
-    I know that there should be problems.
+    >> cabal update; cabal install casadi-bindings
 
 homepage:            http://github.com/ghorn/casadi-bindings
 license:             LGPL-3
@@ -59,8 +38,26 @@
 cabal-version:       >=1.10
 
 library
-  build-depends:       casadi-bindings-internal == 0.1.1,
-                       casadi-bindings-core     == 2.0.0.1
+  hs-source-dirs:      src
+  exposed-modules:     Casadi.Callback
+                       Casadi.DMatrix
+                       Casadi.Function
+                       Casadi.GenericC
+                       Casadi.IOSchemes
+                       Casadi.MX
+                       Casadi.MXFunction
+                       Casadi.Option
+                       Casadi.Overloading
+                       Casadi.SharedObject
+                       Casadi.SX
+                       Casadi.SXElement
+                       Casadi.SXFunction
+  build-depends:       base >=4.6 && <5,
+                       linear,
+                       vector,
+                       containers,
+                       casadi-bindings-internal == 0.1.1,
+                       casadi-bindings-core     == 2.1.0.0
   default-language:    Haskell2010
 
 source-repository head
diff --git a/src/Casadi/Callback.hs b/src/Casadi/Callback.hs
new file mode 100644
--- /dev/null
+++ b/src/Casadi/Callback.hs
@@ -0,0 +1,30 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# Language ScopedTypeVariables #-}
+{-# Language FlexibleContexts #-}
+
+module Casadi.Callback
+       ( makeCallback
+       ) where
+
+import Foreign.C.Types
+import Foreign.Ptr ( Ptr )
+import Foreign.ForeignPtr ( newForeignPtr_ )
+
+import Casadi.Core.Data
+import Casadi.Internal.WrapReturn ( WrapReturn(..) )
+import Casadi.Internal.Callback ( mkCallback, c_newCallbackHaskell )
+
+-- | add a callback to an NLPSolver
+makeCallback :: (Function -> IO CInt) -> IO Callback
+makeCallback callback = do
+  -- safely wrap the callback into the C-friendly version
+  let callback' :: Ptr Function' -> IO CInt
+      callback' ptrFx = do
+        foreignCFun <- newForeignPtr_ ptrFx
+        callback (Function foreignCFun)
+
+  -- turn the callback into a FunPtr
+  callbackFunPtr <- mkCallback callback'
+
+  -- create the callback object
+  (c_newCallbackHaskell callbackFunPtr :: IO (Ptr Callback')) >>= wrapReturn
diff --git a/src/Casadi/DMatrix.hs b/src/Casadi/DMatrix.hs
new file mode 100644
--- /dev/null
+++ b/src/Casadi/DMatrix.hs
@@ -0,0 +1,175 @@
+{-# OPTIONS_GHC -Wall -fno-cse -fno-warn-orphans #-}
+
+module Casadi.DMatrix
+       ( DMatrix(), dcrs, dmm, dvector, ddata, ddiag
+       , ddense, dsparse, dtrans, dtriu, dtril
+       , dsize, dsize1, dsize2, dnumel
+       , dvertcat, dhorzcat, dveccat, dvertsplit, dhorzsplit
+       , dones, dzeros
+       ) where
+
+import qualified Data.Vector as V
+import System.IO.Unsafe ( unsafePerformIO )
+
+import Casadi.Core.Classes.Sparsity
+import Casadi.Core.Classes.DMatrix
+import qualified Casadi.Core.Tools as C
+
+import Casadi.Overloading ( Fmod(..), ArcTan2(..), SymOrd(..) )
+
+-- | matrix matrix product
+dmm :: DMatrix -> DMatrix -> DMatrix
+dmm x y = unsafePerformIO (dmatrix_mul__0 x y)
+{-# NOINLINE dmm #-}
+
+-- | transpose
+dtrans :: DMatrix -> DMatrix
+dtrans x = unsafePerformIO (dmatrix_trans x)
+{-# NOINLINE dtrans #-}
+
+ddense :: DMatrix -> DMatrix
+ddense x = unsafePerformIO (C.dense__2 x)
+{-# NOINLINE ddense #-}
+
+dsparse :: DMatrix -> DMatrix
+dsparse x = unsafePerformIO (C.sparse__2 x)
+{-# NOINLINE dsparse #-}
+
+dcrs :: DMatrix -> Sparsity
+dcrs x = unsafePerformIO (dmatrix_sparsityRef__0 x)
+{-# NOINLINE dcrs #-}
+
+ddiag :: DMatrix -> DMatrix
+ddiag x = unsafePerformIO (C.diag__2 x)
+{-# NOINLINE ddiag #-}
+
+-- | from vector
+dvector :: V.Vector Double -> DMatrix
+dvector x = unsafePerformIO (dmatrix__4 x)
+{-# NOINLINE dvector #-}
+
+ddata :: DMatrix -> V.Vector Double
+ddata x = unsafePerformIO (dmatrix_data__0 x)
+{-# NOINLINE ddata #-}
+
+dsize :: DMatrix -> Int
+dsize x = unsafePerformIO (dmatrix_size__1 x)
+{-# NOINLINE dsize #-}
+
+dsize1 :: DMatrix -> Int
+dsize1 x = unsafePerformIO (dmatrix_size1 x)
+{-# NOINLINE dsize1 #-}
+
+dsize2 :: DMatrix -> Int
+dsize2 x = unsafePerformIO (dmatrix_size2 x)
+{-# NOINLINE dsize2 #-}
+
+dnumel :: DMatrix -> Int
+dnumel x = unsafePerformIO (dmatrix_numel x)
+{-# NOINLINE dnumel #-}
+
+dvertcat :: V.Vector DMatrix -> DMatrix
+dvertcat x = unsafePerformIO (C.vertcat__3 x)
+{-# NOINLINE dvertcat #-}
+
+dveccat :: V.Vector DMatrix -> DMatrix
+dveccat x = unsafePerformIO (C.veccat__2 x)
+{-# NOINLINE dveccat #-}
+
+dvertsplit :: DMatrix -> V.Vector Int -> V.Vector DMatrix
+dvertsplit x ks = unsafePerformIO (C.vertsplit__9 x ks)
+{-# NOINLINE dvertsplit #-}
+
+dhorzsplit :: DMatrix -> V.Vector Int -> V.Vector DMatrix
+dhorzsplit x ks = unsafePerformIO (C.horzsplit__9 x ks)
+{-# NOINLINE dhorzsplit #-}
+
+dhorzcat :: V.Vector DMatrix -> DMatrix
+dhorzcat x = unsafePerformIO (C.horzcat__3 x)
+{-# NOINLINE dhorzcat #-}
+
+dtriu :: DMatrix -> DMatrix
+dtriu x = unsafePerformIO (C.triu__4 (castDMatrix x))
+{-# NOINLINE dtriu #-}
+
+dtril :: DMatrix -> DMatrix
+dtril x = unsafePerformIO (C.tril__4 (castDMatrix x))
+{-# NOINLINE dtril #-}
+
+dones :: (Int,Int) -> DMatrix
+dones (r,c) = unsafePerformIO (dmatrix_ones__3 r c)
+{-# NOINLINE dones #-}
+
+dzeros :: (Int,Int) -> DMatrix
+dzeros (r,c) = unsafePerformIO (dmatrix_zeros__3 r c)
+{-# NOINLINE dzeros #-}
+
+instance Num DMatrix where
+  (+) x y = unsafePerformIO (dmatrix___add__ x y)
+  {-# NOINLINE (+) #-}
+  (-) x y = unsafePerformIO (dmatrix___sub__ x y)
+  {-# NOINLINE (-) #-}
+  (*) x y = unsafePerformIO (dmatrix___mul__ x y)
+  {-# NOINLINE (*) #-}
+  fromInteger x = unsafePerformIO (dmatrix__5 (fromInteger x :: Double))
+  {-# NOINLINE fromInteger #-}
+  abs x = unsafePerformIO (dmatrix_fabs x)
+  {-# NOINLINE abs #-}
+  signum x = unsafePerformIO (dmatrix_sign x)
+  {-# NOINLINE signum #-}
+
+instance Fractional DMatrix where
+  (/) x y = unsafePerformIO (dmatrix___truediv____0 x y)
+  {-# NOINLINE (/) #-}
+  fromRational x = unsafePerformIO (dmatrix__5 (fromRational x :: Double))
+  {-# NOINLINE fromRational #-}
+
+instance Floating DMatrix where
+  pi = unsafePerformIO (dmatrix__5 (pi :: Double))
+  {-# NOINLINE pi #-}
+  (**) x y = unsafePerformIO (dmatrix___pow__ x y)
+  {-# NOINLINE (**) #-}
+  exp x   = unsafePerformIO (dmatrix_exp x)
+  {-# NOINLINE exp #-}
+  log x   = unsafePerformIO (dmatrix_log x)
+  {-# NOINLINE log #-}
+  sin x   = unsafePerformIO (dmatrix_sin x)
+  {-# NOINLINE sin #-}
+  cos x   = unsafePerformIO (dmatrix_cos x)
+  {-# NOINLINE cos #-}
+  tan x   = unsafePerformIO (dmatrix_tan x)
+  {-# NOINLINE tan #-}
+  asin x  = unsafePerformIO (dmatrix_arcsin x)
+  {-# NOINLINE asin #-}
+  atan x  = unsafePerformIO (dmatrix_arctan x)
+  {-# NOINLINE atan #-}
+  acos x  = unsafePerformIO (dmatrix_arccos x)
+  {-# NOINLINE acos #-}
+  sinh x  = unsafePerformIO (dmatrix_sinh x)
+  {-# NOINLINE sinh #-}
+  cosh x  = unsafePerformIO (dmatrix_cosh x)
+  {-# NOINLINE cosh #-}
+  tanh x  = unsafePerformIO (dmatrix_tanh x)
+  {-# NOINLINE tanh #-}
+  asinh x = unsafePerformIO (dmatrix_arcsinh x)
+  {-# NOINLINE asinh #-}
+  atanh x = unsafePerformIO (dmatrix_arctanh x)
+  {-# NOINLINE atanh #-}
+  acosh x = unsafePerformIO (dmatrix_arccosh x)
+  {-# NOINLINE acosh #-}
+
+instance Fmod DMatrix where
+  fmod x y = unsafePerformIO (dmatrix_fmod x y)
+  {-# NOINLINE fmod #-}
+
+instance ArcTan2 DMatrix where
+  arctan2 x y = unsafePerformIO (dmatrix_arctan2 x y)
+  {-# NOINLINE arctan2 #-}
+
+instance SymOrd DMatrix where
+  x `leq` y = unsafePerformIO (dmatrix___le__ x y)
+  {-# NOINLINE leq #-}
+  x `geq` y = unsafePerformIO (dmatrix___ge____0 x y)
+  {-# NOINLINE geq #-}
+  x  `eq` y = unsafePerformIO (dmatrix___eq__ x y)
+  {-# NOINLINE eq #-}
diff --git a/src/Casadi/Function.hs b/src/Casadi/Function.hs
new file mode 100644
--- /dev/null
+++ b/src/Casadi/Function.hs
@@ -0,0 +1,64 @@
+{-# OPTIONS_GHC -Wall -fno-cse -fno-warn-orphans #-}
+
+module Casadi.Function
+       ( C.MXFunction, C.Function, callMX, callSX, evalDMatrix
+       , jacobian, gradient, derivative
+       , generateCode, externalFunction
+       ) where
+
+import Data.Vector ( Vector )
+import qualified Data.Vector as V
+import System.IO.Unsafe ( unsafePerformIO )
+import Control.Monad ( zipWithM_ )
+
+import qualified Casadi.Core.Classes.MXFunction as C
+import qualified Casadi.Core.Classes.IOInterfaceFunction as C
+import qualified Casadi.Core.Classes.Function as C
+import qualified Casadi.Core.Classes.ExternalFunction as C
+
+import Casadi.SX ( SX )
+import Casadi.MX ( MX )
+import Casadi.DMatrix ( DMatrix )
+
+-- | call an MXFunction on symbolic inputs, getting symbolic outputs
+callMX :: C.FunctionClass f => f -> Vector MX -> Vector MX
+callMX f ins = unsafePerformIO (C.function_call__0 f ins)
+{-# NOINLINE callMX #-}
+
+-- | call an SXFunction on symbolic inputs, getting symbolic outputs
+callSX :: C.FunctionClass f => f -> Vector SX -> Vector SX
+callSX f ins = unsafePerformIO (C.function_call__3 f ins)
+{-# NOINLINE callSX #-}
+
+-- | evaluate an SXFunction with 1 input and 1 output
+evalDMatrix :: (C.FunctionClass f, C.IOInterfaceFunctionClass f)
+               => f -> Vector DMatrix -> IO (Vector DMatrix)
+evalDMatrix sxf inputs = do
+  -- set inputs
+  zipWithM_ (C.ioInterfaceFunction_setInput__2 sxf) (V.toList inputs) [0..]
+
+  -- eval
+  C.function_evaluate sxf
+
+  -- get outputs
+  numOut <- C.ioInterfaceFunction_getNumOutputs sxf
+  outputs <- mapM (C.ioInterfaceFunction_output__2 sxf) (take numOut [0..])
+
+  -- return vectorized outputs
+  return (V.fromList outputs)
+
+jacobian :: C.FunctionClass a => a -> Int -> Int -> Bool -> Bool -> IO C.Function
+jacobian = C.function_jacobian__14
+
+gradient :: C.FunctionClass a => a -> Int -> Int -> IO C.Function
+gradient = C.function_gradient__6
+
+derivative :: C.FunctionClass a => a -> Int -> Int -> IO C.Function
+derivative = C.function_derivative
+
+generateCode :: C.FunctionClass a => a -> String
+generateCode f = unsafePerformIO (C.function_generateCode__0 f)
+{-# NOINLINE generateCode #-}
+
+externalFunction :: String -> IO C.Function
+externalFunction name = fmap C.castFunction $ C.externalFunction__0 name
diff --git a/src/Casadi/GenericC.hs b/src/Casadi/GenericC.hs
new file mode 100644
--- /dev/null
+++ b/src/Casadi/GenericC.hs
@@ -0,0 +1,56 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# Language FlexibleInstances #-}
+
+module Casadi.GenericC
+       ( GenericC(..)
+       , getDescription
+       ) where
+
+import Data.Vector ( Vector )
+import Casadi.Core.Classes.Function ( Function )
+import Casadi.Core.Classes.GenericType
+
+class GenericC a where
+  mkGeneric :: a -> IO GenericType
+  fromGeneric :: GenericType -> IO (Maybe a)
+
+getDescription :: GenericType -> IO String
+getDescription = genericType_get_description
+
+instance GenericC Bool where
+  mkGeneric = genericType__11
+  fromGeneric = ifThenGet genericType_isBool genericType_toBool
+instance GenericC Int where
+  mkGeneric = genericType__10
+  fromGeneric = ifThenGet genericType_isInt genericType_toInt
+instance GenericC Double where
+  mkGeneric = genericType__9
+  fromGeneric = ifThenGet genericType_isDouble genericType_toDouble
+instance GenericC String where
+  mkGeneric = genericType__8
+  fromGeneric = ifThenGet genericType_isString genericType_toString
+instance GenericC (Vector Bool) where
+  mkGeneric = genericType__7
+  fromGeneric = const (return Nothing)
+instance GenericC (Vector Int) where
+  mkGeneric = genericType__6
+  fromGeneric = ifThenGet genericType_isIntVector genericType_toIntVector
+instance GenericC (Vector Double) where
+  mkGeneric = genericType__5
+  fromGeneric = ifThenGet genericType_isDoubleVector genericType_toDoubleVector
+instance GenericC (Vector String) where
+  mkGeneric = genericType__4
+  fromGeneric = ifThenGet genericType_isStringVector genericType_toStringVector
+instance GenericC GenericType where
+  mkGeneric = return
+  fromGeneric = return . Just
+instance GenericC Function where
+  mkGeneric = genericType__3
+  fromGeneric = ifThenGet genericType_isFunction genericType_toFunction
+
+ifThenGet :: (a -> IO Bool) -> (a -> IO b) -> a -> IO (Maybe b)
+ifThenGet isOpt getOpt g = do
+  isopt <- isOpt g
+  if isopt
+    then fmap Just (getOpt g)
+    else return Nothing
diff --git a/src/Casadi/IOSchemes.hs b/src/Casadi/IOSchemes.hs
new file mode 100644
--- /dev/null
+++ b/src/Casadi/IOSchemes.hs
@@ -0,0 +1,63 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# Language ScopedTypeVariables #-}
+
+module Casadi.IOSchemes
+       ( mkSchemeSX
+       , mkSchemeMX
+       , mkSchemeCRSSparsity
+       ) where
+
+import qualified Data.Map as M
+import qualified Data.Set as S
+import qualified Data.Foldable as F
+import qualified Data.Vector as V
+
+import Casadi.Core.Classes.Sparsity -- ( Sparsity, sparsity' )
+import Casadi.Core.Classes.SX -- ( SX, sx )
+import Casadi.Core.Classes.MX -- ( MX, mx )
+import Casadi.Core.Classes.IOScheme -- ( ioScheme', ioScheme_size, ioScheme_entry )
+import Casadi.Core.Enums ( InputOutputScheme(..) )
+
+mkScheme :: forall a . IO a -> InputOutputScheme -> [(String,a)] -> IO (V.Vector a)
+mkScheme newEmpty schemeEnum userVals = do
+  sch <- ioScheme__22 schemeEnum
+  size <- ioScheme_size sch
+  let ks = take size [(0::Int)..]
+  entries <- mapM (ioScheme_entry sch) ks
+  let entrySet :: S.Set String
+      entrySet = S.fromList entries
+
+      -- map of user input {String:a}, already checked for duplicates
+      userMap :: M.Map String a
+      userMap = M.fromListWithKey err userVals
+      err k _ _ = error $ "mkScheme: " ++ show schemeEnum ++ ": you gave key \"" ++ k ++ "\" more than once"
+
+      userSet :: S.Set String
+      userSet = M.keysSet userMap
+
+  case F.toList (S.difference userSet entrySet) of
+    [] -> return ()
+    xs ->  error $ "mkScheme: " ++ show schemeEnum ++ ": you gave keys " ++ show xs ++ " which aren't valid, valid entries:\n" ++ show entries
+
+  let getElem str = case M.lookup str userMap of
+        Nothing -> newEmpty -- new empty
+        Just x -> return x
+
+--  name <- ioScheme_name sch
+--  print size
+--  print name
+--  ioScheme_entryNames sch >>= putStrLn
+--  mapM (ioScheme_entry sch) ks >>= print
+--  mapM (ioScheme_entryEnum sch) ks >>= print
+--  mapM (ioScheme_entryLabel sch) ks >>= print
+
+  fmap V.fromList $ mapM getElem entries
+
+mkSchemeSX :: InputOutputScheme -> [(String,SX)] -> IO (V.Vector SX)
+mkSchemeSX = mkScheme sx__14
+
+mkSchemeMX :: InputOutputScheme -> [(String,MX)] -> IO (V.Vector MX)
+mkSchemeMX = mkScheme mx__8
+
+mkSchemeCRSSparsity :: InputOutputScheme -> [(String,Sparsity)] -> IO (V.Vector Sparsity)
+mkSchemeCRSSparsity = mkScheme sparsity__1
diff --git a/src/Casadi/MX.hs b/src/Casadi/MX.hs
new file mode 100644
--- /dev/null
+++ b/src/Casadi/MX.hs
@@ -0,0 +1,216 @@
+{-# OPTIONS_GHC -Wall -fno-cse -fno-warn-orphans #-}
+
+module Casadi.MX
+       ( MX(), sym, symV, symM, mm, trans, diag
+       , gradient, jacobian -- , hessian
+       , solve
+       , expand
+       , triu
+       , tril
+       , dense --, sparse
+       , d2m
+       , size, size1, size2, numel
+       , crs, vertcat, horzcat, veccat, vertsplit, horzsplit
+       , ones, zeros
+       ) where
+
+import Data.Vector ( Vector )
+import qualified Data.Vector as V
+import System.IO.Unsafe ( unsafePerformIO )
+import Linear.Conjugate ( Conjugate(..) )
+
+import Casadi.Core.Classes.MX
+import Casadi.Core.Classes.DMatrix ( DMatrix )
+import Casadi.Core.Classes.Sparsity ( Sparsity )
+import qualified Casadi.Core.Tools as C
+
+import Casadi.Overloading ( Fmod(..), ArcTan2(..), SymOrd(..) )
+
+instance Conjugate MX where
+  conjugate = id
+
+sym :: String -> IO MX
+sym x = fmap castMX (mx_sym__5 x)
+
+symV :: String -> Int -> IO MX
+symV x y = fmap castMX (mx_sym__6 x y)
+
+symM :: String -> Int -> Int -> IO MX
+symM x y z = fmap castMX (mx_sym__7 x y z)
+
+-- | @jacobian exp x@ is the jacobian of exp w.r.t. x
+gradient :: MX -> MX -> MX
+gradient x y = unsafePerformIO (C.gradient__0 x y)
+{-# NOINLINE gradient #-}
+
+-- | @jacobian exp x@ is the jacobian of exp w.r.t. x
+jacobian :: MX -> MX -> MX
+jacobian x y = unsafePerformIO (C.jacobian__0 x y)
+{-# NOINLINE jacobian #-}
+
+expand :: Vector MX -> Vector MX
+expand x = unsafePerformIO (C.matrix_expand__0 x)
+{-# NOINLINE expand #-}
+
+solve :: MX -> MX -> MX
+solve a b = unsafePerformIO (C.solve__0 a b)
+{-# NOINLINE solve #-}
+
+---- | @hessian exp x@ is the jacobian of exp w.r.t. x
+--hessian :: MX -> MX -> MX
+--hessian x y = unsafePerformIO (C.hessian x y)
+--{-# NOINLINE hessian #-}
+
+d2m :: DMatrix -> MX
+d2m x = unsafePerformIO (mx__0 x)
+{-# NOINLINE d2m #-}
+
+-- | matrix matrix product
+mm :: MX -> MX -> MX
+mm x y = unsafePerformIO (mx_mul__0 x y)
+{-# NOINLINE mm #-}
+
+-- | transpose
+trans :: MX -> MX
+trans x = unsafePerformIO (mx_trans x)
+{-# NOINLINE trans #-}
+
+dense :: MX -> MX
+dense x = unsafePerformIO (C.dense__0 x)
+{-# NOINLINE dense #-}
+
+--sparse :: MX -> MX
+--sparse x = unsafePerformIO (C.sparse x)
+--{-# NOINLINE sparse #-}
+
+triu :: MX -> MX
+triu x = unsafePerformIO (C.triu__2 (castMX x))
+{-# NOINLINE triu #-}
+
+tril :: MX -> MX
+tril x = unsafePerformIO (C.tril__2 (castMX x))
+{-# NOINLINE tril #-}
+
+diag :: MX -> MX
+diag x = unsafePerformIO (C.diag__0 x)
+{-# NOINLINE diag #-}
+
+crs :: MX -> Sparsity
+crs x = unsafePerformIO (mx_sparsityRef__0 x)
+{-# NOINLINE crs #-}
+
+-- | from MXElement vector
+size :: MX -> Int
+size x = unsafePerformIO (mx_size__1 x)
+{-# NOINLINE size #-}
+
+size1 :: MX -> Int
+size1 x = unsafePerformIO (mx_size1 x)
+{-# NOINLINE size1 #-}
+
+size2 :: MX -> Int
+size2 x = unsafePerformIO (mx_size2 x)
+{-# NOINLINE size2 #-}
+
+numel :: MX -> Int
+numel x = unsafePerformIO (mx_numel x)
+{-# NOINLINE numel #-}
+
+vertcat :: V.Vector MX -> MX
+vertcat x = unsafePerformIO (C.vertcat__0 x)
+{-# NOINLINE vertcat #-}
+
+veccat :: V.Vector MX -> MX
+veccat x = unsafePerformIO (C.veccat__0 x)
+{-# NOINLINE veccat #-}
+
+vertsplit :: MX -> V.Vector Int -> V.Vector MX
+vertsplit x ks = unsafePerformIO (C.vertsplit__2 x ks)
+{-# NOINLINE vertsplit #-}
+
+horzsplit :: MX -> V.Vector Int -> V.Vector MX
+horzsplit x ks = unsafePerformIO (C.horzsplit__2 x ks)
+{-# NOINLINE horzsplit #-}
+
+horzcat :: V.Vector MX -> MX
+horzcat x = unsafePerformIO (C.horzcat__0 x)
+{-# NOINLINE horzcat #-}
+
+ones :: (Int,Int) -> MX
+ones (r,c) = unsafePerformIO (mx_ones__3 r c)
+{-# NOINLINE ones #-}
+
+zeros :: (Int,Int) -> MX
+zeros (r,c) = unsafePerformIO (mx_zeros__3 r c)
+{-# NOINLINE zeros #-}
+
+instance Num MX where
+  (+) x y = unsafePerformIO (mx___add__ x y)
+  {-# NOINLINE (+) #-}
+  (-) x y = unsafePerformIO (mx___sub__ x y)
+  {-# NOINLINE (-) #-}
+  (*) x y = unsafePerformIO (mx___mul__ x y)
+  {-# NOINLINE (*) #-}
+  fromInteger x = unsafePerformIO (mx__3 (fromInteger x :: Double))
+  {-# NOINLINE fromInteger #-}
+  abs x = unsafePerformIO (mx_fabs x)
+  {-# NOINLINE abs #-}
+  signum x = unsafePerformIO (mx_sign x)
+  {-# NOINLINE signum #-}
+
+instance Fractional MX where
+  (/) x y = unsafePerformIO (mx___truediv____0 x y)
+  {-# NOINLINE (/) #-}
+  fromRational x = unsafePerformIO (mx__3 (fromRational x :: Double))
+  {-# NOINLINE fromRational #-}
+
+instance Floating MX where
+  pi = unsafePerformIO (mx__3 (pi :: Double))
+  {-# NOINLINE pi #-}
+  (**) x y = unsafePerformIO (mx___pow__ x y)
+  {-# NOINLINE (**) #-}
+  exp x   = unsafePerformIO (mx_exp x)
+  {-# NOINLINE exp #-}
+  log x   = unsafePerformIO (mx_log x)
+  {-# NOINLINE log #-}
+  sin x   = unsafePerformIO (mx_sin x)
+  {-# NOINLINE sin #-}
+  cos x   = unsafePerformIO (mx_cos x)
+  {-# NOINLINE cos #-}
+  tan x   = unsafePerformIO (mx_tan x)
+  {-# NOINLINE tan #-}
+  asin x  = unsafePerformIO (mx_arcsin x)
+  {-# NOINLINE asin #-}
+  atan x  = unsafePerformIO (mx_arctan x)
+  {-# NOINLINE atan #-}
+  acos x  = unsafePerformIO (mx_arccos x)
+  {-# NOINLINE acos #-}
+  sinh x  = unsafePerformIO (mx_sinh x)
+  {-# NOINLINE sinh #-}
+  cosh x  = unsafePerformIO (mx_cosh x)
+  {-# NOINLINE cosh #-}
+  tanh x  = unsafePerformIO (mx_tanh x)
+  {-# NOINLINE tanh #-}
+  asinh x = unsafePerformIO (mx_arcsinh x)
+  {-# NOINLINE asinh #-}
+  atanh x = unsafePerformIO (mx_arctanh x)
+  {-# NOINLINE atanh #-}
+  acosh x = unsafePerformIO (mx_arccosh x)
+  {-# NOINLINE acosh #-}
+
+instance Fmod MX where
+  fmod x y = unsafePerformIO (mx_fmod x y)
+  {-# NOINLINE fmod #-}
+
+instance ArcTan2 MX where
+  arctan2 x y = unsafePerformIO (mx_arctan2 x y)
+  {-# NOINLINE arctan2 #-}
+
+instance SymOrd MX where
+  x `leq` y = unsafePerformIO (mx___le__ x y)
+  {-# NOINLINE leq #-}
+  x `geq` y = unsafePerformIO (mx___ge__ x y)
+  {-# NOINLINE geq #-}
+  x  `eq` y = unsafePerformIO (mx___eq__ x y)
+  {-# NOINLINE eq #-}
+
diff --git a/src/Casadi/MXFunction.hs b/src/Casadi/MXFunction.hs
new file mode 100644
--- /dev/null
+++ b/src/Casadi/MXFunction.hs
@@ -0,0 +1,13 @@
+{-# OPTIONS_GHC -Wall #-}
+
+module Casadi.MXFunction
+       ( C.MXFunction, mxFunction
+       ) where
+
+import Data.Vector ( Vector )
+
+import qualified Casadi.Core.Classes.MXFunction as C
+import Casadi.MX ( MX )
+
+mxFunction :: Vector MX -> Vector MX -> IO C.MXFunction
+mxFunction = C.mxFunction__0
diff --git a/src/Casadi/Option.hs b/src/Casadi/Option.hs
new file mode 100644
--- /dev/null
+++ b/src/Casadi/Option.hs
@@ -0,0 +1,30 @@
+{-# OPTIONS_GHC -Wall #-}
+{-# Language GADTs #-}
+
+module Casadi.Option
+       ( Opt(..)
+       , GenericC(..)
+       , setOption
+       , getOption
+       ) where
+
+import Casadi.Core.Classes.OptionsFunctionality
+  ( OptionsFunctionalityClass, optionsFunctionality_setOption,
+    optionsFunctionality_hasOption, optionsFunctionality_getOption)
+import Casadi.GenericC
+
+data Opt where
+  Opt :: GenericC a => a -> Opt
+
+setOption :: (OptionsFunctionalityClass a, GenericC b) => a -> String -> b -> IO ()
+setOption f name val = do
+  gval <- mkGeneric val
+  optionsFunctionality_setOption f name gval
+
+getOption :: (OptionsFunctionalityClass a, GenericC b) => a -> String -> IO (Maybe b)
+getOption f name = do
+  has <- optionsFunctionality_hasOption f name
+  if has
+    then optionsFunctionality_getOption f name >>= fromGeneric
+    else return Nothing
+
diff --git a/src/Casadi/Overloading.hs b/src/Casadi/Overloading.hs
new file mode 100644
--- /dev/null
+++ b/src/Casadi/Overloading.hs
@@ -0,0 +1,38 @@
+{-# OPTIONS_GHC -Wall #-}
+
+module Casadi.Overloading
+       ( Fmod(..)
+       , ArcTan2(..)
+       , SymOrd(..)
+       ) where
+
+import Data.Fixed ( mod' )
+
+-- | doesn't require Real, used for overloading symbolics
+class Fmod a where
+  fmod :: a -> a -> a
+
+instance Fmod Double where fmod = mod'
+instance Fmod Float where fmod = mod'
+
+-- | doesn't require RealFloat, used for overloading symbolics
+class ArcTan2 a where
+  arctan2 :: a -> a -> a
+
+instance ArcTan2 Double where arctan2 = atan2
+instance ArcTan2 Float where arctan2 = atan2
+
+-- | Ord, but returns a 1 or a 0 instead of True or False
+class SymOrd a where
+  leq :: a -> a -> a
+  geq :: a -> a -> a
+  eq :: a -> a -> a
+
+instance SymOrd Double where
+  x `leq` y = if x <= y then 1 else 0
+  x `geq` y = if x >= y then 1 else 0
+  x  `eq` y = if x == y then 1 else 0
+instance SymOrd Float where
+  x `leq` y = if x <= y then 1 else 0
+  x `geq` y = if x >= y then 1 else 0
+  x  `eq` y = if x == y then 1 else 0
diff --git a/src/Casadi/SX.hs b/src/Casadi/SX.hs
new file mode 100644
--- /dev/null
+++ b/src/Casadi/SX.hs
@@ -0,0 +1,219 @@
+{-# OPTIONS_GHC -Wall -fno-cse -fno-warn-orphans #-}
+
+module Casadi.SX
+       ( SX(), ssym, ssymV, ssymM, smm, strans
+       , sgradient, sjacobian, shessian, svector, sdiag
+       , ssolve
+       , sdata
+       , striu
+       , stril
+       , sdense, ssparse
+       , d2s
+       , ssize, ssize1, ssize2, snumel
+       , scrs, svertcat, shorzcat, sveccat, svertsplit, shorzsplit
+       , sones, szeros
+       ) where
+
+import qualified Data.Vector as V
+import System.IO.Unsafe ( unsafePerformIO )
+import Linear.Conjugate ( Conjugate(..) )
+
+import Casadi.Core.Classes.SXElement ( SXElement )
+import Casadi.Core.Classes.SX
+import Casadi.Core.Classes.DMatrix ( DMatrix )
+import Casadi.Core.Classes.Sparsity ( Sparsity )
+import qualified Casadi.Core.Tools as C
+
+import Casadi.Overloading ( Fmod(..), ArcTan2(..), SymOrd(..) )
+
+instance Conjugate SX where
+  conjugate = id
+
+ssym :: String -> IO SX
+ssym = sx_sym__5
+
+ssymV :: String -> Int -> IO SX
+ssymV = sx_sym__6
+
+ssymM :: String -> Int -> Int -> IO SX
+ssymM = sx_sym__7
+
+-- | @jacobian exp x@ is the jacobian of exp w.r.t. x
+sgradient :: SX -> SX -> SX
+sgradient x y = unsafePerformIO (C.gradient__1 x y)
+{-# NOINLINE sgradient #-}
+
+-- | @jacobian exp x@ is the jacobian of exp w.r.t. x
+sjacobian :: SX -> SX -> SX
+sjacobian x y = unsafePerformIO (C.jacobian__1 x y)
+{-# NOINLINE sjacobian #-}
+
+-- | @hessian exp x@ is the hessian of exp w.r.t. x
+shessian :: SX -> SX -> SX
+shessian x y = unsafePerformIO (C.hessian__1 x y)
+{-# NOINLINE shessian #-}
+
+-- | matrix matrix product
+smm :: SX -> SX -> SX
+smm x y = unsafePerformIO (sx_mul__0 x y)
+{-# NOINLINE smm #-}
+
+d2s :: DMatrix -> SX
+d2s x = unsafePerformIO (sx__2 x)
+{-# NOINLINE d2s #-}
+
+sdiag :: SX -> SX
+sdiag x = unsafePerformIO (C.diag__1 x)
+{-# NOINLINE sdiag #-}
+
+-- | transpose
+strans :: SX -> SX
+strans x = unsafePerformIO (sx_trans x)
+{-# NOINLINE strans #-}
+
+sdense :: SX -> SX
+sdense x = unsafePerformIO (C.dense__1 x)
+{-# NOINLINE sdense #-}
+
+ssparse :: SX -> SX
+ssparse x = unsafePerformIO (C.sparse__0 x)
+{-# NOINLINE ssparse #-}
+
+striu :: SX -> SX
+striu x = unsafePerformIO (C.triu__3 (castSX x))
+{-# NOINLINE striu #-}
+
+stril :: SX -> SX
+stril x = unsafePerformIO (C.tril__3 (castSX x))
+{-# NOINLINE stril #-}
+
+scrs :: SX -> Sparsity
+scrs x = unsafePerformIO (sx_sparsityRef__0 x)
+{-# NOINLINE scrs #-}
+
+-- | from SXElement vector
+svector :: V.Vector SXElement -> SX
+svector x = unsafePerformIO (sx__7 x)
+{-# NOINLINE svector #-}
+
+sdata :: SX -> V.Vector SXElement
+sdata x = unsafePerformIO (sx_data__0 x)
+{-# NOINLINE sdata #-}
+
+ssize :: SX -> Int
+ssize x = unsafePerformIO (sx_size__1 x)
+{-# NOINLINE ssize #-}
+
+ssize1 :: SX -> Int
+ssize1 x = unsafePerformIO (sx_size1 x)
+{-# NOINLINE ssize1 #-}
+
+ssize2 :: SX -> Int
+ssize2 x = unsafePerformIO (sx_size2 x)
+{-# NOINLINE ssize2 #-}
+
+snumel :: SX -> Int
+snumel x = unsafePerformIO (sx_numel x)
+{-# NOINLINE snumel #-}
+
+svertcat :: V.Vector SX -> SX
+svertcat x = unsafePerformIO (C.vertcat__2 x)
+{-# NOINLINE svertcat #-}
+
+shorzcat :: V.Vector SX -> SX
+shorzcat x = unsafePerformIO (C.horzcat__2 x)
+{-# NOINLINE shorzcat #-}
+
+sveccat :: V.Vector SX -> SX
+sveccat x = unsafePerformIO (C.veccat__1 x)
+{-# NOINLINE sveccat #-}
+
+svertsplit :: SX -> V.Vector Int -> V.Vector SX
+svertsplit x ks = unsafePerformIO (C.vertsplit__6 x ks)
+{-# NOINLINE svertsplit #-}
+
+shorzsplit :: SX -> V.Vector Int -> V.Vector SX
+shorzsplit x ks = unsafePerformIO (C.horzsplit__6 x ks)
+{-# NOINLINE shorzsplit #-}
+
+ssolve :: SX -> SX -> SX
+ssolve a b = unsafePerformIO (C.solve__2 a b)
+{-# NOINLINE ssolve #-}
+
+sones :: (Int,Int) -> SX
+sones (r,c) = unsafePerformIO (sx_ones__3 r c)
+{-# NOINLINE sones #-}
+
+szeros :: (Int,Int) -> SX
+szeros (r,c) = unsafePerformIO (sx_zeros__3 r c)
+{-# NOINLINE szeros #-}
+
+instance Num SX where
+  (+) x y = unsafePerformIO (sx___add__ x y)
+  {-# NOINLINE (+) #-}
+  (-) x y = unsafePerformIO (sx___sub__ x y)
+  {-# NOINLINE (-) #-}
+  (*) x y = unsafePerformIO (sx___mul__ x y)
+  {-# NOINLINE (*) #-}
+  fromInteger x = unsafePerformIO (sx__8 (fromInteger x :: Double))
+  {-# NOINLINE fromInteger #-}
+  abs x = unsafePerformIO (sx_fabs x)
+  {-# NOINLINE abs #-}
+  signum x = unsafePerformIO (sx_sign x)
+  {-# NOINLINE signum #-}
+
+instance Fractional SX where
+  (/) x y = unsafePerformIO (sx___truediv____0 x y)
+  {-# NOINLINE (/) #-}
+  fromRational x = unsafePerformIO (sx__8 (fromRational x :: Double))
+  {-# NOINLINE fromRational #-}
+
+instance Floating SX where
+  pi = unsafePerformIO (sx__8 (pi :: Double))
+  {-# NOINLINE pi #-}
+  (**) x y = unsafePerformIO (sx___pow__ x y)
+  {-# NOINLINE (**) #-}
+  exp x   = unsafePerformIO (sx_exp x)
+  {-# NOINLINE exp #-}
+  log x   = unsafePerformIO (sx_log x)
+  {-# NOINLINE log #-}
+  sin x   = unsafePerformIO (sx_sin x)
+  {-# NOINLINE sin #-}
+  cos x   = unsafePerformIO (sx_cos x)
+  {-# NOINLINE cos #-}
+  tan x   = unsafePerformIO (sx_tan x)
+  {-# NOINLINE tan #-}
+  asin x  = unsafePerformIO (sx_arcsin x)
+  {-# NOINLINE asin #-}
+  atan x  = unsafePerformIO (sx_arctan x)
+  {-# NOINLINE atan #-}
+  acos x  = unsafePerformIO (sx_arccos x)
+  {-# NOINLINE acos #-}
+  sinh x  = unsafePerformIO (sx_sinh x)
+  {-# NOINLINE sinh #-}
+  cosh x  = unsafePerformIO (sx_cosh x)
+  {-# NOINLINE cosh #-}
+  tanh x  = unsafePerformIO (sx_tanh x)
+  {-# NOINLINE tanh #-}
+  asinh x = unsafePerformIO (sx_arcsinh x)
+  {-# NOINLINE asinh #-}
+  atanh x = unsafePerformIO (sx_arctanh x)
+  {-# NOINLINE atanh #-}
+  acosh x = unsafePerformIO (sx_arccosh x)
+  {-# NOINLINE acosh #-}
+
+instance Fmod SX where
+  fmod x y = unsafePerformIO (sx_fmod x y)
+  {-# NOINLINE fmod #-}
+
+instance ArcTan2 SX where
+  arctan2 x y = unsafePerformIO (sx_arctan2 x y)
+  {-# NOINLINE arctan2 #-}
+
+instance SymOrd SX where
+  x `leq` y = unsafePerformIO (sx___le__ x y)
+  {-# NOINLINE leq #-}
+  x `geq` y = unsafePerformIO (sx___ge____0 x y)
+  {-# NOINLINE geq #-}
+  x  `eq` y = unsafePerformIO (sx___eq__ x y)
+  {-# NOINLINE eq #-}
diff --git a/src/Casadi/SXElement.hs b/src/Casadi/SXElement.hs
new file mode 100644
--- /dev/null
+++ b/src/Casadi/SXElement.hs
@@ -0,0 +1,90 @@
+{-# OPTIONS_GHC -Wall -fno-cse -fno-warn-orphans #-}
+
+module Casadi.SXElement
+       ( SXElement(), sxElement_sym
+       ) where
+
+--import qualified Data.Vector as V
+import System.IO.Unsafe ( unsafePerformIO )
+import Linear.Conjugate ( Conjugate(..) )
+
+import Casadi.Core.Classes.SXElement
+
+--import Casadi.SX ( svector )
+import Casadi.Overloading ( Fmod(..), ArcTan2(..), SymOrd(..) )
+
+--instance Show SXElement where
+--  show = show . svector . V.singleton
+
+instance Conjugate SXElement where
+  conjugate = id
+
+instance Num SXElement where
+  (+) x y = unsafePerformIO (sxElement___add__ x y)
+  {-# NOINLINE (+) #-}
+  (-) x y = unsafePerformIO (sxElement___sub__ x y)
+  {-# NOINLINE (-) #-}
+  (*) x y = unsafePerformIO (sxElement___mul__ x y)
+  {-# NOINLINE (*) #-}
+  abs x = unsafePerformIO (sxElement_fabs x)
+  {-# NOINLINE abs #-}
+  signum x = unsafePerformIO (sxElement_sign x)
+  {-# NOINLINE signum #-}
+  fromInteger x = unsafePerformIO (sxElement__0 (fromInteger x :: Double))
+  {-# NOINLINE fromInteger #-}
+
+instance Fractional SXElement where
+  (/) x y = unsafePerformIO (sxElement___truediv____0 x y)
+  {-# NOINLINE (/) #-}
+  fromRational x = unsafePerformIO (sxElement__0 (fromRational x :: Double))
+  {-# NOINLINE fromRational #-}
+
+instance Floating SXElement where
+  pi = unsafePerformIO (sxElement__0 (pi :: Double))
+  {-# NOINLINE pi #-}
+  (**) x y = unsafePerformIO (sxElement___pow__ x y)
+  {-# NOINLINE (**) #-}
+  exp x   = unsafePerformIO (sxElement_exp x)
+  {-# NOINLINE exp #-}
+  log x   = unsafePerformIO (sxElement_log x)
+  {-# NOINLINE log #-}
+  sin x   = unsafePerformIO (sxElement_sin x)
+  {-# NOINLINE sin #-}
+  cos x   = unsafePerformIO (sxElement_cos x)
+  {-# NOINLINE cos #-}
+  tan x   = unsafePerformIO (sxElement_tan x)
+  {-# NOINLINE tan #-}
+  asin x  = unsafePerformIO (sxElement_arcsin x)
+  {-# NOINLINE asin #-}
+  atan x  = unsafePerformIO (sxElement_arctan x)
+  {-# NOINLINE atan #-}
+  acos x  = unsafePerformIO (sxElement_arccos x)
+  {-# NOINLINE acos #-}
+  sinh x  = unsafePerformIO (sxElement_sinh x)
+  {-# NOINLINE sinh #-}
+  cosh x  = unsafePerformIO (sxElement_cosh x)
+  {-# NOINLINE cosh #-}
+  tanh x  = unsafePerformIO (sxElement_tanh x)
+  {-# NOINLINE tanh #-}
+  asinh x = unsafePerformIO (sxElement_arcsinh x)
+  {-# NOINLINE asinh #-}
+  atanh x = unsafePerformIO (sxElement_arctanh x)
+  {-# NOINLINE atanh #-}
+  acosh x = unsafePerformIO (sxElement_arccosh x)
+  {-# NOINLINE acosh #-}
+
+instance Fmod SXElement where
+  fmod x y = unsafePerformIO (sxElement_fmod x y)
+  {-# NOINLINE fmod #-}
+
+instance ArcTan2 SXElement where
+  arctan2 x y = unsafePerformIO (sxElement_arctan2__1 x y)
+  {-# NOINLINE arctan2 #-}
+
+instance SymOrd SXElement where
+  x `leq` y = unsafePerformIO (sxElement___le__ x y)
+  {-# NOINLINE leq #-}
+  x `geq` y = unsafePerformIO (sxElement___ge__ x y)
+  {-# NOINLINE geq #-}
+  x  `eq` y = unsafePerformIO (sxElement___eq__ x y)
+  {-# NOINLINE eq #-}
diff --git a/src/Casadi/SXFunction.hs b/src/Casadi/SXFunction.hs
new file mode 100644
--- /dev/null
+++ b/src/Casadi/SXFunction.hs
@@ -0,0 +1,13 @@
+{-# OPTIONS_GHC -Wall #-}
+
+module Casadi.SXFunction
+       ( C.SXFunction, sxFunction
+       ) where
+
+import Data.Vector ( Vector )
+
+import qualified Casadi.Core.Classes.SXFunction as C
+import Casadi.SX ( SX )
+
+sxFunction :: Vector SX -> Vector SX -> IO C.SXFunction
+sxFunction = C.sxFunction__0
diff --git a/src/Casadi/SharedObject.hs b/src/Casadi/SharedObject.hs
new file mode 100644
--- /dev/null
+++ b/src/Casadi/SharedObject.hs
@@ -0,0 +1,10 @@
+{-# OPTIONS_GHC -Wall #-}
+
+module Casadi.SharedObject
+       ( soInit
+       ) where
+
+import qualified Casadi.Core.Classes.SharedObject as C
+
+soInit :: C.SharedObjectClass a => a -> IO ()
+soInit = C.sharedObject_init__0
