lp-diagrams 2.0 → 2.0.0
raw patch · 11 files changed
+272/−300 lines, 11 filesdep +parsekdep +processdep −addep −nonlinear-optimizationsetup-changedPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: parsek, process
Dependencies removed: ad, nonlinear-optimization
API changes (from Hackage documentation)
- Algebra.AD: D :: !c -> !(Map v c) -> D v c
- Algebra.AD: E :: ((v -> D v c) -> D v c) -> E v c
- Algebra.AD: [dDerivs] :: D v c -> !(Map v c)
- Algebra.AD: [dValue] :: D v c -> !c
- Algebra.AD: [fromE] :: E v c -> (v -> D v c) -> D v c
- Algebra.AD: dVar :: forall v c. Ring c => v -> c -> D v c
- Algebra.AD: data D v c
- Algebra.AD: instance (Algebra.Classes.AbelianAdditive c, GHC.Classes.Ord v) => Algebra.Classes.AbelianAdditive (Algebra.AD.D v c)
- Algebra.AD: instance (Algebra.Classes.Field c, GHC.Classes.Ord v) => Algebra.Classes.Division (Algebra.AD.D v c)
- Algebra.AD: instance (Algebra.Classes.Field c, GHC.Classes.Ord v) => Algebra.Classes.Division (Algebra.AD.E v c)
- Algebra.AD: instance (GHC.Classes.Ord v, Algebra.Classes.Additive c) => Algebra.Classes.Additive (Algebra.AD.D v c)
- Algebra.AD: instance (GHC.Classes.Ord v, Algebra.Classes.Additive c) => Algebra.Classes.Additive (Algebra.AD.E v c)
- Algebra.AD: instance (GHC.Classes.Ord v, Algebra.Classes.Group c) => Algebra.Classes.Group (Algebra.AD.D v c)
- Algebra.AD: instance (GHC.Classes.Ord v, Algebra.Classes.Group c) => Algebra.Classes.Group (Algebra.AD.E v c)
- Algebra.AD: instance (GHC.Classes.Ord v, Algebra.Classes.Ring c) => Algebra.Classes.AbelianAdditive (Algebra.AD.E v c)
- Algebra.AD: instance (GHC.Classes.Ord v, Algebra.Classes.Ring c) => Algebra.Classes.Module (Algebra.AD.D v c) (Algebra.AD.D v c)
- Algebra.AD: instance (GHC.Classes.Ord v, Algebra.Classes.Ring c) => Algebra.Classes.Module (Algebra.AD.E v c) (Algebra.AD.E v c)
- Algebra.AD: instance (GHC.Classes.Ord v, Algebra.Classes.Ring c) => Algebra.Classes.Module c (Algebra.AD.D v c)
- Algebra.AD: instance (GHC.Classes.Ord v, Algebra.Classes.Ring c) => Algebra.Classes.Module c (Algebra.AD.E v c)
- Algebra.AD: instance (GHC.Classes.Ord v, Algebra.Classes.Ring c) => Algebra.Classes.Multiplicative (Algebra.AD.D v c)
- Algebra.AD: instance (GHC.Classes.Ord v, Algebra.Classes.Ring c) => Algebra.Classes.Multiplicative (Algebra.AD.E v c)
- Algebra.AD: instance (GHC.Classes.Ord v, Algebra.Classes.Ring c) => Algebra.Classes.Ring (Algebra.AD.D v c)
- Algebra.AD: instance (GHC.Classes.Ord v, Algebra.Classes.Ring c) => Algebra.Classes.Ring (Algebra.AD.E v c)
- Algebra.AD: instance (GHC.Show.Show v, GHC.Show.Show c) => GHC.Show.Show (Algebra.AD.AST v c)
- Algebra.AD: instance (GHC.Show.Show v, GHC.Show.Show c) => GHC.Show.Show (Algebra.AD.D v c)
- Algebra.AD: instance GHC.Classes.Eq c => GHC.Classes.Eq (Algebra.AD.D v c)
- Algebra.AD: instance GHC.Classes.Ord c => GHC.Classes.Ord (Algebra.AD.D v c)
- Algebra.AD: newtype E v c
- Algebra.AD: sqrtE :: forall t t1. (Floating t1, Ord t, Field t1) => E t t1 -> E t t1
- Algebra.AD: subst :: E v c -> (v -> E v c) -> E v c
- Algebra.AD: var :: (Multiplicative c, Additive c, Ord v) => v -> E v c
- Algebra.Linear: Func :: (Map v c) -> c -> LinFunc v c
- Algebra.Linear: clean :: (Eq v, Eq c, Ring c) => LinFunc v c -> LinFunc v c
- Algebra.Linear: data LinFunc v c
- Algebra.Linear: instance (Algebra.Classes.Additive c, GHC.Classes.Ord v) => Algebra.Classes.Additive (Algebra.Linear.LinFunc v c)
- Algebra.Linear: instance (GHC.Classes.Ord v, Algebra.Classes.AbelianAdditive c) => Algebra.Classes.AbelianAdditive (Algebra.Linear.LinFunc v c)
- Algebra.Linear: instance (GHC.Classes.Ord v, Algebra.Classes.Group c) => Algebra.Classes.Group (Algebra.Linear.LinFunc v c)
- Algebra.Linear: instance (GHC.Classes.Ord v, Algebra.Classes.Ring c) => Algebra.Classes.Module c (Algebra.Linear.LinFunc v c)
- Algebra.Linear: instance (GHC.Show.Show c, GHC.Show.Show v) => GHC.Show.Show (Algebra.Linear.LinFunc v c)
- Algebra.Linear: instance GHC.Base.Functor (Algebra.Linear.LinFunc v)
- Algebra.Linear: type Constraint v c = LinFunc v c
- Algebra.Linear: var :: Ring c => v -> LinFunc v c
- Algebra.Linear.GaussianElimination: linSolve :: (Eq c, Ord v, Field c) => [Constraint v c] -> [(v, LinFunc v c)]
- Graphics.Diagrams.Core: fromLinear :: Expr -> GExpr
- Graphics.Diagrams.Core: maximize' :: Monad m => GExpr -> Diagram lab m ()
- Graphics.Diagrams.Core: minimize' :: Monad m => GExpr -> Diagram lab m ()
- Graphics.Diagrams.Core: type Expr = LinFunc Var Constant
- Graphics.Diagrams.Core: type GExpr = E Var Constant
- Graphics.Diagrams.Point: dotProd :: forall a. (Ring a) => Point' a -> Point' a -> a
- Graphics.Diagrams.Point: norm :: Point' GExpr -> GExpr
- Graphics.Diagrams.Point: normalize :: Point' GExpr -> Point' GExpr
- Graphics.Diagrams.Point: sqNorm :: forall a. (Ring a) => Point' a -> a
+ Graphics.Diagrams.Core: absE :: IsDouble a => a -> a
+ Graphics.Diagrams.Core: data Expr
+ Graphics.Diagrams.Core: instance Algebra.Classes.AbelianAdditive Graphics.Diagrams.Core.Expr
+ Graphics.Diagrams.Core: instance Algebra.Classes.AbelianAdditive Graphics.Diagrams.Core.SExpr
+ Graphics.Diagrams.Core: instance Algebra.Classes.AbelianAdditive x => Algebra.Classes.AbelianAdditive (Graphics.Diagrams.Core.R env x)
+ Graphics.Diagrams.Core: instance Algebra.Classes.Additive Graphics.Diagrams.Core.Expr
+ Graphics.Diagrams.Core: instance Algebra.Classes.Additive Graphics.Diagrams.Core.SExpr
+ Graphics.Diagrams.Core: instance Algebra.Classes.Additive x => Algebra.Classes.Additive (Graphics.Diagrams.Core.R env x)
+ Graphics.Diagrams.Core: instance Algebra.Classes.Division Graphics.Diagrams.Core.SExpr
+ Graphics.Diagrams.Core: instance Algebra.Classes.Division x => Algebra.Classes.Division (Graphics.Diagrams.Core.R env x)
+ Graphics.Diagrams.Core: instance Algebra.Classes.Field Graphics.Diagrams.Core.SExpr
+ Graphics.Diagrams.Core: instance Algebra.Classes.Field x => Algebra.Classes.Field (Graphics.Diagrams.Core.R env x)
+ Graphics.Diagrams.Core: instance Algebra.Classes.Group Graphics.Diagrams.Core.Expr
+ Graphics.Diagrams.Core: instance Algebra.Classes.Group Graphics.Diagrams.Core.SExpr
+ Graphics.Diagrams.Core: instance Algebra.Classes.Group x => Algebra.Classes.Group (Graphics.Diagrams.Core.R env x)
+ Graphics.Diagrams.Core: instance Algebra.Classes.Module GHC.Real.Rational Graphics.Diagrams.Core.Expr
+ Graphics.Diagrams.Core: instance Algebra.Classes.Module Graphics.Diagrams.Types.Constant Graphics.Diagrams.Core.Expr
+ Graphics.Diagrams.Core: instance Algebra.Classes.Multiplicative Graphics.Diagrams.Core.SExpr
+ Graphics.Diagrams.Core: instance Algebra.Classes.Multiplicative x => Algebra.Classes.Multiplicative (Graphics.Diagrams.Core.R env x)
+ Graphics.Diagrams.Core: instance Algebra.Classes.Ring Graphics.Diagrams.Core.SExpr
+ Graphics.Diagrams.Core: instance Algebra.Classes.Ring x => Algebra.Classes.Ring (Graphics.Diagrams.Core.R env x)
+ Graphics.Diagrams.Core: instance Data.String.IsString Graphics.Diagrams.Core.SExpr
+ Graphics.Diagrams.Core: instance GHC.Base.Applicative (Graphics.Diagrams.Core.R env)
+ Graphics.Diagrams.Core: instance GHC.Base.Functor (Graphics.Diagrams.Core.R env)
+ Graphics.Diagrams.Core: instance Graphics.Diagrams.Core.IsDouble Graphics.Diagrams.Core.Expr
+ Graphics.Diagrams.Core: instance Graphics.Diagrams.Core.IsDouble Graphics.Diagrams.Core.SExpr
+ Graphics.Diagrams.Core: instance Graphics.Diagrams.Core.IsDouble Graphics.Diagrams.Types.Constant
+ Graphics.Diagrams.Core: instance Graphics.Diagrams.Core.IsDouble x => Graphics.Diagrams.Core.IsDouble (Graphics.Diagrams.Core.R env x)
+ Graphics.Diagrams.Point: orthonorm :: Point -> Expr
- Graphics.Diagrams.Core: (=~=) :: Monad m => GExpr -> GExpr -> Diagram lab m ()
+ Graphics.Diagrams.Core: (=~=) :: Monad m => Expr -> Expr -> Diagram lab m ()
- Graphics.Diagrams.Core: constant :: Constant -> Expr
+ Graphics.Diagrams.Core: constant :: Double -> Expr
- Graphics.Diagrams.Object: Object :: String -> Path -> Anchorage -> Object
+ Graphics.Diagrams.Object: Object :: !String -> !Path -> !Anchorage -> Object
- Graphics.Diagrams.Object: [anchors] :: Object -> Anchorage
+ Graphics.Diagrams.Object: [anchors] :: Object -> !Anchorage
- Graphics.Diagrams.Object: [objectName] :: Object -> String
+ Graphics.Diagrams.Object: [objectName] :: Object -> !String
- Graphics.Diagrams.Object: [objectOutline] :: Object -> Path
+ Graphics.Diagrams.Object: [objectOutline] :: Object -> !Path
- Graphics.Diagrams.Types: diaBackend :: forall lab_ajNx m_ajNy lab_ajTd m_ajTe. Lens (Env lab_ajNx m_ajNy) (Env lab_ajTd m_ajTe) (Backend lab_ajNx m_ajNy) (Backend lab_ajTd m_ajTe)
+ Graphics.Diagrams.Types: diaBackend :: forall lab_akJT m_akJU lab_akPz m_akPA. Lens (Env lab_akJT m_akJU) (Env lab_akPz m_akPA) (Backend lab_akJT m_akJU) (Backend lab_akPz m_akPA)
- Graphics.Diagrams.Types: diaPathOptions :: forall lab_ajNx m_ajNy. Lens' (Env lab_ajNx m_ajNy) PathOptions
+ Graphics.Diagrams.Types: diaPathOptions :: forall lab_akJT m_akJU. Lens' (Env lab_akJT m_akJU) PathOptions
- Graphics.Diagrams.Types: diaTightness :: forall lab_ajNx m_ajNy. Lens' (Env lab_ajNx m_ajNy) Rational
+ Graphics.Diagrams.Types: diaTightness :: forall lab_akJT m_akJU. Lens' (Env lab_akJT m_akJU) Rational
- Graphics.Diagrams.Types: traceLabel :: forall lab_ajGF m_ajGG location_ajGH x_ajGI. Monad x_ajGI => Getter (Backend lab_ajGF m_ajGG) ((location_ajGH -> (FrozenPoint -> m_ajGG ()) -> x_ajGI ()) -> (forall (a_ajGJ :: Type). m_ajGG a_ajGJ -> x_ajGI a_ajGJ) -> location_ajGH -> lab_ajGF -> x_ajGI BoxSpec)
+ Graphics.Diagrams.Types: traceLabel :: forall lab_akD1 m_akD2 location_akD3 x_akD4. Monad x_akD4 => Getter (Backend lab_akD1 m_akD2) ((location_akD3 -> (FrozenPoint -> m_akD2 ()) -> x_akD4 ()) -> (forall (a_akD5 :: Type). m_akD2 a_akD5 -> x_akD4 a_akD5) -> location_akD3 -> lab_akD1 -> x_akD4 BoxSpec)
- Graphics.Diagrams.Types: tracePath :: forall lab_ajGF m_ajGG. Lens' (Backend lab_ajGF m_ajGG) (PathOptions -> FrozenPath -> m_ajGG ())
+ Graphics.Diagrams.Types: tracePath :: forall lab_akD1 m_akD2. Lens' (Backend lab_akD1 m_akD2) (PathOptions -> FrozenPath -> m_akD2 ())
Files
- Algebra/AD.hs +0/−112
- Algebra/Linear/GaussianElimination.hs +0/−32
- Graphics/Diagrams/Core.hs +180/−132
- Graphics/Diagrams/DerivationTrees.hs +3/−3
- Graphics/Diagrams/Object.hs +11/−7
- Graphics/Diagrams/Path.hs +2/−2
- Graphics/Diagrams/Point.hs +10/−5
- Graphics/Diagrams/Types.hs +1/−1
- SMT/Model.hs +49/−0
- Setup.hs +2/−0
- lp-diagrams.cabal +14/−6
− Algebra/AD.hs
@@ -1,112 +0,0 @@-{-# LANGUAGE RankNTypes, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses, RebindableSyntax #-}-module Algebra.AD (D(..),E(..),subst,dVar,var,sqrtE) where--import Algebra.Classes hiding ((:+))-import Data.Map (Map)-import qualified Data.Map.Strict as M-import Prelude hiding (Num(..),(/),fromRational,recip)--- import Data.Vector as V-import Data.Function (on)--data AST v c = V v- | AST v c :* AST v c- | AST v c :+ AST v c- | AST v c :- AST v c- | K c--instance (Show v, Show c) => Show (AST v c) where- showsPrec p (V v) = shows v- showsPrec p (K c ) = shows c- showsPrec p (x :+ y) = parens (p>2) (showsPrec 2 x . showString " + " . showsPrec 2 y)- showsPrec p (x :* y) = parens (p>3) (showsPrec 3 x . showString " + " . showsPrec 3 y)--parens True x = showString "(" . x . showString ")"-parens False x = x--data D v c = D {dValue :: !c- ,dDerivs :: !(Map v c)- }- deriving Show--dVar :: forall v c. Ring c => v -> c -> D v c-dVar v c = D c (M.singleton v 1)--var :: (Multiplicative c, Additive c, Ord v) => v -> E v c-var v = E $ \env -> env v--instance (Ord v,Additive c) => Additive (D v c) where- zero = D zero zero- D v1 d1 + D v2 d2 = D (v1 + v2) (d1 + d2)--instance (Ord v,Group c) => Group (D v c) where- negate (D x d) = D (negate x) (negate d)- D v1 d1 - D v2 d2 = D (v1 - v2) (d1 - d2)--instance Ord c => Ord (D v c) where- compare = compare `on` dValue--instance Eq c => Eq (D v c) where- (==) = (==) `on` dValue--instance (Ord v,Ring c) => Multiplicative (D v c) where- one = D one zero- D v1 d1 * D v2 d2 = D (v1 * v2) (v2 *^ d1 + v1 *^ d2)--instance (AbelianAdditive c,Ord v) => AbelianAdditive (D v c)-instance (Ord v,Ring c) => Module c (D v c) where- k *^ D v d = D (k * v) (k *^ d)--instance (Ord v,Ring c) => Module (D v c) (D v c) where- (*^) = (*)--instance (Ord v, Ring c) => Ring (D v c) where- fromInteger k = D (fromInteger k) zero--newtype E v c = E {fromE :: (v -> D v c) -> D v c}--instance (Ord v,Additive c) => Additive (E v c) where- zero = E (const zero)- (+) = liftE2 (+)--instance (Ord v,Group c) => Group (E v c) where- negate (E x) = E (negate . x)- (-) = liftE2 (-)--instance (Ord v,Ring c) => Multiplicative (E v c) where- one = E (const one)- (*) = liftE2 (*)--instance (Ord v,Ring c) => AbelianAdditive (E v c)-instance (Ord v,Ring c) => Module c (E v c) where- k *^ E x = E ((k *^) . x)--instance (Ord v,Ring c) => Module (E v c) (E v c) where- (*^) = (*)--instance (Ord v, Ring c) => Ring (E v c) where- fromInteger k = E (\ _ -> fromInteger k)--liftE2 :: forall t t1. (D t t1 -> D t t1 -> D t t1) -> E t t1 -> E t t1 -> E t t1-liftE2 f (E x) (E y) = E (\e -> f (x e) (y e))--liftE :: forall t t1. (D t t1 -> D t t1) -> E t t1 -> E t t1-liftE f (E x) = E (\e -> f (x e))--subst :: E v c -> (v -> E v c) -> E v c-subst (E p) f = E $ \k -> p (\a -> fromE (f a) k)--sqrtD :: (Ord v, Floating c, Field c) => D v c -> D v c-sqrtD (D v d) = D (sqrtv) ((0.5/sqrtv) *^ d)- where sqrtv = sqrt v--sqrtE :: forall t t1. (Floating t1, Ord t, Field t1) => E t t1 -> E t t1-sqrtE = liftE sqrtD--instance (Field c,Ord v) => Division (D v c) where- recip (D v d) = D (recip v) (negate (square iv) *^ d)- where square x = x*x- iv = recip v--instance (Field c,Ord v) => Division (E v c) where- recip = liftE recip- (/) = liftE2 (/)
− Algebra/Linear/GaussianElimination.hs
@@ -1,32 +0,0 @@-{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, RebindableSyntax, DeriveFunctor #-}-module Algebra.Linear.GaussianElimination (linSolve) where--import Prelude hiding (Num(..),(/))-import Algebra.Classes-import qualified Data.Map.Strict as M-import Data.Maybe-import Algebra.Linear--gaussianElim :: (Ord v,Eq c,Field c) => [Constraint v c] -> [(v,LinFunc v c)]-gaussianElim [] = []-gaussianElim (co@(Func f k):cos) = case M.minViewWithKey f of- Nothing -> if k == 0 then gaussianElim cos- else error "gaussianElim: unsatisfiable"- Just ((_,0),_) -> error "gaussianElim: invariant not respected"- Just ((v,c),_) -> (v,clean $ var v - co') : gaussianElim (fmap t cos)- where co' = (1/c) *^ co- t co2@(Func m _) = case (M.lookup v m) of- Nothing -> co2- Just cv -> clean (co2 - cv *^ co')--substitution :: (Ord v,Ring c, Eq c) => [(v,LinFunc v c)] -> [(v,LinFunc v c)]-substitution [] = []-substitution ((v,f):vfs) = (v,f) : substitution [(v',subst v f f') | (v',f') <- vfs]--subst :: (Eq scalar, Ord v, Ring scalar) => v -> LinFunc v scalar -> LinFunc v scalar -> LinFunc v scalar-subst v f f'@(Func m _) = clean $ f' - coef *^ var v + coef *^ f- where coef = fromMaybe 0 (M.lookup v m)---linSolve :: (Eq c, Ord v, Field c) => [Constraint v c] -> [(v, LinFunc v c)]-linSolve = substitution . reverse . gaussianElim . fmap clean
Graphics/Diagrams/Core.hs view
@@ -1,13 +1,10 @@-{-# LANGUAGE TypeSynonymInstances, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, RecursiveDo, TypeFamilies, OverloadedStrings, RecordWildCards,UndecidableInstances, PackageImports, TemplateHaskell, RankNTypes, GADTs, ImpredicativeTypes, DeriveFunctor, ScopedTypeVariables, ConstraintKinds #-}+{-# LANGUAGE TypeSynonymInstances, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, RecursiveDo, TypeFamilies, OverloadedStrings, RecordWildCards,UndecidableInstances, PackageImports, TemplateHaskell, RankNTypes, GADTs, ImpredicativeTypes, DeriveFunctor, ScopedTypeVariables, ConstraintKinds, OverloadedStrings #-} module Graphics.Diagrams.Core ( module Graphics.Diagrams.Types,- Expr, constant, newVars,+ Expr, constant, absE, newVars, minimize, maximize, (===), (>==), (<==), (=~=),- GExpr,- minimize', maximize',- fromLinear, Diagram(..), runDiagram, drawText, freeze, relax, tighten,@@ -15,57 +12,106 @@ ) where import Prelude hiding (sum,mapM_,mapM,concatMap,Num(..),(/),fromRational,recip,(/))+import qualified Prelude import Control.Monad.RWS hiding (forM,forM_,mapM_,mapM) import Algebra.Classes as AC-import Algebra.Linear as Linear-import Algebra.Linear.GaussianElimination import Data.Map (Map) import qualified Data.Map.Strict as M import Control.Lens hiding (element) import Data.Traversable import Data.Foldable import System.IO.Unsafe-import Data.Vector (Vector,(!))-import qualified Data.Vector as V-import qualified Data.Vector.Storable as S-import Numeric.Optimization.Algorithms.HagerZhang05 hiding (optimize)-import qualified Numeric.Optimization.Algorithms.HagerZhang05 as HagerZhang05-import Algebra.AD as AD import Graphics.Diagrams.Types-+import Data.List (isPrefixOf,intercalate)+import Data.String+import System.Process+import SMT.Model -- | Expressions are linear functions of the variables-type Expr = LinFunc Var Constant newtype Var = Var Int deriving (Ord,Eq,Show,Enum) --- | A non-linear expression.-type GExpr = E Var Constant+class IsDouble a where+ fromDouble :: Double -> a+ -- sqrtE :: a -> a+ absE :: a -> a -fromLinear :: Expr -> GExpr-fromLinear m = fromLinear' one m AD.var+instance IsDouble Constant where+ fromDouble = id+ -- sqrtE = sqrt+ absE = Prelude.abs -fromLinear' :: forall a scalar. (Module scalar a) => a -> LinFunc Var scalar -> (Var -> a) -> a-fromLinear' unit (Func m c) f = c *^ unit + fromSum (M.foldMapWithKey (\v k -> AC.Sum (k *^ f v)) m)+-- | S-Expression represented as strings+newtype SExpr = S {fromS :: String} -substLinear :: Expr -> (Var -> Expr) -> Expr-substLinear = fromLinear' (Func M.empty 1)+-- Generic environment+newtype R env y = R {_fromR :: env -> y}+ deriving Functor+instance Applicative (R env) where+ pure x = R (\_ -> x)+ R f <*> R x = R (\rho -> (f rho) (x rho))+liftA2 :: forall (f :: * -> *) a b a1.+ Applicative f =>+ (a1 -> a -> b) -> f a1 -> f a -> f b+liftA2 f x y = f <$> x <*> y+instance IsDouble x => IsDouble (R env x) where+ fromDouble x = pure (fromDouble x)+ -- sqrtE = fmap sqrtE+ absE = fmap absE+instance Additive x => Additive (R env x) where+ zero = pure zero+ (+) = liftA2 (+)+instance Multiplicative x => Multiplicative (R env x) where+ one = pure one+ (*) = liftA2 (*)+instance Division x => Division (R env x) where+ recip = fmap recip+ (/) = liftA2 (/)+instance AbelianAdditive x => AbelianAdditive (R env x)+instance Ring x => Ring (R env x) where+ fromInteger x = pure (fromInteger x)+instance Field x => Field (R env x) where+ fromRational x = pure (fromRational x)+instance Group x => Group (R env x) where+ negate = fmap negate+ (-) = liftA2 (-) -rename :: (Var -> Var) -> Expr -> Expr-rename f e = substLinear e (Linear.var . f)+newtype Expr = E {_fromE :: forall x. (Field x,IsDouble x) => R (Var -> x) x} +instance Additive Expr where+ zero = E zero+ E x + E y = E (x+y)+instance Group Expr where+ E x - E y = E (x-y)+-- Not a decidable theory: avoid.+-- instance Multiplicative Expr where+-- one = E one+-- E x * E y = E (x*y)+-- instance Division Expr where+-- E x / E y = E (x/y)+-- instance Ring Expr+-- instance Field Expr+-- instance Module Expr Expr where+-- (*^) = (*)+instance AbelianAdditive Expr+instance Module Rational Expr where+ k *^ E x = E (fromRational k*x)+instance Module Constant Expr where+ k *^ E x = E (fromDouble k*x) -- | Some action to perform after a solution has been found. data Freeze m where Freeze :: forall t m. Functor t => (t Constant -> m ()) -> t Expr -> Freeze m +type Constraint = SExpr+ data DiagramState = DiagramState- {_diaNextVar :: Var- ,_diaLinConstraints :: [Constraint Var Constant]- ,_diaObjective :: GExpr+ {_diaNextVar :: Var -- ^ next var to allocate+ ,_diaConstraints :: [Constraint]+ ,_diaObjective :: Expr -- ^ objective function ,_diaVarNames :: Map Var String- ,_diaNoOverlaps :: [Pair (Point' GExpr)]+ ,_diaNoOverlaps :: [Pair (Point' Expr)] } $(makeLenses ''DiagramState)@@ -82,9 +128,37 @@ -- Diagrams +runDiagram :: Monad m => Backend lab m -> Diagram lab m a -> m a+runDiagram backend diag = do+ let env = Env one defaultPathOptions backend+ (a,finalState,ds) <- runRWST (fromDia $ do x<-diag;resolveNonOverlaps;return x) env $+ DiagramState (Var 0) [] zero (M.empty) []+ let maxVar = finalState ^. diaNextVar+ decls = [sexp ["declare-const", smtVar x, "Real"] | x <- [Var 0 .. maxVar]]+ constrs = intercalate "\n" $ map fromS $+ decls +++ (unop "assert" <$> (finalState ^. diaConstraints)) +++ [ unop "minimize" (renderExpr (finalState ^. diaObjective)),+ sexp ["check-sat"],+ sexp ["get-model"]+ ]+ solution = unsafePerformIO $ do+ writeFile "problem.smt2" $ constrs+ _exitCode <- system "z3 -smt2 problem.smt2 > result.smt2"+ res <- readFile "result.smt2"+ let modelText = unlines . dropWhile (not . ("(model" `isPrefixOf`)) . lines $ res+ case readModel modelText of+ Right model -> return $ M.fromList model+ Left err -> do print err+ error "die."+ lkMod m (Var v) = M.findWithDefault (error "variable not in model") ("x"++show v) m++ forM_ ds (\(Freeze f x) -> f (fmap (\(E (R g)) -> g (lkMod solution)) x))+ return a+ -- | Relax the optimisation functions by the given factor relax :: Monad m => Rational -> Diagram lab m a -> Diagram lab m a-relax factor = tighten (one/factor)+relax factor = tighten (recip factor) -- | Tighten the optimisation functions by the given factor tighten :: Monad m => Rational -> Diagram lab m a -> Diagram lab m a@@ -93,12 +167,6 @@ -------------- -- Variables --newVar :: Monad m => String -> Diagram lab m Expr-newVar name = do- [v] <- newVars [name]- return v- newVars :: Monad m => [String] -> Diagram lab m [Expr] newVars kinds = forM kinds $ \name -> do v <- rawNewVar name@@ -117,60 +185,17 @@ -- Expressions -runDiagram :: Monad m => Backend lab m -> Diagram lab m a -> m a-runDiagram backend diag = do- let env = Env one defaultPathOptions backend- (a,finalState,ds) <- runRWST (fromDia $ do x<-diag;resolveNonOverlaps;return x) env $- DiagramState (Var 0) [] zero (M.empty) []- let reducedConstraints = M.fromList $ linSolve (finalState ^. diaLinConstraints)- linSolvSubst v = case M.lookup v reducedConstraints of- Nothing -> Linear.var v- Just x -> x- solvSubst = fromLinear . linSolvSubst- maxVar = finalState ^. diaNextVar- freeVars = filter (\v -> M.notMember v reducedConstraints) [Var 0..maxVar]- varsToFreeVars' :: Map Var Int- varsToFreeVars' = M.fromList (zip freeVars [0..])- freeVarsToVars :: V.Vector Var- freeVarsToVars = V.fromList freeVars-- obj' :: GExpr- obj' = AD.subst (finalState ^. diaObjective) solvSubst- grad' rho = (y,fmap (\v -> M.findWithDefault zero v dy) freeVarsToVars)- where D y dy = fromE obj' (\v -> maybe (error "not found") id (M.lookup v env') )- env' = M.mapWithKey (\v i -> D (rho ! i) (M.singleton v 1)) varsToFreeVars'- (solution,_result,_statistics) = unsafePerformIO $ do- putStrLn $ "free vars: " ++ show freeVars- putStrLn $ "reducedConstraints: " ++ show reducedConstraints- putStrLn $ "optimizing ..."- opt@(s,_,_) <- HagerZhang05.optimize- defaultParameters {verbose = VeryVerbose}- 0.01- (V.replicate (length freeVars) 0)- (VFunction (fst . grad')) (VGradient (snd . grad')) (Just (VCombined grad'))- putStrLn $ "done: " ++ show (grad' (S.convert s))- return opt- solution' = fmap (solution S.!) varsToFreeVars'- fullSolution = M.union solution' (fmap (valueIn solution') reducedConstraints)-- forM_ ds (\(Freeze f x) -> f (fmap (valueIn fullSolution) x))- return a---valueIn :: Map Var Double -> Expr -> Double-valueIn sol f = fromLinear' one f (\v -> M.findWithDefault 0 v sol)- -- | Embed a variable in an expression variable :: Var -> Expr-variable v = Func (M.singleton v 1) 0+variable v = E (R $ \rho -> rho v) -- | Embed a constant in an expression-constant :: Constant -> Expr-constant c = Func M.empty c+constant :: Double -> Expr+constant c = E (R $ \_ -> fromDouble c) satAll :: Monad m => String -> (Expr -> a -> Diagram lab m b) -> [a] -> Diagram lab m Expr satAll name p xs = do- [m] <- newVars [(name)]+ [m] <- newVars [name] mapM_ (p m) xs return m @@ -181,52 +206,25 @@ -------------- -- Expression constraints-(===), (>==), (<==) :: Expr -> Expr -> Monad m => Diagram lab m ()-e1 <== e2 = do- let Func f c = e1 - e2- isFalse = M.null f && c < 0- when isFalse $ error "Diagrams.Core: inconsistent constraint!"- minimize' $ E $ \s ->- let [v1,v2] = map (($ s) . fromE . fromLinear) [e1,e2]- in if v1 <= v2 then zero else square (square (v2-v1)) -prettyExpr :: Monad m => Expr -> Diagram lab m String-prettyExpr (Func f k) = do- vnames <- Dia (use diaVarNames)- let vname n = case M.lookup n vnames of- Nothing -> error ("prettyExpr: variable not found: " ++ show n)- Just nm -> nm- return $ prettySum ([prettyProd c (vname v) | (v,c) <- M.assocs f] ++ [show k | k /= 0])- where prettySum [] = "0"- prettySum xs = foldr1 prettyPlus xs- prettyPlus a ('-':b) = a ++ ('-':b)- prettyPlus x y = x ++ "+" ++ y- prettyProd 1 v = show v- prettyProd (-1) v = '-' : show v- prettyProd c v = show c ++ show v-+(===), (>==), (<==) :: Expr -> Expr -> Monad m => Diagram lab m ()+e1 <== e2 = assert (e1 .<= e2) (>==) = flip (<==)--e1 === e2 = do- constrName <- (\x y -> x ++ " = " ++ y) <$> prettyExpr e1 <*> prettyExpr e2- diaLinConstraints %= (e1 - e2 :)+e1 === e2 = assert (e1 .== e2) -- | minimize the distance between expressions-(=~=) :: Monad m => GExpr -> GExpr -> Diagram lab m ()-x =~= y = minimize' $ square (x-y)+(=~=) :: Monad m => Expr -> Expr -> Diagram lab m ()+x =~= y = minimize $ absE (x-y) ------------------------- -- Expression objectives + minimize,maximize :: Monad m => Expr -> Diagram lab m ()-minimize = minimize' . fromLinear maximize = minimize . negate--minimize',maximize' :: Monad m => GExpr -> Diagram lab m ()-maximize' = minimize' . negate-minimize' f = do+minimize f = do tightness <- view diaTightness- diaObjective %= \o -> (fromRational tightness::Double) *^ f + o+ diaObjective %= \o -> tightness *^ f + o drawText :: Monad m => Point' Expr -> lab -> Diagram lab m BoxSpec@@ -241,22 +239,72 @@ -- Non-overlapping things registerNonOverlap :: Monad m => Point' Expr -> Point' Expr -> Diagram lab m ()-registerNonOverlap nw se = Dia $ diaNoOverlaps %= (Pair (fromLinear <$> nw) (fromLinear <$> se):)+registerNonOverlap nw se = Dia $ diaNoOverlaps %= (Pair nw se:) -surface :: forall a. Multiplicative a => Point' a -> a-surface (Point x y) = x*y+allPairs :: forall a. [a] -> [Pair a]+allPairs [] = []+allPairs (x:xs) = [Pair x y | y <- xs] ++ allPairs xs resolveNonOverlaps :: Monad m => Diagram lab m () resolveNonOverlaps = do noOvl <- Dia $ use diaNoOverlaps- minimize' $ E $ \s ->- add $ do- pair <- allPairs noOvl- let (Pair bx1 bx2) = fmap (fmap (fmap (($ s) . fromE))) pair- overlap = inters bx1 bx2- return $ if nonEmpty overlap then (square $ surface overlap) else zero- where- allPairs [] = []- allPairs (x:xs) = [Pair x y | y <- xs] ++ allPairs xs- inters (Pair p1 q1) (Pair p2 q2) = (min <$> q1 <*> q2) - (max <$> p1 <*> p2)- nonEmpty (Point a b) = a > zero && b > zero+ forM_ (allPairs noOvl) $ \p -> do+ assert (disj (ffmap xpart p) .|| disj (ffmap ypart p))+ where disj (Pair (Pair p1 q1) (Pair p2 q2)) = (q1 .<= p2) .|| (q2 .<= p1)+ ffmap f = fmap (fmap f)+++---------------------------------+-- Constraint & SExpr utils++assert :: Monad m => SExpr -> Diagram lab m ()+assert x = diaConstraints %= (x:)++(.<=),(.==) :: Expr -> Expr -> Constraint+x .<= y = binop "<=" (renderExpr x) (renderExpr y)++x .== y = binop "=" (renderExpr x) (renderExpr y)++(.||) :: Constraint -> Constraint -> Constraint+(.||) = binop "or"++renderExpr :: Expr -> SExpr+renderExpr (E (R x)) = x smtVar++smtVar :: Var -> SExpr+smtVar (Var x) = S ("x" ++ show x)++parens :: forall a. IsString [a] => [a] -> [a]+parens x = "(" ++ x ++ ")"+sexp :: [SExpr] -> SExpr+sexp xs = S $ parens $ intercalate " " $ map fromS xs+binop :: String -> SExpr -> SExpr -> SExpr+binop s x y = sexp [S s,x,y]+unop :: String -> SExpr -> SExpr+unop s x = sexp [S s,x]+instance Multiplicative (SExpr) where+ (*) = binop "*"+ one = S "1"+instance Division (SExpr) where+ (/) = binop "/"+instance Additive (SExpr) where+ (+) = binop "+"+ zero = S "0"+instance AbelianAdditive (SExpr)+instance Field (SExpr)+instance Ring (SExpr)+instance Group (SExpr) where+ negate = unop "-"+ (-) = binop "-"+instance IsString SExpr where+ fromString = S++instance IsDouble Expr where+ fromDouble d = E (R $ \_ -> fromDouble d)+ -- sqrtE (E x) = E (sqrtE x)+ absE (E x) = E (absE x)++instance IsDouble SExpr where+ fromDouble x = S $ show x+ -- sqrtE x = binop "^" x "0.5"+ absE = unop "abs"
Graphics/Diagrams/DerivationTrees.hs view
@@ -100,7 +100,7 @@ let pt = ptObj # S pt `eastOf` (concl # W) pt `westOf` (concl # E)- fromLinear (xpart pt) =~= fromLinear (xpart (concl # Center))+ (xpart pt) =~= (xpart (concl # Center)) let top = ypart (concl # S) ypart pt + (fromIntegral steps *- layerHeight) === top using linkStyle $ path $ polyline [ptObj # Base,Point (xpart pt) top]@@ -169,9 +169,9 @@ -- layout hints (not necessary for "correctness") let xd = xdiff (separ # W) (psGrp # W) xd === xdiff (psGrp # E) (separ # E)- relax 2 $ fromLinear (2 *- xd) =~= fromLinear premisesDist+ relax 2 $ (2 *- xd) =~= premisesDist -- centering of conclusion- relax 3 $ minimize' $ sqNorm $ fmap fromLinear $ (separ # Center) - (concl # Center)+ relax 3 $ minimize $ orthonorm $ (separ # Center) - (concl # Center) -- draw the rule. using ruleStyle $ path $ polyline [separ # W,separ # E]
Graphics/Diagrams/Object.hs view
@@ -8,7 +8,7 @@ import Control.Monad import Control.Lens (set,view) import Algebra.Classes hiding (normalize)-import Prelude hiding (Num(..))+import Prelude hiding (Num(..),(/)) data Anchor = Center | N | NW | W | SW | S | SE | E | NE | BaseW | Base | BaseE deriving Show@@ -17,7 +17,9 @@ type Box = Object type Anchorage = Anchor -> Point-data Object = Object {objectName :: String, objectOutline :: Path, anchors :: Anchorage}+data Object = Object { objectName :: !String+ , objectOutline :: !Path+ , anchors :: !Anchorage} infix 8 #@@ -164,6 +166,7 @@ p = circlePath (bx # Center) radius pathObject $ Object name p (anchors bx) +-- | Debug, by tracing the bounding box of the object in a certain color. traceBox :: (Monad m) => Color -> Object -> Diagram lab m () traceBox c l = do stroke c $ path $ polygon (map (l #) [NW,NE,SE,SW])@@ -229,14 +232,15 @@ -- vector. autoLabelObj :: Monad m => Box -> OVector -> Diagram lab m () autoLabelObj lab (OVector pt v) = do- let normalVector :: Point' GExpr- normalVector = normalize $ fromLinear <$> v+ let normalVector :: Point' Expr+ normalVector = v -- label must touch the point tighten 10 $ pt `insideBox` lab+ minimize (orthonorm (pt+v- lab#Center)) -- go as far as possible in the normal direction- maximize' $ dotProd (fromLinear <$> ((lab#Center) - pt)) normalVector- -- don't stray from the normal line- minimize' $ square $ dotProd (fromLinear <$> ((lab#Center) - pt)) (rotate90 normalVector)+ -- maximize $ dotProd (((lab#Center) - pt)) normalVector+ -- don't stray away from the normal line+ -- minimize $ absE $ dotProd (((lab#Center) - pt)) (rotate90 normalVector) -- -- | @autoLabel o i@ Layouts the label object @o@ at the given incidence
Graphics/Diagrams/Path.hs view
@@ -111,8 +111,8 @@ CurveTo (pt (negate r) (negate k)) (pt (negate k) (negate r)) (pt zero (negate r)), CurveTo (pt k (negate r)) (pt r (negate k)) (pt r zero), Cycle]- where k1 :: Constant- k1 = 4 * (sqrt 2 - 1) / 3+ where k1 :: Double+ k1 = fromInteger 4 * (sqrt (fromInteger 2) - (fromInteger 1)) / fromInteger 3 k = k1 *^ r pt x y = center + (Point x y)
Graphics/Diagrams/Point.hs view
@@ -7,7 +7,6 @@ import Data.List (transpose) import Prelude hiding (sum,mapM_,mapM,concatMap,maximum,minimum,Num(..),(/)) import Algebra.Classes-import Algebra.AD (sqrtE) infix 4 .=. ----------------@@ -17,12 +16,18 @@ type Point = Point' Expr +orthonorm :: Point -> Expr+orthonorm (Point x y) = absE x + absE y++{-++ -- | Norm of a vector. Don't minimize this: the solver does not like functions -- with non-continuous derivatives (at zero in this case).-norm :: Point' GExpr -> GExpr+norm :: Point' Expr -> Expr norm p = sqrtE (sqNorm p) -normalize :: Point' GExpr -> Point' GExpr+normalize :: Point' Expr -> Point' Expr normalize x = (one/norm x) *^ x -- | Dot product@@ -32,14 +37,14 @@ -- | Squared norm of a vector sqNorm :: forall a. (Ring a) => Point' a -> a sqNorm p = dotProd p p-+-} -- | Rotate a vector 90 degres in the trigonometric direction. rotate90 :: forall a. Group a => Point' a -> Point' a rotate90 (Point x y) = Point (negate y) x -- | Rotate a vector 180 degres rotate180 :: forall a. Group a => Point' a -> Point' a-rotate180 x = rotate90 . rotate90 $ x+rotate180 = rotate90 . rotate90 xdiff,ydiff :: Point -> Point -> Expr xdiff p q = xpart (q - p)
Graphics/Diagrams/Types.hs view
@@ -24,7 +24,7 @@ -- | Average avg :: Module Constant a => [a] -> a-avg xs = (1/fromIntegral (length xs)) *- add xs+avg xs = (one/fromIntegral (length xs)::Constant) *^ add xs ------------ -- Types
+ SMT/Model.hs view
@@ -0,0 +1,49 @@+module SMT.Model (readModel) where++import Text.ParserCombinators.Parsek.Position+import Data.Char (isSpace)++type P a = Parser a++tok :: String -> P ()+tok s = spaces >> string s >> return ()++many1 p = (:) <$> p <*> many p++parseDouble :: P Double+parseDouble = do+ spaces+ x <- many1 digit+ string "."+ y <- many1 digit+ return $ read $ x ++ "." ++ y+parseValue = parseDouble <|> parens (parseDiv <|> parseNeg)++parseDiv = do+ tok "/"+ x <- parseValue+ y <- parseValue+ return (x/y)++parseNeg = do+ tok "-"+ x <- parseValue+ return (negate x)++parseAssoc :: P (String,Double)+parseAssoc = parens $ do+ tok "define-fun"+ spaces+ v <- many1 (satisfy (not . isSpace))+ parens (return ())+ tok "Real"+ x <- parseValue+ return (v,x)++parens = between (tok "(") (tok")")+parseModel = parens $ do+ tok "model"+ many parseAssoc++readModel :: String -> ParseResult SourcePos [(String, Double)]+readModel = parse "<model>" parseModel longestResult
Setup.hs view
@@ -1,2 +1,4 @@+#!/usr/bin/env runhaskell import Distribution.Simple+main :: IO () main = defaultMain
lp-diagrams.cabal view
@@ -1,5 +1,5 @@ name: lp-diagrams-version: 2.0+version: 2.0.0 synopsis: An EDSL for diagrams based based on linear constraints license: AGPL-3 license-file: LICENSE@@ -10,11 +10,20 @@ build-type: Simple -- extra-source-files: cabal-version: >=1.18+description:+ A library to describe diagrams. The defining+ feature of the package is the ability to use linear constraints to+ specify layout, which are resolved using z3 (latest z3 must be installed).+ Backends are provided either of the following packages lp-diagrams-svg (svg) or marxup (tikz). Flag graphviz Description: Enable graphviz support Default: True +source-repository head+ type: git+ location: https://github.com/jyp/lp-diagrams+ library if flag(graphviz) build-depends: graphviz@@ -28,21 +37,20 @@ Graphics.Diagrams.Types, Graphics.Diagrams.DerivationTrees, Graphics.Diagrams+ other-modules: SMT.Model - Algebra.AD Algebra.Linear- Algebra.Linear.GaussianElimination build-depends: base >=4.8 && < 666,- ad, lens >=4.12, text >=1.2 , typography-geometry >=1.0 , gasp,- nonlinear-optimization, reflection, vector, polynomials-bernstein, mtl >=2.2 , containers >=0.5,- labeled-tree+ labeled-tree,+ parsek,+ process default-language: Haskell2010