packages feed

mfsolve 0.2.0 → 0.3.0

raw patch · 2 files changed

+103/−69 lines, 2 files

Files

Math/MFSolve.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE DeriveGeneric, PatternGuards, PatternSynonyms, MultiParamTypeClasses, FlexibleContexts, DeriveDataTypeable #-}+{-# LANGUAGE DeriveGeneric, PatternGuards, PatternSynonyms, MultiParamTypeClasses, FlexibleContexts, DeriveDataTypeable, GeneralizedNewtypeDeriving #-}  {-| Module      : Math.MFSolve@@ -23,7 +23,8 @@ === Examples:  Let's define some variables.  The `SimpleVar` type is a simple wrapper-around `String` to provide nice output.+around `String` to provide nice output, since the Show instance for+`String` outputs quotation marks.  > let [x, y, t, a] = map (makeVariable . SimpleVar) ["x", "y", "t", "a"] @@ -76,26 +77,35 @@ -}  module Math.MFSolve-       (-- * Types-        MFSolver, SimpleExpr(..), Expr, LinExpr(..), UnaryOp(..), BinaryOp(..),-        Dependencies, DepError(..), SimpleVar(..),-        -- * Expressions-        evalSimple, evalExpr, fromSimple, toSimple, makeVariable,-        makeConstant, hasVar, +       (-- * Expressions+        SimpleExpr(..), Expr, LinExpr(..), UnaryOp(..), BinaryOp(..),+        SimpleVar(..),+        makeVariable,+        makeConstant, evalExpr, fromSimple, toSimple, evalSimple, hasVar,          -- * Dependencies+        Dependencies, DepError(..), +        noDeps, addEquation, eliminate,         getKnown, knownVars, varDefined, nonlinearEqs, dependendVars,-        noDeps, -        eliminate, addEquation,         -- * Monadic Interface-        dependencies, getValue, getKnownM, varDefinedM, eliminateM,-        (=&=), (===), ignore,  -        runSolver, evalSolver, execSolver, unsafeSolve, showVars)+        (===), (=&=), dependencies, getValue, getKnownM,+        varDefinedM, eliminateM, ignore,+        -- * MFSolver monad+        MFSolver, +        runSolver, evalSolver, execSolver, unsafeSolve, showVars,+        -- * MFSolverT monad transformer+        MFSolverT, +        runSolverT, evalSolverT, execSolverT, unsafeSolveT) where import qualified Data.HashMap.Strict as M import qualified Data.HashSet as H import GHC.Generics import Control.Monad.Except import Control.Monad.State+import Control.Monad.Reader+import Control.Monad.Writer+import Control.Monad.Identity+import Control.Monad.RWS+import Control.Monad.Cont import Control.Exception import Data.Typeable import Control.Applicative hiding (Const)@@ -112,7 +122,8 @@   Tan | Sinh | Asin | Acos | Asinh | Acosh | Atan   deriving (Eq, Generic) --- | A simplified datatype representing an expression+-- | A simplified datatype representing an expression.  This can be+-- used to inspect the structure of a `Expr`, which is hidden. data SimpleExpr v n =   SEBin BinaryOp (SimpleExpr v n) (SimpleExpr v n) |   SEUn UnaryOp (SimpleExpr v n) |@@ -122,7 +133,9 @@ newtype SimpleVar = SimpleVar String                   deriving (Eq, Ord, Generic) --- | An mathematical expression of several variables.+-- | A mathematical expression of several variables. Several Numeric+-- instances (`Num`, `Floating` and `Fractional`) are provided, so+-- doing calculations over `Expr` is more convenient. data Expr v n = Expr (LinExpr v n) [TrigTerm v n] [NonLinExpr v n]                 deriving (Generic) @@ -170,13 +183,20 @@ instance Show SimpleVar where   show (SimpleVar s) = s --- | An opaque datatype containing the dependencies of each variable.--- A variable who's dependency is just a number is called /known/.  A--- variables which depends on other variables is called /dependend/.--- A variable which is neither known or dependend is called--- /independend/.  A variable can only depend on other /independend/--- variables.  It also contains nonlinear equations which it couldn't--- reduce to a linear equation yet.+-- | This hidden datatype represents a system of equations.  It+-- contains linear dependencies on variables as well as nonlinear+-- equations. The following terminology is used from /metafont/:+-- +--   * /known variable/: A variable who's dependency is just a number.+--   +--   * /dependend variable/: A variable which depends linearly on other variables.+--+--   * /independend variable/: any other variable.+--+-- A /dependend/ variable can only depend on other /independend/+-- variables.  Nonlinear equations will be simplified by substituting+-- and evaluating known variables, or by reducing some trigonometric+-- equations to linear equations. data Dependencies v n = Dependencies                         (M.HashMap v (H.HashSet v))                         (LinearMap v n)@@ -184,18 +204,18 @@                         (TrigEq2 v n)                         [Expr v n]                         --- | An error type for '===', '=&=' and 'solveEq':+-- | An error type for '===', '=&=' and 'addEquation': data DepError v n =-  -- | 'UndefinedVar' @v@: The variable is not defined.+  -- | The variable is not defined.   UndefinedVar v |-  -- | 'UnknownVar' @v@: The variable is defined but dependend an other variables.+  -- | The variable is defined but dependend an other variables.   UnknownVar v n |-  -- | 'InconsistentEq' @a@: The equation was reduced to the+  -- | The equation was reduced to the   -- impossible equation `a == 0` for nonzero a, which means the   -- equation is inconsistent with previous equations.   InconsistentEq n |-  -- | 'RedundantEq': The equation was reduced to the redundant equation 0 == 0, which-  -- means it doesn't add any information.+  -- | The equation was reduced to the redundant equation `0 == 0`,+  -- which means it doesn't add any information.   RedundantEq   deriving Typeable @@ -204,37 +224,20 @@ instance (Ord n, Num n, Eq n, Show v, Show n) => Show (Expr v n) where   show e = show (toSimple e) --- | A monad for solving equations.  Basicly just a state and exception monad.-newtype MFSolver v n a = MFSolver {-  -- | Unwrap a solver monad as a function.-  runSolver :: Dependencies v n -> Either (DepError v n) (Dependencies v n, a) }--instance Monad (MFSolver v n) where-  MFSolver s >>= f = MFSolver $ \dep ->-    case s dep of-     Left err -> Left err-     Right (dep2, val) ->-       runSolver (f val) dep2-  return a = MFSolver $ \dep -> Right (dep, a)+-- | A monad transformer for solving equations.  Basicly just a state and exception monad transformer over `Dependencies` and `DepError`.+newtype MFSolverT v n m a = MFSolverT (StateT (Dependencies v n) (ExceptT (DepError v n) m) a)+                            deriving (Functor, Applicative, Monad, MonadIO, MonadState (Dependencies v n),+                                      MonadError (DepError v n), MonadReader s, MonadWriter s,+                                      MonadCont) -instance (MonadState (Dependencies v n)) (MFSolver v n) where-  get = MFSolver $ \dep -> Right (dep, dep)-  put dep = MFSolver $ const $ Right (dep, ())-           -instance (MonadError (DepError v n)) (MFSolver v n) where-  throwError e = MFSolver $ const $ Left e-  catchError s h = MFSolver $ \dep ->-    case runSolver s dep of-     Left e -> runSolver (h e) dep-     v -> v+instance MonadTrans (MFSolverT v n) where+  lift = MFSolverT . lift. lift -instance Functor (MFSolver v n) where-  fmap f s = MFSolver $ \dep ->-    fmap f <$> runSolver s dep +runSolverT :: MFSolverT v n m a -> Dependencies v n -> m (Either (DepError v n) (a, Dependencies v n))+runSolverT (MFSolverT s) = runExceptT . runStateT s  -instance Applicative (MFSolver v n) where-  (<*>) = ap-  pure = return+-- | A monad for solving equations.  Basicly just a state and exception monad over `Dependencies` and `DepError`.+type MFSolver v n a = MFSolverT v n Identity a  withParens :: (Show t1, Show t, Ord t1, Num t1, Eq t1) => SimpleExpr t t1 -> [BinaryOp] -> String withParens e@(SEBin op _ _) ops@@ -596,7 +599,7 @@   foldr ((+).substVarTrig s) 0 trig +   foldr ((+).substVarNonLin s) 0 nl --- | An empty set of dependencies.+-- | An empty system of equations. noDeps :: Dependencies v n noDeps = Dependencies M.empty M.empty [] M.empty [] @@ -618,7 +621,7 @@ addEqs :: (Hashable v, Hashable n, RealFrac (Phase n), Ord v, Floating n) => Dependencies v n -> [Expr v n] -> Either (DepError v n) (Dependencies v n) addEqs = foldM addEquation --- | @addEquation e d@: Add the equation @e = 0@ to the system d.+-- | @addEquation d e@: Add the equation @e = 0@ to the system d. addEquation :: (Hashable n, Hashable v, RealFrac (Phase n), Ord v,           Floating n) =>          Dependencies v n@@ -796,6 +799,9 @@ -- | Eliminate an variable from the equations.  Returns the eliminated -- equations.  Before elimination it performs substitution to minimize -- the number of eliminated equations.+-- +--__Important__: this function is+-- still experimental and mostly untested. eliminate :: (Hashable n, Show n, Hashable v, RealFrac (Phase n), Ord v, Show v,               Floating n) => Dependencies v n -> v -> (Dependencies v n, [Expr v n]) eliminate (Dependencies vdep lin trig trig2 nonlin) v@@ -1028,18 +1034,46 @@   \e -> case e of          RedundantEq -> return ()          _ -> throwError e)-  ++-- | run the solver.+runSolver :: MFSolver v n a -> Dependencies v n -> Either (DepError v n) (a, Dependencies v n)+runSolver s = runIdentity . runSolverT s+           +-- | Return the result of solving the equations, or throw the error as an exception.  Monadic version.+unsafeSolveT :: (Show n, Show v, Typeable n, Typeable v, Monad m) =>+                Dependencies v n -> MFSolverT v n m a -> m a+unsafeSolveT dep s = do+  res <- runSolverT s dep+  case res of+   Right (v, _) -> return v+   Left e -> throw e++-- | Return the result of solving the equations or an error.  Monadic version.+evalSolverT :: Functor f =>+               MFSolverT v n f b+            -> Dependencies v n -> f (Either (DepError v n) b)+evalSolverT s dep =+  fmap fst <$> runSolverT s dep ++-- | Run the solver and return the dependencies or an error.  Monadic version.+execSolverT :: Functor m =>+               MFSolverT v n m a+            -> Dependencies v n -> m (Either (DepError v n) (Dependencies v n))+execSolverT s dep =+  fmap snd <$> runSolverT s dep+ -- | Return the result of solving the equations, or throw the error as an exception.-unsafeSolve :: (Typeable n, Typeable v, Show n, Show v) => MFSolver v n a -> Dependencies v n -> a-unsafeSolve s dep = case runSolver s dep of-  Right (_, v) -> v-  Left e -> throw e+unsafeSolve :: (Typeable n, Typeable v, Show n, Show v) =>+               Dependencies v n -> MFSolver v n a -> a+unsafeSolve dep = runIdentity . unsafeSolveT dep  -- | Return the result of solving the equations or an error.-evalSolver :: MFSolver v n a -> Dependencies v n -> Either (DepError v n) a-evalSolver s dep = snd <$> runSolver s dep +evalSolver :: MFSolver v n a+           -> Dependencies v n -> Either (DepError v n) a+evalSolver s = runIdentity . evalSolverT s  -- | Run the solver and return the dependencies or an error.-execSolver :: MFSolver v n a -> Dependencies v n -> -              Either (DepError v n) (Dependencies v n)-execSolver s dep = fst <$> runSolver s dep+execSolver :: MFSolver v n a+           -> Dependencies v n -> Either (DepError v n) (Dependencies v n)+execSolver s = runIdentity . execSolverT s+
mfsolve.cabal view
@@ -1,5 +1,5 @@ Name:		mfsolve-Version: 	0.2.0+Version: 	0.3.0 Synopsis:	Equation solver and calculator à la metafont Category: 	Math Copyright: 	Kristof Bastiaensen (2015)