packages feed

hbayes 0.3 → 0.4

raw patch · 23 files changed

+1965/−555 lines, 23 filesdep +binaryPVP ok

version bump matches the API change (PVP)

Dependencies added: binary

API changes (from Hackage documentation)

- Bayes: (.!.) :: LE -> LE
- Bayes: (.&.) :: LE -> LE -> LE
- Bayes: (.==.) :: Testable d v => d -> v -> LE
- Bayes: (.|.) :: LE -> LE -> LE
- Bayes: (~~) :: (DirectedGraph g, Factor f, Distribution d, BayesianDiscreteVariable v) => BNMonad g f v -> d -> BNMonad g f ()
- Bayes: class Distribution d
- Bayes: cpt :: (DirectedGraph g, BayesianDiscreteVariable v, BayesianDiscreteVariable vb) => v -> [vb] -> BNMonad g f v
- Bayes: createFactor :: (Distribution d, Factor f) => [DV] -> d -> Maybe f
- Bayes: evalBN :: BNMonad DirectedSG f a -> a
- Bayes: execBN :: BNMonad DirectedSG f a -> DirectedSG () f
- Bayes: instance (Show b, Show e) => Show (DirectedSG e b)
- Bayes: instance Eq DE
- Bayes: instance Eq Edge
- Bayes: instance Eq LE
- Bayes: instance Eq UE
- Bayes: instance Instantiable d v => Testable d v
- Bayes: instance Ord Edge
- Bayes: instance Real a => Distribution [a]
- Bayes: instance Show DE
- Bayes: instance Show Edge
- Bayes: instance Show UE
- Bayes: logical :: (Factor f, DirectedGraph g) => TDV Bool -> LE -> BNMonad g f ()
- Bayes: noisyOR :: (DirectedGraph g, Factor f, NamedGraph g) => [(TDV Bool, Double)] -> BNMonad g f (TDV Bool)
- Bayes: proba :: (DirectedGraph g, BayesianDiscreteVariable v) => v -> BNMonad g f v
- Bayes: runBN :: BNMonad DirectedSG f a -> (a, DirectedSG () f)
- Bayes: se :: Factor f => TDV s -> TDV s -> Double -> Maybe f
- Bayes: softEvidence :: (NamedGraph g, DirectedGraph g, Factor f) => TDV Bool -> BNMonad g f (TDV Bool)
- Bayes: t :: a
- Bayes: tdv :: DV -> TDV s
- Bayes: type BNMonad g f a = GraphMonad g () (MaybeBNode f) a
- Bayes: unamedVariable :: (Enum a, Bounded a, NamedGraph g) => a -> BNMonad g f (TDV a)
- Bayes: variable :: (Enum a, Bounded a, NamedGraph g) => String -> a -> BNMonad g f (TDV a)
- Bayes: variableWithSize :: NamedGraph g => String -> Int -> BNMonad g f DV
- Bayes.VariableElimination: instance Show f => Show (Buckets f)
+ Bayes: childrenNodes :: DirectedGraph g => g a b -> Vertex -> [Vertex]
+ Bayes: displaySimpleGraph :: (Vertex -> n -> Maybe String) -> (Vertex -> n -> Maybe String) -> (Edge -> e -> Maybe String) -> (Edge -> e -> Maybe String) -> SimpleGraph local e n -> String
+ Bayes: emptyAuxiliaryState :: (Map k a, Int)
+ Bayes: getNewEmptyVariable :: NamedGraph g => Maybe String -> f -> GraphMonad g e f Vertex
+ Bayes: getVertex :: Graph g => String -> GraphMonad g e f (Maybe Vertex)
+ Bayes: instance Show (DirectedSG () CPT)
+ Bayes: instance Show (DirectedSG () MAXCPT)
+ Bayes: instance Show (DirectedSG String String)
+ Bayes: isRoot :: DirectedGraph g => g a b -> Vertex -> Bool
+ Bayes: parentNodes :: DirectedGraph g => g a b -> Vertex -> [Vertex]
+ Bayes: rootNode :: DirectedGraph g => g a b -> Maybe Vertex
+ Bayes: varMap :: SimpleGraph n e v -> Map String Vertex
+ Bayes.BayesianNetwork: (.!.) :: LE -> LE
+ Bayes.BayesianNetwork: (.&.) :: LE -> LE -> LE
+ Bayes.BayesianNetwork: (.==.) :: Testable d v => d -> v -> LE
+ Bayes.BayesianNetwork: (.|.) :: LE -> LE -> LE
+ Bayes.BayesianNetwork: (~~) :: (DirectedGraph g, Factor f, Distribution d, BayesianDiscreteVariable v) => BNMonad g f v -> d -> BNMonad g f ()
+ Bayes.BayesianNetwork: class Distribution d
+ Bayes.BayesianNetwork: cpt :: (DirectedGraph g, BayesianDiscreteVariable v, BayesianDiscreteVariable vb) => v -> [vb] -> BNMonad g f v
+ Bayes.BayesianNetwork: createFactor :: (Distribution d, Factor f) => [DV] -> d -> Maybe f
+ Bayes.BayesianNetwork: evalBN :: BNMonad DirectedSG f a -> a
+ Bayes.BayesianNetwork: execBN :: BNMonad DirectedSG f a -> SBN f
+ Bayes.BayesianNetwork: instance Eq LE
+ Bayes.BayesianNetwork: instance Instantiable d v => Testable d v
+ Bayes.BayesianNetwork: logical :: (Factor f, DirectedGraph g) => TDV Bool -> LE -> BNMonad g f ()
+ Bayes.BayesianNetwork: noisyOR :: (DirectedGraph g, Factor f, NamedGraph g) => [(TDV Bool, Double)] -> BNMonad g f (TDV Bool)
+ Bayes.BayesianNetwork: proba :: (DirectedGraph g, BayesianDiscreteVariable v) => v -> BNMonad g f v
+ Bayes.BayesianNetwork: runBN :: BNMonad DirectedSG f a -> (a, SBN f)
+ Bayes.BayesianNetwork: se :: Factor f => TDV s -> TDV s -> Double -> Maybe f
+ Bayes.BayesianNetwork: softEvidence :: (NamedGraph g, DirectedGraph g, Factor f) => TDV Bool -> BNMonad g f (TDV Bool)
+ Bayes.BayesianNetwork: t :: a
+ Bayes.BayesianNetwork: tdv :: DV -> TDV s
+ Bayes.BayesianNetwork: type BNMonad g f a = NetworkMonad g () f a
+ Bayes.BayesianNetwork: unamedVariable :: (Enum a, Bounded a, NamedGraph g) => a -> NetworkMonad g e f (TDV a)
+ Bayes.BayesianNetwork: variable :: (Enum a, Bounded a, NamedGraph g) => String -> a -> NetworkMonad g e f (TDV a)
+ Bayes.BayesianNetwork: variableWithSize :: NamedGraph g => String -> Int -> NetworkMonad g e f DV
+ Bayes.Examples.Influence: exampleID :: InfluenceDiagram
+ Bayes.Examples.Influence: instance Bounded E
+ Bayes.Examples.Influence: instance Bounded EF
+ Bayes.Examples.Influence: instance Bounded F
+ Bayes.Examples.Influence: instance Bounded I
+ Bayes.Examples.Influence: instance Bounded IN
+ Bayes.Examples.Influence: instance Bounded S
+ Bayes.Examples.Influence: instance Enum E
+ Bayes.Examples.Influence: instance Enum EF
+ Bayes.Examples.Influence: instance Enum F
+ Bayes.Examples.Influence: instance Enum I
+ Bayes.Examples.Influence: instance Enum IN
+ Bayes.Examples.Influence: instance Enum S
+ Bayes.Examples.Influence: instance Eq E
+ Bayes.Examples.Influence: instance Eq EF
+ Bayes.Examples.Influence: instance Eq F
+ Bayes.Examples.Influence: instance Eq I
+ Bayes.Examples.Influence: instance Eq IN
+ Bayes.Examples.Influence: instance Eq S
+ Bayes.Examples.Influence: market :: InfluenceDiagram
+ Bayes.Examples.Influence: marketTest :: IO ()
+ Bayes.Examples.Influence: policyTest :: IO ()
+ Bayes.Examples.Influence: student :: InfluenceDiagram
+ Bayes.Examples.Influence: studentDecisionVars :: (DEV, TDV Bool, DEV)
+ Bayes.Examples.Influence: studentSimple :: InfluenceDiagram
+ Bayes.Examples.Influence: studentSimpleDecisionVar :: DEV
+ Bayes.Examples.Influence: theTest :: IO ()
+ Bayes.Factor: DVSet :: [DV] -> DVSet s
+ Bayes.Factor: class Distribution d
+ Bayes.Factor: class MultiDimTable f
+ Bayes.Factor: createFactor :: (Distribution d, Factor f) => [DV] -> d -> Maybe f
+ Bayes.Factor: elementStringValue :: MultiDimTable f => f -> [DVI] -> String
+ Bayes.Factor: instance Real a => Distribution [a]
+ Bayes.Factor: newtype DVSet s
+ Bayes.Factor: tableVariables :: MultiDimTable f => f -> [DV]
+ Bayes.Factor: tdv :: DV -> TDV s
+ Bayes.Factor.CPT: cptDivide :: CPT -> CPT -> CPT
+ Bayes.Factor.CPT: cptSum :: [CPT] -> CPT
+ Bayes.Factor.CPT: instance IsBucketItem CPT
+ Bayes.Factor.CPT: instance MultiDimTable CPT
+ Bayes.Factor.MaxCPT: instance IsBucketItem MAXCPT
+ Bayes.Factor.MaxCPT: instance MultiDimTable MAXCPT
+ Bayes.ImportExport: instance (Binary l, Binary e, Binary v) => Binary (SimpleGraph l e v)
+ Bayes.ImportExport: instance (Ord c, Binary c, Binary f) => Binary (JTree c f)
+ Bayes.ImportExport: instance Binary (Vector Double)
+ Bayes.ImportExport: instance Binary (v Double) => Binary (PrivateCPT v Double)
+ Bayes.ImportExport: instance Binary Cluster
+ Bayes.ImportExport: instance Binary DE
+ Bayes.ImportExport: instance Binary DV
+ Bayes.ImportExport: instance Binary Edge
+ Bayes.ImportExport: instance Binary UE
+ Bayes.ImportExport: instance Binary Vertex
+ Bayes.ImportExport: instance Binary a => Binary (NodeValue a)
+ Bayes.ImportExport: instance Binary a => Binary (SeparatorValue a)
+ Bayes.ImportExport: readNetworkFromFile :: FilePath -> IO (SBN CPT)
+ Bayes.ImportExport: readVariableMapAndJunctionTreeToFile :: FilePath -> IO (Map String Vertex, JunctionTree CPT)
+ Bayes.ImportExport: writeNetworkToFile :: FilePath -> SBN CPT -> IO ()
+ Bayes.ImportExport: writeVariableMapAndJunctionTreeToFile :: FilePath -> (Map String Vertex) -> JunctionTree CPT -> IO ()
+ Bayes.InfluenceDiagram: (=:) :: Instantiable d v => d -> v -> DVI
+ Bayes.InfluenceDiagram: (~~) :: (Initializable v, DirectedGraph g, Distribution d) => IDMonad g v -> d -> IDMonad g ()
+ Bayes.InfluenceDiagram: chance :: (Bounded a, Enum a, NamedGraph g) => String -> a -> IDMonad g (TDV a)
+ Bayes.InfluenceDiagram: class Instantiable d v
+ Bayes.InfluenceDiagram: cpt :: (DirectedGraph g, BayesianDiscreteVariable vb, ChanceVariable c) => c -> [vb] -> IDMonad g c
+ Bayes.InfluenceDiagram: d :: DEV -> PorD
+ Bayes.InfluenceDiagram: data DEV
+ Bayes.InfluenceDiagram: data DV
+ Bayes.InfluenceDiagram: data DVI
+ Bayes.InfluenceDiagram: data TDV s
+ Bayes.InfluenceDiagram: data UV
+ Bayes.InfluenceDiagram: decision :: (DirectedGraph g, BayesianDiscreteVariable dv) => DEV -> [dv] -> IDMonad g DEV
+ Bayes.InfluenceDiagram: decisionNode :: (Bounded a, Enum a, NamedGraph g) => String -> a -> IDMonad g DEV
+ Bayes.InfluenceDiagram: decisionToInstantiation :: DecisionFactor -> [DVISet]
+ Bayes.InfluenceDiagram: decisionsOrder :: InfluenceDiagram -> [ChancesOrDecision]
+ Bayes.InfluenceDiagram: instance BayesianDiscreteVariable DEV
+ Bayes.InfluenceDiagram: instance BayesianDiscreteVariable PorD
+ Bayes.InfluenceDiagram: instance ChanceVariable (TDV s)
+ Bayes.InfluenceDiagram: instance ChanceVariable DV
+ Bayes.InfluenceDiagram: instance Eq ChancesOrDecision
+ Bayes.InfluenceDiagram: instance Eq DEV
+ Bayes.InfluenceDiagram: instance Eq EdgeKind
+ Bayes.InfluenceDiagram: instance Eq IDValue
+ Bayes.InfluenceDiagram: instance Eq JoinSum
+ Bayes.InfluenceDiagram: instance Eq PorD
+ Bayes.InfluenceDiagram: instance Eq UV
+ Bayes.InfluenceDiagram: instance Initializable (TDV s)
+ Bayes.InfluenceDiagram: instance Initializable DEV
+ Bayes.InfluenceDiagram: instance Initializable DV
+ Bayes.InfluenceDiagram: instance Initializable UV
+ Bayes.InfluenceDiagram: instance Instantiable DEV Int
+ Bayes.InfluenceDiagram: instance IsBucketItem JoinSum
+ Bayes.InfluenceDiagram: instance Monoid EdgeKind
+ Bayes.InfluenceDiagram: instance MultiDimTable DecisionFactor
+ Bayes.InfluenceDiagram: instance Ord ChancesOrDecision
+ Bayes.InfluenceDiagram: instance Ord DEV
+ Bayes.InfluenceDiagram: instance Show ChancesOrDecision
+ Bayes.InfluenceDiagram: instance Show DEV
+ Bayes.InfluenceDiagram: instance Show DecisionFactor
+ Bayes.InfluenceDiagram: instance Show EdgeKind
+ Bayes.InfluenceDiagram: instance Show IDValue
+ Bayes.InfluenceDiagram: instance Show InfluenceDiagram
+ Bayes.InfluenceDiagram: instance Show JoinSum
+ Bayes.InfluenceDiagram: noDependencies :: [DV]
+ Bayes.InfluenceDiagram: p :: ChanceVariable c => c -> PorD
+ Bayes.InfluenceDiagram: policyNetwork :: [DecisionFactor] -> InfluenceDiagram -> SBN CPT
+ Bayes.InfluenceDiagram: proba :: (ChanceVariable c, DirectedGraph g) => c -> IDMonad g c
+ Bayes.InfluenceDiagram: runID :: IDMonad DirectedSG a -> (a, InfluenceDiagram)
+ Bayes.InfluenceDiagram: solveInfluenceDiagram :: InfluenceDiagram -> [DecisionFactor]
+ Bayes.InfluenceDiagram: t :: a
+ Bayes.InfluenceDiagram: type DVISet = [DVI]
+ Bayes.InfluenceDiagram: type DecisionFactor = PrivateCPT (Vector) DVI
+ Bayes.InfluenceDiagram: type InfluenceDiagram = DirectedSG EdgeKind IDValue
+ Bayes.InfluenceDiagram: utility :: (DirectedGraph g, BayesianDiscreteVariable dv) => UV -> [dv] -> IDMonad g UV
+ Bayes.InfluenceDiagram: utilityNode :: NamedGraph g => String -> IDMonad g UV
+ Bayes.Test.InfluencePatterns: testStudentDecisions :: IO ()
+ Bayes.Test.ReferencePatterns: testFileExport :: IO ()
+ Bayes.VariableElimination.Buckets: Buckets :: !EliminationOrder DV -> !Map DV [f] -> Buckets f
+ Bayes.VariableElimination.Buckets: addBucket :: IsBucketItem f => Buckets f -> f -> Buckets f
+ Bayes.VariableElimination.Buckets: class IsBucketItem f
+ Bayes.VariableElimination.Buckets: createBuckets :: IsBucketItem f => [f] -> EliminationOrder DV -> EliminationOrder DV -> Buckets f
+ Bayes.VariableElimination.Buckets: data Buckets f
+ Bayes.VariableElimination.Buckets: getBucket :: DV -> Buckets f -> [f]
+ Bayes.VariableElimination.Buckets: instance Show f => Show (Buckets f)
+ Bayes.VariableElimination.Buckets: itemContainsVariable :: IsBucketItem f => f -> DV -> Bool
+ Bayes.VariableElimination.Buckets: itemProduct :: IsBucketItem f => [f] -> f
+ Bayes.VariableElimination.Buckets: itemProjectOut :: IsBucketItem f => DV -> f -> f
+ Bayes.VariableElimination.Buckets: marginalizeOneVariable :: IsBucketItem f => Buckets f -> DV -> Buckets f
+ Bayes.VariableElimination.Buckets: removeFromBucket :: DV -> Buckets f -> Buckets f
+ Bayes.VariableElimination.Buckets: scalarItem :: IsBucketItem f => f -> Bool
+ Bayes.VariableElimination.Buckets: type EliminationOrder dv = [dv]
+ Bayes.VariableElimination.Buckets: updateBucket :: IsBucketItem f => DV -> f -> Buckets f -> Buckets f
- Bayes.Factor: changeFactor :: (FactorContainer m, Factor f) => f -> m f -> m f
+ Bayes.Factor: changeFactor :: (FactorContainer m, IsBucketItem f, Factor f) => f -> m f -> m f
- Bayes.Factor: displayFactorBody :: Factor f => f -> String
+ Bayes.Factor: displayFactorBody :: MultiDimTable f => f -> String
- Bayes.FactorElimination: createJunctionTree :: (DirectedGraph g, FoldableWithVertex g, NamedGraph g, Factor f, Show f) => (UndirectedSG () f -> Vertex -> Vertex -> Ordering) -> BayesianNetwork g f -> JunctionTree f
+ Bayes.FactorElimination: createJunctionTree :: (DirectedGraph g, FoldableWithVertex g, NamedGraph g, Factor f, IsBucketItem f, Show f) => (UndirectedSG () f -> Vertex -> Vertex -> Ordering) -> BayesianNetwork g f -> JunctionTree f
- Bayes.FactorElimination: posterior :: (BayesianDiscreteVariable dv, Factor f) => JunctionTree f -> dv -> Maybe f
+ Bayes.FactorElimination: posterior :: (BayesianDiscreteVariable dv, Factor f, IsBucketItem f) => JunctionTree f -> dv -> Maybe f
- Bayes.VariableElimination: marginal :: Factor f => [f] -> EliminationOrder DV -> EliminationOrder DV -> [DVI] -> f
+ Bayes.VariableElimination: marginal :: (IsBucketItem f, Factor f) => [f] -> EliminationOrder DV -> EliminationOrder DV -> [DVI] -> f
- Bayes.VariableElimination: posteriorMarginal :: (Graph g, Factor f, Show f, BayesianDiscreteVariable dva, BayesianDiscreteVariable dvb) => BayesianNetwork g f -> EliminationOrder dva -> EliminationOrder dvb -> [DVI] -> f
+ Bayes.VariableElimination: posteriorMarginal :: (Graph g, IsBucketItem f, Factor f, Show f, BayesianDiscreteVariable dva, BayesianDiscreteVariable dvb) => BayesianNetwork g f -> EliminationOrder dva -> EliminationOrder dvb -> [DVI] -> f
- Bayes.VariableElimination: priorMarginal :: (Graph g, Factor f, Show f, BayesianDiscreteVariable dva, BayesianDiscreteVariable dvb) => BayesianNetwork g f -> EliminationOrder dva -> EliminationOrder dvb -> f
+ Bayes.VariableElimination: priorMarginal :: (Graph g, IsBucketItem f, Factor f, Show f, BayesianDiscreteVariable dva, BayesianDiscreteVariable dvb) => BayesianNetwork g f -> EliminationOrder dva -> EliminationOrder dvb -> f

Files

Bayes.hs view
@@ -1,18 +1,18 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {- | Discrete Bayesian Network Library.  It is a very preliminary version. It has only been tested on very simple-examples where it worked. On bigger networks, imported from Hugin files, it was very very very slow.-So, you can use this software as a toy. Much more work is needed to validate-and optimize it. +examples where it worked. It should be considered as experimental and not used+in any production work.  Look at the "Bayes.Examples" and "Bayes.Examples.Tutorial" in this package  to see how to use the library. +In "Bayes.Examples.Influence" you'll find additional examples about influence diagrams.+ -} module Bayes(   -- * Graph@@ -22,7 +22,6 @@   , DirectedGraph(..)   , FoldableWithVertex(..)   , NamedGraph(..)-  , Distribution(..)   -- ** Graph Monad   , GraphMonad   , GMState(..)@@ -30,11 +29,18 @@   , runGraph   , execGraph   , evalGraph+  , emptyAuxiliaryState+  , getNewEmptyVariable+  , isRoot+  , rootNode+  , parentNodes+  , childrenNodes   -- ** Support functions for Graph constructions   , Vertex   , Edge    , edge   , newEdge+  , getVertex   , edgeEndPoints   , connectedGraph   , dag@@ -43,34 +49,11 @@   -- ** The SimpleGraph type   , DirectedSG   , UndirectedSG+  , SBN(..)+  , varMap+  , displaySimpleGraph   -- ** Bayesian network-  , SBN   , BayesianNetwork(..)-  -- * Bayesian Monad used to ease creation of Bayesian Networks-  , BNMonad-  , runBN -  , evalBN-  , execBN-  -- ** Variable creation-  , variable-  , unamedVariable-  , variableWithSize-  , tdv-  , t-  -- ** Creation of conditional probability tables-  , cpt-  , proba-  , (~~)-  , softEvidence-  , se-  -- ** Creation of truth tables-  , logical -  , (.==.)-  , (.!.)-  , (.|.)-  , (.&.)-  -- ** Noisy OR-  , noisyOR   -- * Testing   , testEdgeRemoval_prop   , testVertexRemoval_prop@@ -82,23 +65,27 @@ import Control.Monad.Writer.Strict import Control.Applicative((<$>)) import Bayes.Factor hiding(isEmpty)+import Bayes.Factor.CPT(CPT(..))+import Bayes.Factor.MaxCPT(MAXCPT(..)) import Data.Maybe import qualified Data.Map as Map import qualified Data.Foldable as F import qualified Data.Traversable as T  import Control.Applicative  import qualified Data.Set as Set-import qualified Data.List as L(find)  import Test.QuickCheck hiding ((.&.),Testable) import Test.QuickCheck.Arbitrary-import Data.List(sort,intercalate,nub)+import Data.List(sort,intercalate,nub,foldl') import Bayes.PrivateTypes hiding(isEmpty) import GHC.Float(float2Double)  --import Debug.Trace --debug a = trace (show a) a +-- | An implementation of the BayesianNetwork using the simple graph and no value for the edges+type SBN f = DirectedSG () f+ -- | Bayesian network. g must be a directed graph and f a factor type BayesianNetwork g f = g () f @@ -292,6 +279,27 @@     ingoing :: g a b -> Vertex -> Maybe [Edge]     outgoing :: g a b -> Vertex -> Maybe [Edge] +-- | Return the parents of a node+parentNodes :: DirectedGraph g => g a b -> Vertex -> [Vertex]+parentNodes g v = maybe [] id $ do +  ie <- ingoing g v+  p <- mapM (startVertex g) ie+  return p++-- | Return the children of a node+childrenNodes :: DirectedGraph g => g a b -> Vertex -> [Vertex]+childrenNodes g v = maybe [] id $ do +  ie <- outgoing g v+  p <- mapM (endVertex g) ie+  return p++isRoot :: DirectedGraph g => g a b -> Vertex -> Bool+{-# INLINE isRoot #-}+isRoot g v =+  case ingoing g v of +    Just [] -> True +    _ -> False+ -- | Get the root node for the graph rootNode :: DirectedGraph g => g a b -> Maybe Vertex rootNode g = @@ -300,11 +308,6 @@   case someRoots of      (h:l) -> Just h      _ -> Nothing-  where -    isRoot g v =-      case ingoing g v of -        Just [] -> True -        _ -> False  -- | Check if the graph is a directed Acyclic graph dag :: DirectedGraph g => g a b -> Bool @@ -333,12 +336,6 @@   -                          ----- | Edge type used to identify and edge in a graph-data Edge = Edge !Vertex !Vertex deriving(Eq,Ord,Show)- -- | Create an edge description edge :: Vertex -> Vertex -> Edge  {-# INLINE edge #-}@@ -349,15 +346,8 @@ edgeEndPoints (Edge va vb) = (va,vb)  --- | Synonym for undefined because it is clearer to use t to set the Enum bounds of a variable-t = undefined --- | Neighborhood structure for directed or undirected edges--- | Directed edges-data DE = DE ![Edge] ![Edge] deriving(Eq,Show) --- | Undirected edges-data UE = UE ![Edge] deriving(Eq,Show)  -- | Class used to share as much code as possible between -- directed and undirected graphs without@@ -402,24 +392,18 @@   addOutgoingEdge e (UE l) = UE (e:l)   addIngoingEdge e (UE l) = UE (e:l) --- | Implementtaion of a SimpleGraph-data SimpleGraph local edgedata vertexdata = SP {- -- | Mapping of edge to edge data-    edgeMap :: !(M.Map Edge edgedata) - -- ^ Mapping of vertex number to vertex neighborhood and vertex data- ,  vertexMap :: !(IM.IntMap (local, vertexdata))- -- ^ Vertex names. Used only to generate the graphviz representtaion. Names are useless for the algorithms- -- and I don't want them to appear in the vetex values which should only be factor. Otherwise, the algorithms- -- are less elegant since I have to extract the factors from the values- , nameMap :: !(IM.IntMap String)- }  + -- | Directed simple graph type DirectedSG = SimpleGraph DE  -- | Undirected simple graph type UndirectedSG = SimpleGraph UE +-- | Get the variable name mapping+varMap :: SimpleGraph n e v -> M.Map String Vertex +varMap (SP _ _ n) = M.fromList . map (\(i,s) -> (s, Vertex i)) . IM.toList $ n+ instance (Eq a, Eq b) => Eq (SimpleGraph DE a b) where     (==) (SP a b _) (SP a' b' _) = a == a' && b == b' @@ -668,6 +652,40 @@ Following code is used to display a graph in a form adapted to humans.  -}++bracketS :: String -> String +bracketS [] = []+bracketS s = " [" ++ s ++ "];"++createNodeStyle :: (MonadWriter String m) +                => (Vertex -> n -> Maybe String)+                -> (Vertex -> n -> Maybe String)+                -> Maybe String +                -> Vertex +                -> n +                -> m ()+createNodeStyle nodeShape nodeColor maybeLabel v n = +  let apply f = f v n+      label _ _ = case maybeLabel of +         Nothing -> Nothing +         Just s -> Just $ "label=\"" ++ s ++ "\""+  in +  tell $ bracketS . intercalate "," . mapMaybe apply $ [nodeShape,nodeColor, label]+  ++createEdgeStyle :: (MonadWriter String m) +                => (Edge -> e -> Maybe String)+                -> (Edge -> e -> Maybe String)+                -> Edge+                -> e +                -> m ()+createEdgeStyle edgeShape edgeColor e n = +  let apply f = f e n+  in +  tell $ bracketS . intercalate "," . mapMaybe apply $ [edgeShape,edgeColor]+++ printNode nm (Vertex k,v) = do    tell "\n"   let r = IM.lookup k nm@@ -676,59 +694,66 @@   tell "\n"   tell $ show v   tell "\n"-addVertexToGraphviz nm (k,(_,v)) = do++addVertexToGraphviz nodeShape nodeColor nm (k,(_,v)) = do   tell $ show k   let r = IM.lookup k $ nm -  when (isJust r) $ do-    tell " [label=\""-    tell $ fromJust r-    tell "\"] ;" +  createNodeStyle nodeShape nodeColor r (Vertex k) v   tell "\n" +addVertexToUndirectedGraphviz nm (k,(_,v)) = do+  tell $ show k+  tell "\n"+ -- | Print the values of the graph vertices printGraphValues :: (Graph (SimpleGraph n), Show b) => SimpleGraph n e b -> IO ()  printGraphValues g@(SP _ _ nm) = putStrLn . execWriter $ mapM_ (printNode nm) (allNodes g) -instance (Show b, Show e) => Show (DirectedSG e b)where-  show g@(SP em vm nm) = execWriter $ do+displaySimpleGraph :: (Vertex -> n -> Maybe String)+                   -> (Vertex -> n -> Maybe String)+                   -> (Edge -> e -> Maybe String)+                   -> (Edge -> e -> Maybe String)+                   -> SimpleGraph local e n +                   -> String +displaySimpleGraph  nodeShape nodeColor edgeShape edgeColor g@(SP em vm nm) = execWriter $ do    tell "digraph dot {\n"-  mapM_ (addVertexToGraphviz nm) $ IM.toList vm+  mapM_ (addVertexToGraphviz nodeShape nodeColor  nm) $ IM.toList vm   tell "\n"-  mapM_ addEdgeToGraphviz $ M.toList em+  mapM_ (addEdgeToGraphviz edgeShape edgeColor ) $ M.toList em   tell "}\n"    where-     addEdgeToGraphviz (Edge (Vertex vs) (Vertex ve),l) = do+     addEdgeToGraphviz es ec (e@(Edge (Vertex vs) (Vertex ve)),l) = do        tell $ show vs         tell " -> "        tell $ show ve-       tell " [label=\""-       tell $ show l-       tell "\"]"-       tell ";\n"+       createEdgeStyle es ec e l+       tell "\n"   +noNodeStyle _ _ = Nothing +noEdgeStyle _ _ = Nothing++instance Show (DirectedSG () CPT) where+  show g = displaySimpleGraph noNodeStyle noNodeStyle noEdgeStyle noEdgeStyle g++instance Show (DirectedSG () MAXCPT) where+  show g = displaySimpleGraph noNodeStyle noNodeStyle noEdgeStyle noEdgeStyle g++instance Show (DirectedSG String String) where+  show g = displaySimpleGraph noNodeStyle noNodeStyle noEdgeStyle noEdgeStyle g+ instance (Show b, Show e) => Show (UndirectedSG e b)where   show g@(SP em vm nm) = execWriter $ do   tell "graph dot {\n"-  mapM_ (addVertexToGraphviz nm) $ IM.toList vm+  mapM_ (addVertexToUndirectedGraphviz nm) $ IM.toList vm   tell "\n"-  mapM_ addEdgeToGraphviz $ M.toList em+  mapM_ (addEdgeToGraphviz) $ M.toList em   tell "}\n"    where-     addEdgeToGraphviz (Edge (Vertex vs) (Vertex ve),l) = do+     addEdgeToGraphviz (e@(Edge (Vertex vs) (Vertex ve)),l) = do        tell $ show vs         tell " -- "        tell $ show ve-       tell " [label=\""-       tell $ show l-       tell "\"]"-       tell ";\n"----- | Bayesian variable : name,dimension, factor--- When initialized it is using a factor with bayesian variables.--- But the factor value are not yet set-data MaybeBNode f = UninitializedBNode String Int-                  | InitializedBNode String Int f+       tell "\n"   displayFactors :: (NeighborhoodStructure n, Show f, Factor f, Graph (SimpleGraph n)) => SimpleGraph n a f -> String@@ -741,21 +766,20 @@   in   intercalate "\n" $ map displayFactor nodes --- | An implementation of the BayesianNetwork using the simple graph and no value of edges-type SBN f = DirectedSG () f+{- +Graph Monad++-}+++ -- | State used for the construction of the graph in the monad and containing -- auxiliary informations like vertex name to vertex id and vertex count type AuxiliaryState = (M.Map String Int, Int)  emptyAuxiliaryState = (M.empty,0) --- | The State for the monad with a mapping from variable name to variable ID.-type BNState g f = GMState g () (MaybeBNode f)---- | The Bayesian monad-type BNMonad g f a = GraphMonad g () (MaybeBNode f) a- -- | The state of the graph monad : the graph and auxiliary data -- useful during the construction type GMState g e f = (AuxiliaryState,g e f)@@ -765,18 +789,6 @@ -- g is the graph type. e the edge type. f the node type (generally a 'Factor') newtype GraphMonad g e f a = GM {runGraphMonad :: State (GMState g e f) a} deriving(Monad, MonadState (GMState g e f)) --- | Get the Bayesian Discrete Variable for a vertex.--- It works because we keep the variable dimension-factorVariable :: Graph g => Vertex -> BNMonad g f (Maybe DV)  -factorVariable v = do -  g <- gets snd -  let value = vertexValue g v-  case value of-    Nothing -> return Nothing-    Just (UninitializedBNode _ d) -> return $ Just $ DV v d-    Just (InitializedBNode _ d _) -> return $ Just $ DV v d-  - -- | Get a named vertex from the graph monad getVertex :: Graph g => String -> GraphMonad g e f (Maybe Vertex) getVertex a = do@@ -785,10 +797,6 @@     i <- M.lookup a namemap     return (Vertex i) --- | Create an edge between two vertex of the Bayesian network-(<--) :: Graph g => DV -> DV -> BNMonad g f ()-DV va _ <-- DV vb _ = newEdge vb va ()- -- | Add a new labeled edge to the graph newEdge :: Graph g => Vertex -> Vertex -> e -> GraphMonad g e f () newEdge va vb e = do@@ -797,97 +805,6 @@   put $! (aux,g1)   return () -whenJust Nothing _ = return ()-whenJust (Just i) f = f i >> return ()---- | Get the node of a bayesian network under creation-getBayesianNode :: Graph g => Vertex -> BNMonad g f (Maybe (MaybeBNode f))-getBayesianNode v = do-  g <- gets snd-  return $ vertexValue g v---- | Set the node of a bayesian network under creation-setBayesianNode :: Graph g => Vertex -> MaybeBNode f -> BNMonad g f ()-setBayesianNode v newValue = do-  (aux,oldGraph) <- get-  let newGraph = changeVertexValue v newValue oldGraph- -  whenJust newGraph $ \nvm -> do-     put $! (aux, nvm)---- | A distribution which can be used to create a factor-class Distribution d where-  -- | Create a factor from variables and a distributions for those variables-  createFactor :: Factor f => [DV] -> d -> Maybe f--instance Real a => Distribution [a] where -  createFactor dvs l = factorWithVariables dvs (map realToFrac l)--setCpt :: (DirectedGraph g, Distribution d, Factor f) -       => g () (MaybeBNode f )-       -> d -       -> Vertex -       -> Maybe DV -       -> MaybeBNode f -       -> BNMonad g f () -setCpt g _ _ _ (InitializedBNode _ _ _) = return ()-setCpt g l v current (UninitializedBNode s dim) = do -  let vertices = map (fromJust . startVertex g) . fromJust . ingoing g $ v-  fv <- mapM factorVariable vertices-  let cpt = createFactor (map fromJust (current:fv)) l-      newValue r = InitializedBNode s dim r-  maybe (return ()) (setBayesianNode v . newValue) cpt---- | Initialize the values of a factor-(~~) :: (DirectedGraph g, Factor f, Distribution d, BayesianDiscreteVariable v) -     => BNMonad g f v -- ^ Discrete variable in the graph-     -> d -- ^ List of values-     -> BNMonad g f ()-(~~) mv l = do -  (DV v _) <- mv >>= return . dv -- This is updating the state and so the graph-  g <- gets snd-  current <- factorVariable v-  mvalue <- getBayesianNode v-  maybe (return ()) (setCpt g l v current) mvalue---    -minBoundForEnum :: Bounded a => a -> a-minBoundForEnum _ = minBound--maxBoundForEnum :: Bounded a => a -> a-maxBoundForEnum _ = maxBound--intValue :: Enum a => a -> Int-intValue = fromEnum----- | Set the bound of a bayesian variable (number of levels)-setVariableBoundWithSize :: Graph g-                         => Vertex -- ^ Vertex-                         -> Int -- ^ Inf limit  (0 for instance)-                         -> Int -- ^ Sup limit (1 for instance for 2 elements)-                         -> BNMonad g f ()-setVariableBoundWithSize a bmin bmax = do-    v <- getBayesianNode a-    whenJust v $ \(UninitializedBNode s _) -> do-      setBayesianNode a (UninitializedBNode s (bmax - bmin + 1))--setVariableBound :: (Enum a, Bounded a, Graph g) -                 => Vertex -- ^ Vertex-                 -> a -- ^ Bounded variable (t :: type where t is undefined)-                 -> BNMonad g f ()-setVariableBound a e = -  let bmin = intValue $ minBoundForEnum e-      bmax = intValue $ maxBoundForEnum e-  in -  setVariableBoundWithSize a bmin bmax---- | Create a new named Bayesian variable if not found.--- Otherwise, return the found one.-addVariableIfNotFound :: NamedGraph g => String -> BNMonad g f Vertex-addVariableIfNotFound vertexName = graphNode vertexName (UninitializedBNode vertexName 0)- -- | Add a node in the graph using the graph monad graphNode :: NamedGraph g => String -> f -> GraphMonad g e f Vertex  graphNode vertexName initValue = do@@ -906,206 +823,6 @@   put $! ((namemap1,count+1),g1)   return (Vertex count) --- | Initialize a new variable-_initializeNewVariable :: (Enum a, Bounded a, NamedGraph g)-                       => Vertex -                       -> a -                       -> BNMonad g f (TDV a)-_initializeNewVariable va e = do -  setVariableBound va e-  maybeValue <- getBayesianNode va -  setBayesianNode va (fromJust maybeValue)-  case fromJust maybeValue of -     UninitializedBNode s d -> return (tdv $ DV va d)-     InitializedBNode _ d _ -> return (tdv $ DV va d) ---- | Create a new unamed variable-unamedVariable :: (Enum a, Bounded a, NamedGraph g)-               => a -- ^ Variable bounds -               -> BNMonad g f (TDV a)-unamedVariable e = do -  va <- getNewEmptyVariable Nothing (UninitializedBNode "unamed" 0)-  _initializeNewVariable va e---- | Define a Bayesian variable (name and bounds)-variable :: (Enum a, Bounded a, NamedGraph g) -        => String -- ^ Variable name-        -> a -- ^ Variable bounds-        -> BNMonad g f (TDV a)-variable name e = do-  va <- addVariableIfNotFound name-  _initializeNewVariable va e---- | Define a Bayesian variable (name and bounds)-variableWithSize :: NamedGraph g-        => String -- ^ Variable name-        -> Int -- ^ Variable size-        -> BNMonad g f DV-variableWithSize name e = do-  va <- addVariableIfNotFound name-  _initializeNewVariableWithSize va e---- | Define a Bayesian variable (name and bounds)-unNamedVariableWithSize :: NamedGraph g-                        => Int -- ^ Variable size-                        -> BNMonad g f DV-unNamedVariableWithSize e = do-  va <- getNewEmptyVariable Nothing (UninitializedBNode "unamed" 0)-  _initializeNewVariableWithSize va e---- | Initialize a new variable with size-_initializeNewVariableWithSize :: NamedGraph g-                               => Vertex -- ^ Variable name-                               -> Int -- ^ Variable size-                               -> BNMonad g f DV-_initializeNewVariableWithSize va e = do-  setVariableBoundWithSize va 0 (e-1)-  maybeValue <- getBayesianNode va -  setBayesianNode va (fromJust maybeValue)-  case fromJust maybeValue of -     UninitializedBNode s d -> return (DV va d)-     InitializedBNode _ d _ -> return (DV va d)---- | Define a conditional probability between different variables--- Variables are ordered like--- FFF FFT FTF FTT TFF TFT TTF TTT--- and same for other enumeration keeping enumeration order-cpt :: (DirectedGraph g , BayesianDiscreteVariable v,BayesianDiscreteVariable vb) => v -> [vb] -> BNMonad g f v-cpt node conditions = do-  mapM_ ((dv node) <--) (reverse (map dv conditions))-  return node---- | Define proba for a variable--- Values are ordered like--- FFF FFT FTF FTT TFF TFT TTF TTT--- and same for other enumeration keeping enumeration order-proba :: (DirectedGraph g, BayesianDiscreteVariable v) => v -> BNMonad g f v-proba node = cpt node ([] :: [DV])---- | Create an auxiliairy node to force soft evidence-softEvidence :: (NamedGraph g, DirectedGraph g, Factor f) -             => TDV Bool -- ^ Variable on which we want to define Soft evidence-             -> BNMonad g f (TDV Bool) -- ^ Return a soft evidence node (for the factor encoding the soft evidence values)-             -- and an hard evidence node to activate the soft evidence observation-softEvidence d = do -  se <- unNamedVariableWithSize (dimension d) -  --seEnabled <- unNamedVariableWithSize (dimension d) --  cpt se [dv d] ~~ [1.0,0.0,1.0,0.0]-  --cpt seEnabled [dv se] ~~ [1.0,0.0,0.0,1.0] -- No info about the observation of the soft evidence node-  return (tdv se) ---- | Soft evidence factor-se :: Factor f -   => TDV s -- ^ Soft evidence node-   -> TDV s -- ^ Node on which the soft evidence is imposed-   -> Double -- ^ Soft evidence (probability of right detection)-   -> Maybe f-se s orgNode p = factorWithVariables [dv s,dv orgNode] [p,1-p,1-p,p]--{---Helper functions to create logical distributions  ---}--data LE = LETest DVI-        | LEAnd LE LE -        | LEOr LE LE -        | LENot LE -        deriving(Eq)---- | Generate the variables used in the expression-varsFromLE :: LE -> [DV]-varsFromLE le = nub $ _getVars le - where -  _getVars  (LETest dvi) = [dv dvi] -  _getVars (LEAnd a b) = _getVars a ++ _getVars b-  _getVars (LEOr a b) = _getVars a ++ _getVars b-  _getVars (LENot a) = _getVars a--boolValue :: Maybe Bool -> Bool -boolValue (Just True) = True -boolValue _ = False---- | Generate values for the LE-functionFromLE :: LE -> ([DVI] -> Bool)-functionFromLE (LETest dvi) = \i -> boolValue $ do -  var <- L.find (== dvi) i-  return (instantiationValue dvi == instantiationValue var)-functionFromLE (LENot l) = \i -> not (functionFromLE l i)-functionFromLE (LEAnd la lb) = \i -> (functionFromLE la i) && (functionFromLE lb i)-functionFromLE (LEOr la lb) = \i -> (functionFromLE la i) || (functionFromLE lb i)--class Testable d v where -  -- | Create a variable instantiation using values from-  -- an enumeration-  (.==.) :: d -> v -> LE --instance Instantiable d v => Testable d v where -  (.==.) a b = LETest (a =: b)--infixl 8 .==.-infixl 6 .&.-infixl 5 .|.--(.|.) :: LE -> LE -> LE-(.|.)  = LEOr --(.&.) :: LE -> LE -> LE-(.&.) = LEAnd--(.!.) :: LE -> LE-(.!.) = LENot--logical :: (Factor f, DirectedGraph g) => TDV Bool -> LE -> BNMonad g f () -logical dv l = -  let theVars = varsFromLE l-      logicalF = functionFromLE l -      probaVal True = 1.0 :: Double-      probaVal False = 0.0 :: Double-      valuesF = [probaVal (logicalF i == False) | i <-forAllInstantiations (DVSet theVars)]-      valuesT = [probaVal (logicalF i == True) | i <-forAllInstantiations (DVSet theVars)]--  in -  cpt dv theVars ~~ (valuesF ++ valuesT)--{---Noisy OR---}---- | Noisy AND. Variable A is passed with probability 1-p-noisyAND :: (DirectedGraph g, Factor f, NamedGraph g) => TDV Bool -> Double -> BNMonad g f (TDV Bool) -noisyAND a p = do -    na <- unamedVariable (t::Bool)-    cpt na [dv a] ~~ [1-p,p,p,1-p]-    return na ---- | OR Gate-orG :: (DirectedGraph g, Factor f, NamedGraph g) => TDV Bool -> TDV Bool -> BNMonad g f (TDV Bool)-orG a b = do -    no <- unamedVariable (t::Bool)-    logical no ((a .==. True) .|. (b .==. True))-    return no ---- | Noisy OR. The Noisy-OR with leak can be implemented by using the--- standard Noisy-OR and a leak variable.-noisyOR :: (DirectedGraph g, Factor f, NamedGraph g) -        => [(TDV Bool,Double)] -- ^ Variables and probability of no influence-        -> BNMonad g f (TDV Bool) -noisyOR l = do -    a <- mapM (\(a,p) -> noisyAND a p) l-    foldM orG (head a) (tail a)--{-- -Graph creation from the Monad.  ---}-- runGraph :: Graph g => GraphMonad g e f a -> (a,g e f) runGraph = removeAuxiliaryState . flip runState (emptyAuxiliaryState,emptyGraph) . runGraphMonad   where @@ -1116,29 +833,3 @@  execGraph :: Graph g => GraphMonad g e f a -> g e f execGraph = snd . flip execState (emptyAuxiliaryState,emptyGraph) . runGraphMonad ---- | Create a bayesian network using the simple graph implementation--- The initialized nodes are replaced by the factor.--- Returns the monad values and the built graph.-runBN :: BNMonad DirectedSG f a -> (a,DirectedSG () f)-runBN x = -  let (r,g) = runGraph x-      convertBNodes (InitializedBNode s d f) = f -      convertBNodes (UninitializedBNode s d) = error $ "All variables must be initialized with a factor: " ++ s ++ "(" ++ show d ++ ")"-  in -  (r,fmap convertBNodes g)---- | Create a bayesian network but only returns the monad value.--- Mainly used for testing.-evalBN :: BNMonad DirectedSG f a -> a-evalBN = evalGraph---- | Create a bayesian network but only returns the monad value.--- Mainly used for testing.-execBN :: BNMonad DirectedSG f a -> DirectedSG () f-execBN x = -  let g = execGraph x-      convertBNodes (InitializedBNode s d f) = f -      convertBNodes (UninitializedBNode s d) = error $ "All variables must be initialized with a factor: " ++ s ++ "(" ++ show d ++ ")"-  in -  fmap convertBNodes g
+ Bayes/BayesianNetwork.hs view
@@ -0,0 +1,224 @@+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}+{- | Module for building Bayesian Networks++-}+module Bayes.BayesianNetwork(+  -- * Bayesian Monad used to ease creation of Bayesian Networks+    BNMonad+  , runBN +  , evalBN+  , execBN+  , Distribution(..)+  -- ** Variable creation+  , variable+  , unamedVariable+  , variableWithSize+  , tdv+  , t+  -- ** Creation of conditional probability tables+  , cpt+  , proba+  , (~~)+  , softEvidence+  , se+  -- ** Creation of truth tables+  , logical +  , (.==.)+  , (.!.)+  , (.|.)+  , (.&.)+  -- ** Noisy OR+  , noisyOR+  ) where++import Bayes+import Bayes.PrivateTypes+import Control.Monad.State.Strict+import Bayes.Factor+import Data.Maybe(fromJust)+import qualified Data.List as L(find)+import Data.List(sort,intercalate,nub)+import Bayes.Tools(minBoundForEnum,maxBoundForEnum,intValue)+import Bayes.Network ++-- | Synonym for undefined because it is clearer to use t to set the Enum bounds of a variable+t = undefined++-- | The Bayesian monad+type BNMonad g f a = NetworkMonad g () f a++-- | Initialize the values of a factor+(~~) :: (DirectedGraph g, Factor f, Distribution d, BayesianDiscreteVariable v) +     => BNMonad g f v -- ^ Discrete variable in the graph+     -> d -- ^ List of values+     -> BNMonad g f ()+(~~) mv l = do +  (DV v _) <- mv >>= return . dv -- This is updating the state and so the graph+  maybeNewValue <- getCpt v l+  currentValue <- getBayesianNode v+  case (currentValue, maybeNewValue) of +    (Just c, Just n) -> initializeNodeWithValue v c n+    _ -> return ()+++-- | Define a conditional probability between different variables+-- Variables are ordered like+-- FFF FFT FTF FTT TFF TFT TTF TTT+-- and same for other enumeration keeping enumeration order+-- Note that the reverse is important. We add the parents in such a way that 'ingoing'+-- will give a list of parents in the right order.+-- This order must correspond to the order of values in the initialization.+cpt :: (DirectedGraph g , BayesianDiscreteVariable v,BayesianDiscreteVariable vb) => v -> [vb] -> BNMonad g f v+cpt node conditions = do+  mapM_ ((dv node) <--) (reverse (map dv conditions))+  return node++-- | Define proba for a variable+-- Values are ordered like+-- FFF FFT FTF FTT TFF TFT TTF TTT+-- and same for other enumeration keeping enumeration order+proba :: (DirectedGraph g, BayesianDiscreteVariable v) => v -> BNMonad g f v+proba node = cpt node ([] :: [DV])++-- | Create an auxiliairy node to force soft evidence+softEvidence :: (NamedGraph g, DirectedGraph g, Factor f) +             => TDV Bool -- ^ Variable on which we want to define Soft evidence+             -> BNMonad g f (TDV Bool) -- ^ Return a soft evidence node (for the factor encoding the soft evidence values)+             -- and an hard evidence node to activate the soft evidence observation+softEvidence d = do +  se <- unNamedVariableWithSize (dimension d) +  --seEnabled <- unNamedVariableWithSize (dimension d) ++  cpt se [dv d] ~~ [1.0,0.0,1.0,0.0]+  --cpt seEnabled [dv se] ~~ [1.0,0.0,0.0,1.0] -- No info about the observation of the soft evidence node+  return (tdv se) ++-- | Soft evidence factor+se :: Factor f +   => TDV s -- ^ Soft evidence node+   -> TDV s -- ^ Node on which the soft evidence is imposed+   -> Double -- ^ Soft evidence (probability of right detection)+   -> Maybe f+se s orgNode p = factorWithVariables [dv s,dv orgNode] [p,1-p,1-p,p]++{-++Helper functions to create logical distributions  ++-}++data LE = LETest DVI+        | LEAnd LE LE +        | LEOr LE LE +        | LENot LE +        deriving(Eq)++-- | Generate the variables used in the expression+varsFromLE :: LE -> [DV]+varsFromLE le = nub $ _getVars le + where +  _getVars  (LETest dvi) = [dv dvi] +  _getVars (LEAnd a b) = _getVars a ++ _getVars b+  _getVars (LEOr a b) = _getVars a ++ _getVars b+  _getVars (LENot a) = _getVars a++boolValue :: Maybe Bool -> Bool +boolValue (Just True) = True +boolValue _ = False++-- | Generate values for the LE+functionFromLE :: LE -> ([DVI] -> Bool)+functionFromLE (LETest dvi) = \i -> boolValue $ do +  var <- L.find (== dvi) i+  return (instantiationValue dvi == instantiationValue var)+functionFromLE (LENot l) = \i -> not (functionFromLE l i)+functionFromLE (LEAnd la lb) = \i -> (functionFromLE la i) && (functionFromLE lb i)+functionFromLE (LEOr la lb) = \i -> (functionFromLE la i) || (functionFromLE lb i)++class Testable d v where +  -- | Create a variable instantiation using values from+  -- an enumeration+  (.==.) :: d -> v -> LE ++instance Instantiable d v => Testable d v where +  (.==.) a b = LETest (a =: b)++infixl 8 .==.+infixl 6 .&.+infixl 5 .|.++(.|.) :: LE -> LE -> LE+(.|.)  = LEOr ++(.&.) :: LE -> LE -> LE+(.&.) = LEAnd++(.!.) :: LE -> LE+(.!.) = LENot++logical :: (Factor f, DirectedGraph g) => TDV Bool -> LE -> BNMonad g f () +logical dv l = +  let theVars = varsFromLE l+      logicalF = functionFromLE l +      probaVal True = 1.0 :: Double+      probaVal False = 0.0 :: Double+      valuesF = [probaVal (logicalF i == False) | i <-forAllInstantiations (DVSet theVars)]+      valuesT = [probaVal (logicalF i == True) | i <-forAllInstantiations (DVSet theVars)]++  in +  cpt dv theVars ~~ (valuesF ++ valuesT)++{-++Noisy OR++-}++-- | Noisy AND. Variable A is passed with probability 1-p+noisyAND :: (DirectedGraph g, Factor f, NamedGraph g) => TDV Bool -> Double -> BNMonad g f (TDV Bool) +noisyAND a p = do +    na <- unamedVariable (t::Bool)+    cpt na [dv a] ~~ [1-p,p,p,1-p]+    return na ++-- | OR Gate+orG :: (DirectedGraph g, Factor f, NamedGraph g) => TDV Bool -> TDV Bool -> BNMonad g f (TDV Bool)+orG a b = do +    no <- unamedVariable (t::Bool)+    logical no ((a .==. True) .|. (b .==. True))+    return no ++-- | Noisy OR. The Noisy-OR with leak can be implemented by using the+-- standard Noisy-OR and a leak variable.+noisyOR :: (DirectedGraph g, Factor f, NamedGraph g) +        => [(TDV Bool,Double)] -- ^ Variables and probability of no influence+        -> BNMonad g f (TDV Bool) +noisyOR l = do +    a <- mapM (\(a,p) -> noisyAND a p) l+    foldM orG (head a) (tail a)++{-+ +Graph creation from the Monad.  ++-}++-- | Create a  network using the simple graph implementation+-- The initialized nodes are replaced by the value.+-- Returns the monad values and the built graph.+runBN :: BNMonad DirectedSG f a -> (a,SBN f)+runBN = runNetwork++-- | Create a  network but only returns the monad value.+-- Mainly used for testing.+execBN :: BNMonad DirectedSG f a -> SBN f+execBN = execNetwork++-- | Create a bayesian network but only returns the monad value.+-- Mainly used for testing.+evalBN :: BNMonad DirectedSG f a -> a+evalBN = evalNetwork++
Bayes/Examples.hs view
@@ -152,7 +152,7 @@ import System.Directory(getHomeDirectory) import System.FilePath((</>)) import Bayes.Factor.CPT-+import Bayes.BayesianNetwork  #ifndef LOCAL import Paths_hbayes
+ Bayes/Examples/Influence.hs view
@@ -0,0 +1,289 @@+{-# LANGUAGE ViewPatterns #-}+{- | Examples of influence diagrams++An influence diagram is an extension of a Bayesian network with can be used to solve some decision problems.+In an influence diagram, there are two new kind of nodes : decision nodes and utility nodes.++Solving an influence diagram means determining the strategies for each decision variable that will maximize the average utility.++There must be an ordering of the decision variables : a path through all the decisions.++A decision variable can depend on other past decisions and probabilistic nodes. In the later case, the variable of +the probabilistic node is assumed to be observed before the decision is taken. So, the decision is only trying to +maximize the average utility based on what has not been observed (the future and some past probabilistic variables).++A probabilistic node can depend on other probabilistic nodes (like in a Bayesian network) and decision nodes.++An utility is a leaf of the graph.++/Example graph/++Building an influence diagram is done like for a Bayesian network : by using the right monad.++@+import Bayes.InfluenceDiagram +studentSimple = snd . 'runID' $ do+@++Then, you create the different nodes of the graph:++@+    e <- 'decisionNode' \"E\" ('t' :: E)+    uc <- 'utilityNode' \"UC\"+    ub <- 'utilityNode' \"UB\"+    i <- 'chance' "I" ('t' :: I)+    pr <- 'chance' "P" ('t' :: Bool)+@++The types used above are:++@+data E = Dont | Do deriving(Eq,Enum,Bounded)+data I = Low | Average | High deriving(Eq,Enum,Bounded)+@++Then, you need to define the dependencies and the numerical values. For probabilistic nodes, it is done like+for Bayesian network:++@+    cpt pr ['d' e] ~~ [1-0.0000001,1 - 0.001,0.0000001, 0.001]+    cpt i ['p' pr, 'd' e] ~~ [0.2,0.1,0.01,0.01,0.6,0.5,0.04,0.04,0.2,0.4,0.95,0.95]+@++The list may contain decision variables of type 'DEV' and probabilistic variables of type 'DV' or 'TDV'. So, the +functions 'p' an 'd' are used for the embedding in the heterogenous list.++For decision nodes, the method is similar but with two differences : The first decision may depend on nothing (just on the assumed future).+And there are no values to define for a decision variable since the goal of the influence diagram is to compute them.++@+    'decision' e 'noDependencies'+@++For the utility nodes, it is similar to probabilistic nodes. You define the dependencies and the numerical values:++@+    'utility' uc [e] ~~ [0,-50000]+    'utility' ub [i] ~~ [100000,200000,500000]+@+  +Once the influence diagram is defined, you can solve it:++@+    'solveInfluenceDiagram' studentSimple+@++The result of this function is the solution : the decision strategies. You may want to display also the original+graph to see to which node are corresponding the vertex numbers.++/Policy Network/++You can transform a solved influence diagram into a policy network : a Bayesian network where decision variables have been replaced+with probabilistic variables where the conditional probability table is containing 1 for a choice of variables corresponding+to the decision and 0 otherwise.++@+    let l = 'solveInfluenceDiagram' student+        g = 'policyNetwork' l student+    print g +    'printGraphValues' g+@ ++-}+module Bayes.Examples.Influence(+    -- * Influence diagrams+      exampleID+    , student+    , studentSimple+    , market +    -- * Variables for some networks+    , studentDecisionVars+    , studentSimpleDecisionVar+    -- * Tests for the networks+    , theTest+    , policyTest+    , marketTest+    ) where ++import Bayes.InfluenceDiagram +import Bayes(printGraphValues)+import Bayes.Factor(forAllInstantiations,dv,instantiationValue,DVSet(..))++-- | Very simple example with one decision node+exampleID :: InfluenceDiagram+exampleID = snd . runID $ do +    a <- chance "A" (t :: Bool)+    d1 <- decisionNode "D" (t :: Bool)+    u <- utilityNode "U"++    proba a ~~ [0.8,0.1]+    decision d1 [a]+    utility u [d d1,p a] ~~ [1,10,8,2]+    return ()++data E = Dont | Do deriving(Eq,Enum,Bounded)+data I = Low | Average | High deriving(Eq,Enum,Bounded)+data S = Found | DontFound deriving(Eq,Enum,Bounded)++studentSimpleDecisionVar :: DEV ++-- | Student network as found in the book by Barber+studentSimple :: InfluenceDiagram+(studentSimpleDecisionVar,studentSimple) = runID $ do +    e <- decisionNode "E" (t :: E)++    uc <- utilityNode "UC"+    ub <- utilityNode "UB"++    i <- chance "I" (t :: I)+    pr <- chance "P" (t :: Bool)++    cpt pr [d e] ~~ [1-0.0000001,1 - 0.001,0.0000001, 0.001]++    cpt i [p pr, d e] ~~ [0.2,0.1,0.01,0.01,0.6,0.5,0.04,0.04,0.2,0.4,0.95,0.95]+    decision e noDependencies++    utility uc [e] ~~ [0,-50000]+    utility ub [i] ~~ [100000,200000,500000]+    return e++-- | Solve the influences diagrams for the both student network.+-- Also displays each network+theTest = do+    print studentSimple+    printGraphValues studentSimple+    putStrLn "RESULT"+    print $ solveInfluenceDiagram studentSimple+    putStrLn "----"+    print student+    printGraphValues student+    putStrLn "RESULT"+    print $ solveInfluenceDiagram student+++-- | Solve the influence diagram 'student' and convert it into+-- a policy network+policyTest = do +    print student +    printGraphValues student+    let l = solveInfluenceDiagram student+        g = policyNetwork l student+    print g +    printGraphValues g++studentDecisionVars :: (DEV,TDV Bool,DEV)   ++-- | Student network as found in the book by Barber+student :: InfluenceDiagram+(studentDecisionVars,student) = runID $ do +    e <- decisionNode "E" (t :: E)+    s <- decisionNode "S" (t :: S)++    uc <- utilityNode "UC"+    ub <- utilityNode "UB"+    us <- utilityNode "US"++    pr <- chance "P" (t :: Bool)+    i <- chance "I" (t :: I)++    cpt pr [d e] ~~ [1-0.0000001,1 - 0.001,0.0000001, 0.001]++    cpt i [p pr, d s] ~~ [0.2,0.1,0.05,0.005, 0.6,0.5,0.15,0.005,0.2,0.4,0.8,0.99]+    decision s [pr]+    decision e noDependencies++    utility uc [e] ~~ [0,-50000]+    utility ub [i] ~~ [100000,200000,500000]+    utility us [s] ~~ [0,-200000]+    return (e,pr,s)+++{- ++Test with a market network+    +-}+data F = Forecast | NoForecast deriving(Eq,Enum,Bounded)+data IN = Choice0 | Choice1 | Choice2 deriving(Eq,Enum,Bounded)+data EF = Up | Flat | Down deriving(Eq,Enum,Bounded)++genValues :: ([DVI] -> Double) -> [DV] -> [Double]+genValues f l = [f x | x <- forAllInstantiations (DVSet l)]++e :: Enum a => DVI -> a+e = toEnum . instantiationValue ++vf :: [DVI] -> (EF,F,EF)+vf [a,b,c] = (e a, e b, e c)+vf _ = (toEnum 0, toEnum 0, toEnum 0)++uf :: [DVI] -> (EF,IN,F)+uf [a,b,c] = (e a, e b, e c)+uf _ = (toEnum 0, toEnum 0, toEnum 0)++getForecastUtility (uf -> (Up, Choice0, Forecast)) = 1500+getForecastUtility (uf -> (Up, Choice0, NoForecast)) = 1500+getForecastUtility (uf -> (Up, Choice1, Forecast)) = 1000+getForecastUtility (uf -> (Up, Choice1, NoForecast)) = 1000+getForecastUtility (uf -> (Up, Choice2, Forecast)) = 500+getForecastUtility (uf -> (Up, Choice2, NoForecast)) = 500++getForecastUtility (uf -> (Flat, Choice0, Forecast)) = 100+getForecastUtility (uf -> (Flat, Choice0, NoForecast)) = 100+getForecastUtility (uf -> (Flat, Choice1, Forecast)) = 200+getForecastUtility (uf -> (Flat, Choice1, NoForecast)) = 200+getForecastUtility (uf -> (Flat, Choice2, Forecast)) = 500+getForecastUtility (uf -> (Flat, Choice2, NoForecast)) = 500++getForecastUtility (uf -> (Down, Choice0, Forecast)) = -1000+getForecastUtility (uf -> (Down, Choice0, NoForecast)) = -1000+getForecastUtility (uf -> (Down, Choice1, Forecast)) = -100+getForecastUtility (uf -> (Down, Choice1, NoForecast)) = -100+getForecastUtility (uf -> (Down, Choice2, Forecast)) = 500+getForecastUtility (uf -> (Down, Choice2, NoForecast)) = 500++getForecastProba (vf -> (Up,Forecast,Up)) = 0.8+getForecastProba (vf -> (Up,Forecast,Flat)) = 0.15+getForecastProba (vf -> (Up,Forecast,Down)) = 0.2+getForecastProba (vf -> (Up,NoForecast,Up)) = 0.33+getForecastProba (vf -> (Up,NoForecast,Flat)) = 0.33+getForecastProba (vf -> (Up,NoForecast,Down)) = 0.33++getForecastProba (vf -> (Flat,Forecast,Up)) = 0.1+getForecastProba (vf -> (Flat,Forecast,Flat)) = 0.7+getForecastProba (vf -> (Flat,Forecast,Down)) = 0.2+getForecastProba (vf -> (Flat,NoForecast,Up)) = 0.33+getForecastProba (vf -> (Flat,NoForecast,Flat)) = 0.33+getForecastProba (vf -> (Flat,NoForecast,Down)) = 0.33++getForecastProba (vf -> (Down,Forecast,Up)) = 0.1+getForecastProba (vf -> (Down,Forecast,Flat)) = 0.15+getForecastProba (vf -> (Down,Forecast,Down)) = 0.6+getForecastProba (vf -> (Down,NoForecast,Up)) = 0.33+getForecastProba (vf -> (Down,NoForecast,Flat)) = 0.33+getForecastProba (vf -> (Down,NoForecast,Down)) = 0.33++-- | Market diagram+market :: InfluenceDiagram+market = snd . runID $ do +    o <- decisionNode "Obtain Forecast" (t :: F)+    i <- decisionNode "Investment" (t :: IN)++    ef <- chance "Economy Forecast" (t :: EF)+    ma <- chance "Market Activity" (t :: EF)++    u <- utilityNode "Payoff"++    proba ma ~~ [0.5,0.3,0.2]+    decision o noDependencies +    decision i [d o,p ef]+    cpt ef [d o, p ma] ~~ (genValues getForecastProba [dv ef, dv o, dv ma])+    utility u [p ma, d i, d o] ~~ (genValues getForecastUtility [dv ma, dv i, dv o])+    return ()++-- | Solve the 'market' influence diagram+marketTest = do +    print market +    printGraphValues market+    let l = solveInfluenceDiagram market+    print l 
Bayes/Examples/Tutorial.hs view
@@ -249,6 +249,8 @@ import Data.Maybe(fromJust,mapMaybe) import System.Exit(exitSuccess) import qualified Data.List as L((\\))+import Bayes.BayesianNetwork(se)+  #ifdef LOCAL miscDiabete = do 
Bayes/Factor.hs view
@@ -6,6 +6,8 @@ module Bayes.Factor(  -- * Factor    Factor(..)+ , Distribution(..)+ , MultiDimTable(..)  , isomorphicFactor  , normedFactor  , displayFactorBody@@ -19,10 +21,11 @@  -- ** Discrete variables and instantiations  , DV(..)  , TDV- --, DVSet(..)+ , DVSet(..)  , DVI  , DVISet  , tdvi+ , tdv  , setDVValue  , instantiationValue  , instantiationVariable@@ -38,11 +41,23 @@ import Bayes.Tools import qualified Data.Vector.Unboxed as V import Text.PrettyPrint.Boxes hiding((//))+import Bayes.VariableElimination.Buckets(IsBucketItem(..))  --import Debug.Trace  --debug a = trace ("\nDEBUG\n" ++ show a ++ "\n") a +++-- | A distribution which can be used to create a factor+class Distribution d where+  -- | Create a factor from variables and a distributions for those variables+  createFactor :: Factor f => [DV] -> d -> Maybe f++instance Real a => Distribution [a] where +  createFactor dvs l = factorWithVariables dvs (map realToFrac l)++ -- | Change factor in a functor (only factor values should have been changed) -- It assumes that the variables of a factor are enough to identify it. -- If the functor is containing several factors with same set of variables then it@@ -59,7 +74,7 @@ -- It is making sense when the factors are related to the nodes of a Bayesian -- network.  class FactorContainer m where -   changeFactor :: Factor f => f -> m f -> m f +   changeFactor :: (IsBucketItem f,Factor f) => f -> m f -> m f   instance FactorContainer [] where      changeFactor = changeFactorInFunctor@@ -171,15 +186,6 @@         in          factorProjectOut s' f --------- -- | Test equality of two factors taking into account the fact -- that the variables may be in a different order. -- In case there is a distinction between conditionned variable and@@ -203,16 +209,22 @@ Following functions are used to typeset the factor when displaying it  -}++-- | Class used to display multidimensional tables+class MultiDimTable f where +    elementStringValue :: f -> [DVI] -> String+    tableVariables :: f -> [DV]   + -- | Display a variable name and its size vname :: Int -> DVI -> Box vname vc i = text $ "v" ++ show vc ++ "=" ++ show (instantiationValue i) -dispFactor :: Factor f => f -> DV -> [DVI] -> [DV] -> Box+dispFactor :: MultiDimTable f => f -> DV -> [DVI] -> [DV] -> Box dispFactor cpt h c [] =      let dstIndexes = allInstantiationsForOneVariable h         dependentIndexes =  reverse c         factorValueAtPosition p = -            let v = factorStringValue cpt p+            let v = elementStringValue cpt p             in             text v     in@@ -223,9 +235,9 @@     in     hsep 1 top . map (\i -> vcat center1 [vname vc i,dispFactor cpt dst (i:c) l])  $ allInst -displayFactorBody :: Factor f => f -> String +displayFactorBody :: MultiDimTable f => f -> String  displayFactorBody c = -        let d = factorVariables c+        let d = tableVariables c             h@(DV (Vertex vc) _) = head d             table = dispFactor c h [] (tail d)             dstIndexes = map head (forAllInstantiations . DVSet $ [h])
Bayes/Factor/CPT.hs view
@@ -10,6 +10,8 @@    -- * CPT Factor      CPT    , changeVariableOrder+   , cptDivide+   , cptSum    -- * Tests    , testProductProject_prop    , testAssocProduct_prop@@ -29,6 +31,8 @@ import Data.Maybe(fromJust,mapMaybe,isJust) import Bayes.Factor.PrivateCPT import Bayes.PrivateTypes+import Bayes.VariableElimination.Buckets(IsBucketItem(..))+import qualified Data.Vector.Unboxed as V  -- | Soft evidence factor can be used to initialize a factor --instance Distribution CPT where @@ -108,6 +112,9 @@     scale = (*)     multiply = (*)     elementUnit = 1.0+    divide _ 0 = 0+    divide a b = a / b +    elementSum = (+)   instance Factor CPT where@@ -129,13 +136,32 @@          evidenceFrom = _evidenceFrom -    factorProduct = _factorProduct+    factorProduct = _factorProduct multiply          factorProjectOut _ f@(Scalar v) = f     factorProjectOut s f= cptFactorProjectOutWith (sum . map fst) s f -+--  Divie two CPT+cptDivide :: CPT -> CPT -> CPT+cptDivide a b = _factorProduct multiply [a,invertCPT b] +invertCPT (Scalar a) = Scalar (1.0 / a)+invertCPT (Table d m v) = Table d m (V.map inv v)+ where +    inv x = 1.0 / x+-- Warning, the fold in factorProduct may not do the operations in the order you expect.+-- Since a/b is different from b/a we have to take this into account. So, the order is changed in the list +cptSum :: [CPT] -> CPT+cptSum = _factorProduct elementSum +instance IsBucketItem CPT where +    scalarItem = isScalarFactor+    itemProduct = factorProduct+    itemProjectOut d = factorProjectOut [d]+    itemContainsVariable = containsVariable +instance MultiDimTable CPT where +    elementStringValue = factorStringValue+    tableVariables = factorVariables+      
Bayes/Factor/MaxCPT.hs view
@@ -16,6 +16,7 @@ import qualified Data.IntMap as IM import Data.List(maximumBy) import Data.Function(on)+import Bayes.VariableElimination.Buckets(IsBucketItem(..))  --import Debug.Trace  @@ -29,6 +30,8 @@     multiply (da,la) (db,[]) = (da*db,la)     multiply (da,la) (db,lb) = (da*db,[xa ++ xb | xa <- la, xb <- lb])     elementUnit = (1.0,[])+    divide _ _ = error "It does not make sense to divide MAXCPT elements"+    elementSum _ _ = error "It does not make sense to sum MAXCPT elements"  instantiationProba :: ((Double,PossibleInstantiations), DVISet) -> Double instantiationProba (a,b) = fst a @@ -62,7 +65,7 @@      evidenceFrom = _evidenceFrom -    factorProduct = _factorProduct+    factorProduct = _factorProduct multiply          factorProjectOut _ f@(Scalar v) = f     factorProjectOut s f = cptFactorProjectOutWith maximization s f@@ -73,8 +76,17 @@  instance Show MAXCPT where     show (Scalar v) = "\nScalar Factor:\n" ++ show v-    show c@(Table [] _ v) = "\nEmpty CPT:\n"+    show c@(Table [] _ v) = "\nEmpty MAXCPT:\n"      show c = displayFactorBody c   +instance IsBucketItem MAXCPT where +    scalarItem = isScalarFactor+    itemProduct = factorProduct+    itemProjectOut d = factorProjectOut [d]+    itemContainsVariable = containsVariable++instance MultiDimTable MAXCPT where +    elementStringValue = factorStringValue+    tableVariables = factorVariables 
Bayes/Factor/PrivateCPT.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-} {- | Private functions used to implement CPT  -}@@ -9,6 +10,7 @@      cptFactorProjectOutWith    -- ** Private functions    , FactorElement(..)+   , DecisionFactor(..)    , _emptyFactor    , _factorVariables    , _isScalarFactor@@ -29,6 +31,8 @@    , PrivateCPT(..)    , PossibleInstantiations    , convertToMaxFactor+   , convertToNormalFactor +   , decisionFactor    , debugCPT    , privateFactorValue   ) where@@ -64,7 +68,7 @@                     , mapping :: !(IM.IntMap Int) -- ^ Mapping from vertex number to position in dimensions                     , values :: !(v a) -- ^ Table of values                     }-                    | Scalar !a +                    | Scalar !a  deriving(Eq)  debugCPT (Scalar d) = do     putStrLn "SCALAR CPT"@@ -88,10 +92,33 @@   in   Table d m newValues -type CPT = PrivateCPT (V.Vector) Double+type DecisionFactor = PrivateCPT (NV.Vector) DVI    ++-- | Return an array of instantiations. Used to compute decisions+-- in an influence diagram+decisionFactor :: MAXCPT -> DecisionFactor+decisionFactor (Scalar (_,l)) = Scalar (head . head $ l) +decisionFactor (Table d m v) =+  let extractElem = head . head -- We only have ONE instantiated variable in influence diagram. So no need+      -- for a list of list (list of several variables)+      newValues = NV.fromList . map extractElem . map snd . NV.toList $ v+  in+  Table d m newValues++++convertToNormalFactor :: MAXCPT -> CPT +convertToNormalFactor (Scalar a) = Scalar (fst a)+convertToNormalFactor (Table d m v) =+  let newValues = V.fromList . map fst . NV.toList $ v+  in+  Table d m newValues++type CPT = PrivateCPT (V.Vector) Double+ type PossibleInstantiations = [DVISet]  type MAXCPT = PrivateCPT (NV.Vector) (Double,PossibleInstantiations)@@ -101,6 +128,8 @@     mkValue :: Double -> a     scale :: Double -> a -> a     multiply :: a -> a -> a+    divide :: a -> a -> a+    elementSum ::  a -> a -> a     elementUnit :: a  _isUsingSameVariablesAs :: PrivateCPT v a -> PrivateCPT v a -> Bool@@ -157,7 +186,7 @@     in      fromJust $ createCPTWithDims (factorVariables f) newValues -privateFactorValue :: (FactorElement a, GV.Vector v a) => PrivateCPT v a  -> [DVI] -> a+privateFactorValue :: (GV.Vector v a) => PrivateCPT v a  -> [DVI] -> a {-# INLINE privateFactorValue #-} privateFactorValue (Scalar v) _ = v  privateFactorValue f@(Table d _ v) i = @@ -181,15 +210,18 @@ {-# INLINE _factorValue #-} _factorValue f d = doubleValue (privateFactorValue f d) -_factorProduct :: (FactorElement a, GV.Vector v a, Factor (PrivateCPT v a)) => [PrivateCPT v a] -> PrivateCPT v a-_factorProduct [] = factorFromScalar 1.0-_factorProduct l = +_factorProduct :: (FactorElement a, GV.Vector v a, Factor (PrivateCPT v a)) +               => (a -> a -> a)+               -> [PrivateCPT v a] +               -> PrivateCPT v a+_factorProduct _ [] = factorFromScalar 1.0+_factorProduct op l =      let nakedVars = L.foldr1 union . map factorVariables $ l         allVars = DVSet nakedVars         (scalars,cpts) = partition isScalarFactor l         stridesFromCPT (Table d _ _) = indexStridesFor (DVSet d) allVars         elementProduct [] = elementUnit-        elementProduct l = foldr1 multiply l+        elementProduct l = foldr1 op l         ps = elementProduct . map (flip privateFactorValue undefined) $ scalars         cptsStrides = map stridesFromCPT cpts     in @@ -199,7 +231,7 @@         else             let getFactorValueAtIndex i (strides,factor@(Table _ _ vals)) = vals!(indexPosition strides i)                 instantiationProduct instantiation = elementProduct . map (getFactorValueAtIndex instantiation) $ (zip cptsStrides cpts)-                values = GV.force $ GV.fromList [multiply ps (instantiationProduct x) | x <- indicesForDomain allVars]+                values = GV.force $ GV.fromList [op ps (instantiationProduct x) | x <- indicesForDomain allVars]             in              fromJust $ createCPTWithDims nakedVars values 
Bayes/FactorElimination.hs view
@@ -53,7 +53,9 @@  import Test.QuickCheck hiding ((.||.), collect) import Test.QuickCheck.Arbitrary+import Bayes.VariableElimination.Buckets(IsBucketItem(..)) + import Bayes.Factor.CPT -- This import is only used for quickcheck tests  --import Debug.Trace@@ -293,7 +295,7 @@   maximumSpanningTree g''  -- | Create a function tree-createJunctionTree :: (DirectedGraph g, FoldableWithVertex g, NamedGraph g, Factor f, Show f)+createJunctionTree :: (DirectedGraph g, FoldableWithVertex g, NamedGraph g, Factor f, IsBucketItem f, Show f)                   => (UndirectedSG () f -> Vertex -> Vertex -> Ordering) -- ^ Weight function on the moral graph                   -> BayesianNetwork g f -- ^ Input directed graph                   -> JunctionTree f -- ^ Junction tree@@ -307,7 +309,7 @@  -- | Compute the marginal posterior (if some evidence is set on the junction tree)   -- otherwise compute just the marginal prior.-posterior :: (BayesianDiscreteVariable dv, Factor f) => JunctionTree f -> dv -> Maybe f+posterior :: (BayesianDiscreteVariable dv, Factor f, IsBucketItem f) => JunctionTree f -> dv -> Maybe f posterior t someDv =    let v = dv someDv   in
Bayes/FactorElimination/JTree.hs view
@@ -50,9 +50,11 @@ import Bayes import Data.Function(on) import Bayes.VariableElimination(marginal)+import Data.Binary+import Bayes.VariableElimination.Buckets(IsBucketItem(..)) -import Debug.Trace -debug s a = trace (s ++ " " ++ show a ++ "\n") a+--import Debug.Trace +--debug s a = trace (s ++ " " ++ show a ++ "\n") a  type UpMessage a = a  type DownMessage a = Maybe a@@ -76,7 +78,7 @@ instance Show a => Show (NodeValue a) where      show (NodeValue v f e) = "f(" ++ show f ++ ") e(" ++ show e ++ ")" -newtype Sep = Sep Int deriving(Eq,Ord,Show,Num)+newtype Sep = Sep Int deriving(Eq,Ord,Show,Num,Binary)  -- | Junction tree. -- 'c' is the node / separator identifier (for instance a set of 'DV')@@ -480,7 +482,7 @@ fromCluster (Cluster s) = Set.toList s   -instance (Factor f) => Message f Cluster where +instance (Factor f,IsBucketItem f) => Message f Cluster where    newMessage input (NodeValue _ f e) c =      let allFactors = f ++ e ++ input          variablesToKeep = fromCluster c 
+ Bayes/ImportExport.hs view
@@ -0,0 +1,175 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts #-}+{- | Import / export Bayesian networks and junction tress++-}+module Bayes.ImportExport (+	-- * Networks+	  writeNetworkToFile+	, readNetworkFromFile+	-- * Junction Tree +	, writeVariableMapAndJunctionTreeToFile+	, readVariableMapAndJunctionTreeToFile+	) where ++import Data.Binary+import Bayes+import Bayes.PrivateTypes(Vertex(..),Edge(..), SimpleGraph(..),DE(..), UE(..),DV(..))+import Bayes.Factor.PrivateCPT(CPT(..), MAXCPT(..),PrivateCPT(..)) +import System.FilePath+import qualified Data.Vector as NV+import qualified Data.Vector.Unboxed as V+import Bayes.FactorElimination.JTree(SeparatorValue(..),NodeValue(..),JTree(..),Cluster(..),JunctionTree(..))+import qualified Data.Map as M ++-- | Write a bayesian network to file+writeNetworkToFile :: FilePath -- ^ File path+                   -> SBN CPT -- ^ Bayesian network+                   -> IO () +writeNetworkToFile f n = encodeFile f n ++-- | Read bayesian network from file +readNetworkFromFile :: FilePath +                    -> IO (SBN CPT)+readNetworkFromFile = decodeFile++-- | Write a junction tree and the variable map to a file +writeVariableMapAndJunctionTreeToFile :: FilePath+                                      -> (M.Map String Vertex)+                                      -> JunctionTree CPT +                                      -> IO ()+writeVariableMapAndJunctionTreeToFile f vm jt = encodeFile f (vm,jt)++-- | Read variable map and junction tree from file+readVariableMapAndJunctionTreeToFile :: FilePath +                                     -> IO (M.Map String Vertex, JunctionTree CPT)+readVariableMapAndJunctionTreeToFile f = decodeFile f++instance Binary Cluster where +	put (Cluster s) = put s +	get = get >>= return . Cluster++instance (Ord c, Binary c, Binary f) => Binary (JTree c f) where +	put (JTree r ls cm pm spm scm nvm svm sck sclm) = do +		put r +		put ls +		put cm +		put pm +		put spm +		put scm +		put nvm +		put svm +		put sck +		put sclm +	get = do +		r <- get+		ls <- get +		cm <- get +		pm <- get +		spm <- get +		scm <- get +		nvm <- get +		svm <- get +		sck <- get +		sclm <- get+		return $ JTree r ls cm pm spm scm nvm svm sck sclm++instance Binary a => Binary (NodeValue a) where +	put (NodeValue v f e) = do +		put v +		put f +		put e +	get = do +		v <- get +		f <- get +		e <- get+		return $ NodeValue v f e++instance Binary a => Binary (SeparatorValue a) where+	put (EmptySeparator) = do +		putWord8 0 +	put (SeparatorValue a b) = do +		putWord8 1 +		put a +		put b +	get = do +		tag <- getWord8 +		case tag of +			0 -> return EmptySeparator+			_ -> do +				a <- get +				b <- get +				return $ SeparatorValue a b ++instance Binary (V.Vector Double) where +	put = put . V.toList +	get = get >>= return . V.fromList ++instance Binary (NV.Vector Double) where +	put = put . NV.toList +	get = get >>= return . NV.fromList ++instance Binary DV where +	put (DV v i) = do +		put v +		put i +	get = do +		v <- get +		i <- get +		return $ DV v i ++instance Binary (v Double) => Binary (PrivateCPT v Double) where +    put (Table d m v) = do +    	putWord8 0 +    	put d +    	put m +    	put v +    put (Scalar v) = do +    	putWord8 1 +    	put v +    get = do +    	tag <- getWord8 +    	case tag of +    		0 -> do +    			d <- get +    			m <- get +    			v <- get +    			return $ Table d m v +    		_ -> get >>= return . Scalar ++instance Binary Vertex where +  put (Vertex v) = put v +  get = get >>= return . Vertex ++instance Binary Edge where +	put (Edge va vb) = do +		put va +		put vb +	get = do +		va <- get+		vb <- get +		return $ Edge va vb++instance (Binary l, Binary e, Binary v) => Binary (SimpleGraph l e v) where +	put (SP e v n) = do +		put e +		put v +		put n +	get = do +		e <- get +		v <- get +		n <- get +		return $ SP e v n++instance Binary DE where +    put (DE a b) = do +    	put a +    	put b +    get = do +    	a <- get +    	b <- get +    	return $ DE a b ++instance Binary UE where +	put (UE a) = put a +	get = get >>= return . UE
Bayes/ImportExport/HuginNet.hs view
@@ -14,6 +14,7 @@ import Bayes import Bayes.PrivateTypes import Bayes.Factor.CPT(changeVariableOrder)+import Bayes.BayesianNetwork  --import Debug.Trace  
+ Bayes/InfluenceDiagram.hs view
@@ -0,0 +1,570 @@+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{- | Tools to build influence diagrams++-}+module Bayes.InfluenceDiagram(+  -- * Type+    InfluenceDiagram+  , DecisionFactor+  , Instantiable(..)+  , DEV +  , UV+  , DV+  , TDV+  -- * Building +  , t +  , (~~)+  , chance +  , decisionNode +  , utilityNode +  , proba +  , decision +  , utility+  , cpt+  , d +  , p+  , noDependencies+  -- * Solving+  , decisionsOrder+  , solveInfluenceDiagram+  , runID+  , policyNetwork+  , decisionToInstantiation+  -- * Testing +  , DVISet +  , DVI+	) where ++import Bayes+import Bayes.PrivateTypes+import Bayes.Network +import Data.Monoid+import Bayes.Factor+import Bayes.Factor.PrivateCPT+import Bayes.Factor.CPT+import Bayes.Factor.MaxCPT+import Data.Maybe(fromJust,mapMaybe)+import Control.Applicative((<$>))+import Bayes.VariableElimination.Buckets+import Bayes.Factor.PrivateCPT(DecisionFactor(..),decisionFactor,convertToMaxFactor,convertToNormalFactor,privateFactorValue,_factorVariables)+import Data.List(foldl1',foldl')+import Control.Monad.State.Strict(gets)+import qualified Data.Vector as NV+import qualified Data.Map as M +import qualified Data.IntMap as IM ++--import Debug.Trace ++--debug s a = trace (s ++ show a) a++replaceDecisionNodeWithPolicy :: InfluenceDiagram -> CPT -> InfluenceDiagram +replaceDecisionNodeWithPolicy g f = +  let dv = factorMainVariable f +      parentVariables = tail (factorVariables f)+      factorV = vertex dv+      g' = fromJust $ changeVertexValue factorV (DecisionNode f) g+      oldParentEdges = fromJust $ ingoing g' factorV +      g'' = foldr removeEdge g' oldParentEdges+      addNewFactorEdge pdv currentG = addEdge (edge (vertex pdv) (vertex dv)) NormalLink currentG+  in +  -- When we add the edges, we don't care about the order because+  -- the CPT is already created and we don't need the order of the parents in the graph+  -- to deduce the order of the variables in the CPT.+  foldr addNewFactorEdge g'' parentVariables++-- | Create a policy factor from a decision factor+policyFactor :: DecisionFactor -> CPT+policyFactor (Scalar v) = +  let decisionVar = v +      originalV = vertex decisionVar +      nakedVars = [dv decisionVar]+      allVars = DVSet nakedVars+      values = do +        x <- forAllInstantiations allVars +        if (instantiationValue v == instantiationValue (head x))+          then +            return 1.0 +          else +            return 0.0+  in +  fromJust . factorWithVariables nakedVars $ values +policyFactor f@(Table d m v) = +  let decisionVar = NV.head v +      originalV = vertex decisionVar +      nakedVars = dv decisionVar : d+      allVars = DVSet nakedVars+      values = do +        x <- forAllInstantiations allVars +        let v = privateFactorValue f (tail x)+        if (instantiationValue v == instantiationValue (head x))+          then +            return 1.0 +          else +            return 0.0+  in+  fromJust . factorWithVariables nakedVars $ values+  ++-- | Convert a decision policy to a set of possible instantiations+-- It is the only way to access to the content of a decision factor.+decisionToInstantiation :: DecisionFactor -> [DVISet]+decisionToInstantiation f@(Scalar v) = [[v]]+decisionToInstantiation f@(Table d m v) = +  let allVars = DVSet d+      values = do +        x <- forAllInstantiations allVars +        let v = privateFactorValue f x +        return (v:x)+  in +  values++-- | Create a policy network from an influence diagram and its solution.+-- A policy network is a Bayesian network where the decision nodes have been replaced+-- with probability nodes where the probability is 1 when the configuration is corresponding+-- to the decision and 0 otherwise.+policyNetwork :: [DecisionFactor] -> InfluenceDiagram -> SBN CPT +policyNetwork l idg = +  let idg1 = foldl' replaceDecisionNodeWithPolicy idg (map policyFactor l) +      utilities = filter (isUtilityNode idg) . allVertices $ idg+      SP e v b = foldr removeVertex idg1 utilities+      toBayesNode (l,ChanceNode f) = (l,f) +      toBayesNode (l,DecisionNode f) = (l,f)+      toBayesNode (l,UtilityNode _ _) = error "No utilities nodes should remain to create the policy network"+      e' = M.map (const ()) e +      v' = IM.map toBayesNode v +  in +  SP e' v' b+++instance Show DecisionFactor where+    show (Scalar v) = "\nScalar Factor:\n" ++ show v+    show c@(Table [] _ v) = "\nEmpty DecisionFactor:\n"++    show c = displayFactorBody c ++instance MultiDimTable DecisionFactor where +    elementStringValue f d = show (privateFactorValue f d)+    tableVariables = _factorVariables+++data JoinSum = JS !CPT !CPT deriving(Eq)++instance Show JoinSum where +  show (JS p u) = "CPT\n" ++ show p ++ "\nUTILITY\n" ++ show u ++ "\n"++chanceFactor f = JS f (factorFromScalar 0.0)+utilityFactor f = JS (factorFromScalar 1.0) f++jsProduct ::  JoinSum -> JoinSum -> JoinSum+jsProduct (JS pa ua) (JS pb ub) = JS (itemProduct [pa,pb]) (cptSum [ua,ub])+++-- | Max out a variable+maximalize :: DV -> [JoinSum] -> (JoinSum,DecisionFactor) +maximalize dv l = +  let JS pa ua = itemProduct l+      maxa = convertToNormalFactor . itemProjectOut dv . convertToMaxFactor $ pa+      maxu' = itemProjectOut dv . convertToMaxFactor  . itemProduct $ [pa,ua]+      maxu = convertToNormalFactor maxu'+      instF = decisionFactor maxu'+  in +  (JS maxa (cptDivide maxu maxa),instF)++++instance IsBucketItem JoinSum where+    scalarItem (JS a b) = isScalarFactor a && isScalarFactor b+    itemProduct l = foldl1' jsProduct l+    itemProjectOut dv (JS pa ua) =  +      let suma = itemProjectOut dv pa+          sumu = itemProjectOut dv (itemProduct [pa,ua])+      in +      JS suma (cptDivide sumu suma)+    itemContainsVariable (JS a b) dv = containsVariable a dv || containsVariable b dv+++-- | Synonym for undefined because it is clearer to use t to set the Enum bounds of a variable+t = undefined++-- | Edge kind+data EdgeKind = NormalLink +              deriving(Eq,Show)++isInformationLink :: InfluenceDiagram -> Edge -> Bool+isInformationLink g (Edge va vb) = +  (isChanceNode g va || isDecisionNode g va) && (isDecisionNode g vb)++isRevealedChanceNode :: InfluenceDiagram -> Vertex -> Bool +isRevealedChanceNode g v = isChanceNode g v && any (isDecisionNode g) (childrenNodes g v)++edgeShape :: InfluenceDiagram -> Edge -> EdgeKind -> Maybe String+edgeShape g e NormalLink | isInformationLink g e = Just "style=dashed"+                         | otherwise = Nothing +edgeColor :: InfluenceDiagram -> Edge -> EdgeKind -> Maybe String+edgeColor _ _ _ = Nothing++nodeShape :: InfluenceDiagram -> Vertex -> IDValue -> Maybe String+nodeShape _ _ (ChanceNode _) = Just "shape=ellipse" +nodeShape _ _ (UtilityNode _ _) = Just "shape=diamond"+nodeShape _ _ (DecisionNode _) = Just "shape=box"++nodeColor :: InfluenceDiagram -> Vertex -> IDValue -> Maybe String+nodeColor g v (ChanceNode _) | isRevealedChanceNode g v = Just "style=filled,fillcolor=gray"+                             | otherwise = Nothing+nodeColor _ _ _ = Nothing++instance Show InfluenceDiagram where+  show g = displaySimpleGraph (nodeShape g) (nodeColor g) (edgeShape g) (edgeColor g) g+++instance Monoid EdgeKind where +   mempty = NormalLink +   NormalLink `mappend` NormalLink = NormalLink++-- | Influence diagram+type InfluenceDiagram = DirectedSG EdgeKind IDValue++type IDMonad g a = NetworkMonad g EdgeKind IDValue a+++-- Most factors are coding for f(abc) where a is the main factor variable+-- and where the a vertex is the original vertex in the graph.+-- For an utility, we have U(abcd) where the variables a is NOT the main factor variable.+-- Indeed, the main factor variable if it was used in the factor would have dimension 1.+-- So, it is useless in the factor.+-- So, we need another DV field to track the original vertex+data IDValue   = ChanceNode !CPT+               | UtilityNode !DV !CPT +               | DecisionNode !CPT+               deriving(Eq)++dvFromIDValue (ChanceNode f) = factorMainVariable f+dvFromIDValue (UtilityNode dv f) = dv+dvFromIDValue (DecisionNode f) = factorMainVariable f++factorVariablesFromIDValue (ChanceNode f) = factorVariables f+factorVariablesFromIDValue (UtilityNode _ f) = factorVariables f+factorVariablesFromIDValue (DecisionNode f) = factorVariables f++jsFromIDValue (ChanceNode f) = chanceFactor f+jsFromIDValue (UtilityNode _ f) = utilityFactor f+jsFromIDValue (DecisionNode _) = error "You don't need to get the factor for a decision node"++instance Show IDValue where +   show (ChanceNode f) = "CHANCE:\n" ++ show f+   show (UtilityNode _ f) = "UTILITY:\n" ++ show f+   show (DecisionNode f) = ""+++-- | Utility variable+data UV = UV !Vertex !Int deriving(Eq)++-- | Decision variable+data DEV = DEV !Vertex !Int deriving(Eq,Ord)++instance Show DEV where+    show (DEV v d) = "D" ++ show v ++ "(" ++ show d ++ ")"++instance BayesianDiscreteVariable DEV where +  dimension (DEV _ d) = d +  dv (DEV v d) = DV v d +  vertex (DEV v _) = v++instance Instantiable DEV Int where +  (=:) d@(DEV v dim) value = DVI (dv d) value++data PorD = P DV | D DEV deriving(Eq)++class ChanceVariable m where +  toDV :: m -> DV++instance ChanceVariable DV where +  toDV = dv ++instance ChanceVariable (TDV s) where +  toDV = dv++instance BayesianDiscreteVariable PorD where+    dimension (D d) = dimension d+    dimension (P p) = dimension p+    dv (D x) = dv x+    dv (P x) = dv x+    vertex (D d) = vertex d+    vertex (P p) = vertex p++-- | Used to mix decision and chance variables and a same list+p :: ChanceVariable c => c -> PorD+p = P . toDV++-- | Used to mix decision and chance variables and a same list+d :: DEV -> PorD +d = D++++-- | Create a chance node+chance :: (Bounded a, Enum a, NamedGraph g)+       => String +       -> a +       -> IDMonad g (TDV a)+chance = variable++-- | Create an utility node+utilityNode :: (NamedGraph g)+            => String +            -> IDMonad g UV+utilityNode s = do+  DV v i <- variableWithSize s 1+  return (UV v i)++-- | Create a decision node+decisionNode :: (Bounded a, Enum a, NamedGraph g)+             => String +             -> a+             -> IDMonad g DEV+decisionNode s a =  do+  DV v i <- variable s a >>= return . dv+  return (DEV v i)++utilityCpt :: (DirectedGraph g, Distribution d, Factor f) +           => Vertex -- ^ Vertex containing the factor+           -> d -- ^ Distribution to initialize the factor+           -> NetworkMonad g e a (Maybe f) +utilityCpt v l  = do +  g <- gets snd+  let vertices = map (fromJust . startVertex g) . fromJust . ingoing g $ v+  fv <- mapM factorVariable vertices+  let cpt = createFactor (map fromJust fv) l+  return cpt++class Initializable v where +  (~~) :: (DirectedGraph g, Distribution d) +     => IDMonad g v -- ^ Discrete variable in the graph+     -> d -- ^ List of values+     -> IDMonad g ()++instance Initializable DV where+  (~~) mv l = do +     (DV v _) <- mv >>= return . dv -- This is updating the state and so the graph+     maybeNewValue <- getCpt v l+     currentValue <- getBayesianNode v+     case (currentValue, maybeNewValue) of +       (Just c, Just n) -> initializeNodeWithValue v c (ChanceNode n)+       _ -> return ()++instance Initializable (TDV s) where+  (~~) mv l = do +     (DV v _) <- mv >>= return . dv -- This is updating the state and so the graph+     maybeNewValue <- getCpt v l+     currentValue <- getBayesianNode v+     case (currentValue, maybeNewValue) of +       (Just c, Just n) -> initializeNodeWithValue v c (ChanceNode n)+       _ -> return ()++instance Initializable UV where+  (~~) mv l = do +     (UV v dim) <- mv  -- This is updating the state and so the graph+     maybeNewValue <- utilityCpt v l+     currentValue <- getBayesianNode v+     case (currentValue, maybeNewValue) of +       (Just c, Just n) -> initializeNodeWithValue v c (UtilityNode (DV v dim) n)+       _ -> return ()++instance Initializable DEV where+  (~~) mv l = do +     (DV v _) <- mv >>= return . dv -- This is updating the state and so the graph+     maybeNewValue <- getCpt v l+     currentValue <- getBayesianNode v+     case (currentValue, maybeNewValue) of +       (Just c, Just n) -> initializeNodeWithValue v c (DecisionNode n)+       _ -> return ()++_cpt :: (DirectedGraph g , BayesianDiscreteVariable v,BayesianDiscreteVariable vb) => v -> [vb] -> IDMonad g v+_cpt node conditions = do+  mapM_ ((dv node) <--) (reverse (map dv conditions))+  return node++-- | Define that a chance node is a conditional probability and define the parent variables+cpt :: (DirectedGraph g ,BayesianDiscreteVariable vb, ChanceVariable c) => c -> [vb] -> IDMonad g c+cpt node conditions = do+  mapM_ ((toDV node) <--) (reverse (map dv conditions))+  return node++-- | Define that a chance node is a probability (not conditional)+-- Values are ordered like+-- FFF FFT FTF FTT TFF TFT TTF TTT+-- and same for other enumeration keeping enumeration order+proba :: (ChanceVariable c, DirectedGraph g) => c -> IDMonad g c+proba node = cpt node ([] :: [DV])++-- | Define a utility dependence+utility :: (DirectedGraph g , BayesianDiscreteVariable dv) => UV -> [dv] -> IDMonad g UV+utility (UV v d) l = do +  DV v' d' <- _cpt (DV v d) l+  return (UV v' d')++-- | Used to define a root decision which is not dependent on any past node+noDependencies :: [DV]+noDependencies = []++-- | Define a decision dependence+decision :: (DirectedGraph g, BayesianDiscreteVariable dv) => DEV -> [dv] -> IDMonad g DEV+decision d l = do +  let dim = product . map dimension $ dv d:map dv l+  _cpt d l ~~ (replicate dim 1.0)+  return d+++-- | Run an influence monad+runID :: IDMonad DirectedSG a -> (a,InfluenceDiagram)+runID = runNetwork ++{-+ +Generation of temporal order++-}++maybeOnlyResult :: [a] -> Maybe a +maybeOnlyResult [a] = Just a +maybeOnlyResult _ = Nothing++isDecisionNode :: InfluenceDiagram -> Vertex -> Bool +{-# INLINE isDecisionNode #-}+isDecisionNode g v = maybe False (const True) $ do+  DecisionNode f <- vertexValue g v+  return f++isUtilityNode :: InfluenceDiagram -> Vertex -> Bool +{-# INLINE isUtilityNode #-}+isUtilityNode g v = maybe False (const True) $ do+  UtilityNode _ f <- vertexValue g v+  return f++isChanceNode :: InfluenceDiagram -> Vertex -> Bool +{-# INLINE isChanceNode #-}+isChanceNode g v = maybe False (const True) $ do+  ChanceNode f <- vertexValue g v+  return f++-- | Check the node is a decision node and none of its parents are decision nodes+isRootDecision :: InfluenceDiagram -> Vertex -> Bool+{-# INLINE isRootDecision #-}+isRootDecision g v | isDecisionNode g v = +  case ingoing g v of +    Just [] -> True +    _ -> False+                   | otherwise = False++-- | Get the chance parents of a decision node and a new graph with those parents+-- removed and the decision node removed+chanceParents :: DEV -> InfluenceDiagram -> (InfluenceDiagram,[DV])+chanceParents dev currentG = +  let p = filter (isChanceNode currentG) . parentNodes currentG $ (vertex dev) +      theParents = map (vertexToDV currentG) p+      newG = foldr removeVertex currentG (vertex dev : p)+  in +  (newG,theParents)++-- | Return the remaining chance nodes of the graph+remainingChanceNodes :: InfluenceDiagram -> [DV]+remainingChanceNodes = chanceNodes ++-- | Return the utility nodes+utilityNodes :: InfluenceDiagram -> [UV]+utilityNodes g = map (vertexToUV g) . filter (isUtilityNode g) . allVertices $ g++-- | Return the chance nodes+chanceNodes :: InfluenceDiagram -> [DV]+chanceNodes g = map (vertexToDV g) . filter (isChanceNode g) . allVertices $ g++-- | Return all chances factor and utility factors+chanceAndUtilityFactors :: InfluenceDiagram -> [JoinSum]+chanceAndUtilityFactors g = map (jsFromIDValue . fromJust . vertexValue g) . filter (not . isDecisionNode g) . allVertices $ g++vertexToDV :: InfluenceDiagram -> Vertex -> DV +vertexToDV g v = dvFromIDValue . fromJust . vertexValue g $ v++vertexToDEV :: InfluenceDiagram -> Vertex -> DEV +vertexToDEV g v = +  let DV v1 d = vertexToDV g v +  in +  DEV v1 d++vertexToUV :: InfluenceDiagram -> Vertex -> UV +vertexToUV g v = +  let DV v1 d = vertexToDV g v +  in +  UV v1 d++-- | Return a root decision+rootDecision :: InfluenceDiagram -> Maybe Vertex +rootDecision g = do +    r <- rootNode g +    if isDecisionNode g r +      then+        return r +      else +        rootDecision (removeVertex r g)++-- | Used to encode the temporal order+data ChancesOrDecision = C ![DV] | DEC !DEV deriving(Eq,Ord,Show)++dvOrder :: [ChancesOrDecision] -> [DV] +dvOrder [] = []+dvOrder (C l:r) = l ++ dvOrder r +dvOrder (DEC d:r) = dv d: dvOrder r ++-- | Remove all decisions node and record their chance parents+removeAndRecordRootDecision :: [ChancesOrDecision] -> InfluenceDiagram -> [ChancesOrDecision]+removeAndRecordRootDecision currentL currentG = +  case vertexToDEV currentG <$> (rootDecision currentG) of +    Nothing -> (C (remainingChanceNodes currentG)):currentL +    Just newD -> +      let (currentG', p) = chanceParents newD currentG+      in+      removeAndRecordRootDecision ((DEC newD):(C p):currentL) currentG'++-- | List of decision vertices in reverse temporal order (corresponding to elimination order)+decisionsOrder :: InfluenceDiagram -> [ChancesOrDecision] +decisionsOrder g = removeAndRecordRootDecision [] $ g ++-- | Maximalize the decision variable to find the decision strategy at the current set+maximalizeOneVariable :: Buckets JoinSum -> DV -> (Buckets JoinSum,DecisionFactor)+maximalizeOneVariable currentBucket dv   = +  let fk = getBucket dv currentBucket+      (newF, instF) = maximalize dv fk+  in+  (updateBucket dv newF currentBucket, instF)++--debugs True f = \a b -> debug ("SUM OUT " ++ show b ++ "\n") (f a b)+--debugs False f = \a b -> debug ("MAX OUT " ++ show b ++ "\n") (f a b)++marginalizeID :: [ChancesOrDecision]  -> Buckets JoinSum -> [DecisionFactor] -> (Buckets JoinSum,[DecisionFactor])+marginalizeID [] b r = (b,r)+marginalizeID (C d:r) currentB currentR =  +  let bucket' = foldl' marginalizeOneVariable currentB d +  in +  marginalizeID r bucket' currentR +marginalizeID (DEC de:r) currentB currentR = +  let (bucket',instF) = maximalizeOneVariable currentB (dv de) +  in +  marginalizeID r bucket' (instF:currentR) ++-- | Solve an influence diagram. A DecisionFactor is generated for each decision variable.+-- A decision factor is containing a variable instantiation instead of a double.+-- This instantiation is giving the decision to take for each value of the parents.+solveInfluenceDiagram :: InfluenceDiagram -> [DecisionFactor]+solveInfluenceDiagram g = +  let decOrder = decisionsOrder g+      theFactors = chanceAndUtilityFactors g+      p = dvOrder decOrder +      bucket = createBuckets theFactors p []+      (_, result) = marginalizeID decOrder bucket []+  in+  result ++
+ Bayes/Network.hs view
@@ -0,0 +1,214 @@+{-# LANGUAGE ViewPatterns #-}+{- | Common functions and types for building networks++-}+module Bayes.Network(+	-- * Types +	  MaybeNode(..)+	, NetworkMonad(..)+	-- * Functions+	, factorVariable+	, (<--)+	, getBayesianNode +	, setBayesianNode+	, initializeNodeWithValue+	, setVariableBoundWithSize+	, setVariableBound+	, addVariableIfNotFound+	, unamedVariable+	, variable+	, variableWithSize+	, unNamedVariableWithSize+	, runNetwork+	, execNetwork+	, evalNetwork+	, getCpt+	) where ++import Bayes.PrivateTypes+import Bayes +import Control.Monad.State.Strict+import Bayes.Tools +import Data.Maybe(fromJust)+import Bayes.Factor+import Data.Monoid++-- | Bayesian variable : name,dimension, factor+-- When initialized it is using a factor with bayesian variables.+-- But the factor value are not yet set+data MaybeNode f = UninitializedNode String Int+                 | InitializedNode String Int f+++-- | The Network monad+type NetworkMonad g e f a = GraphMonad g e (MaybeNode f) a+++-- | Get the Bayesian Discrete Variable for a vertex.+-- It works because we keep the variable dimension during creating of the graph+factorVariable :: Graph g => Vertex -> NetworkMonad g e f (Maybe DV)  +factorVariable v = do +  g <- gets snd +  let value = vertexValue g v+  case value of+    Nothing -> return Nothing+    Just (UninitializedNode _ d) -> return $ Just $ DV v d+    Just (InitializedNode _ d _) -> return $ Just $ DV v d+++-- | Create an edge between two vertex of the Bayesian network+(<--) :: (Graph g, BayesianDiscreteVariable dv, Monoid e) => dv -> dv -> NetworkMonad g e f ()+(dv -> DV va _) <-- (dv -> DV vb _) = newEdge vb va mempty++whenJust Nothing _ = return ()+whenJust (Just i) f = f i >> return ()++getCpt :: (DirectedGraph g, Distribution d, Factor f) +       => Vertex -- ^ Vertex containing the factor+       -> d -- ^ Distribution to initialize the factor+       -> NetworkMonad g e a (Maybe f) +getCpt v l  = do +  g <- gets snd+  currentVar <- factorVariable v+  let vertices = map (fromJust . startVertex g) . fromJust . ingoing g $ v+  fv <- mapM factorVariable vertices+  let cpt = createFactor (map fromJust (currentVar:fv)) l+  return cpt++-- | Get the node of a bayesian network under creation+getBayesianNode :: Graph g => Vertex -> NetworkMonad g e f (Maybe (MaybeNode f))+getBayesianNode v = do+  g <- gets snd+  return $ vertexValue g v++-- | Set the node of a bayesian network under creation+setBayesianNode :: Graph g => Vertex -> MaybeNode f -> NetworkMonad g e f ()+setBayesianNode v newValue = do+  (aux,oldGraph) <- get+  let newGraph = changeVertexValue v newValue oldGraph+ +  whenJust newGraph $ \nvm -> do+     put $! (aux, nvm)++-- | Set the value of uninitialized nodes. Initialized nodes are not changed.+initializeNodeWithValue :: Graph g +                        => Vertex -- ^ Vertex+                        -> MaybeNode a -- ^ Current uninitialized node+                        -> a -- ^ Value to set+                        -> NetworkMonad g e a () +initializeNodeWithValue _ (InitializedNode _ _ _) _ = return ()+initializeNodeWithValue v (UninitializedNode s dim) newValue = do +  g <- gets snd+  setBayesianNode v (InitializedNode s dim newValue)++-- | Set the bound of a bayesian variable (number of levels)+setVariableBoundWithSize :: Graph g+                         => Vertex -- ^ Vertex+                         -> Int -- ^ Inf limit  (0 for instance)+                         -> Int -- ^ Sup limit (1 for instance for 2 elements)+                         -> NetworkMonad g e f ()+setVariableBoundWithSize a bmin bmax = do+    v <- getBayesianNode a+    whenJust v $ \(UninitializedNode s _) -> do+      setBayesianNode a (UninitializedNode s (bmax - bmin + 1))++setVariableBound :: (Enum a, Bounded a, Graph g) +                 => Vertex -- ^ Vertex+                 -> a -- ^ Bounded variable (t :: type where t is undefined)+                 -> NetworkMonad g e f ()+setVariableBound a e = +  let bmin = intValue $ minBoundForEnum e+      bmax = intValue $ maxBoundForEnum e+  in +  setVariableBoundWithSize a bmin bmax++-- | Create a new named Bayesian variable if not found.+-- Otherwise, return the found one.+addVariableIfNotFound :: NamedGraph g => String -> NetworkMonad g e f Vertex+addVariableIfNotFound vertexName = graphNode vertexName (UninitializedNode vertexName 0)++-- | Initialize a new variable+_initializeVariableBounds :: (Enum a, Bounded a, NamedGraph g)+                          => Vertex +                          -> a +                          -> NetworkMonad g e f (TDV a)+_initializeVariableBounds va e = do +  setVariableBound va e+  maybeValue <- getBayesianNode va +  case fromJust maybeValue of +     UninitializedNode s d -> return (tdv $ DV va d)+     InitializedNode _ d _ -> return (tdv $ DV va d) ++-- | Initialize a new variable with size+_initializeVariableBoundsWithSize :: NamedGraph g+                                  => Vertex -- ^ Variable name+                                  -> Int -- ^ Variable size+                                  -> NetworkMonad g e f DV+_initializeVariableBoundsWithSize va e = do+  setVariableBoundWithSize va 0 (e-1)+  maybeValue <- getBayesianNode va +  setBayesianNode va (fromJust maybeValue)+  case fromJust maybeValue of +     UninitializedNode s d -> return (DV va d)+     InitializedNode _ d _ -> return (DV va d)++-- | Create a new unamed variable+unamedVariable :: (Enum a, Bounded a, NamedGraph g)+               => a -- ^ Variable bounds +               -> NetworkMonad g e f (TDV a)+unamedVariable e = do +  va <- getNewEmptyVariable Nothing (UninitializedNode "unamed" 0)+  _initializeVariableBounds va e++-- | Define a Bayesian variable (name and bounds)+variable :: (Enum a, Bounded a, NamedGraph g) +        => String -- ^ Variable name+        -> a -- ^ Variable bounds+        -> NetworkMonad g e f (TDV a)+variable name e = do+  va <- addVariableIfNotFound name+  _initializeVariableBounds va e++-- | Define a Bayesian variable (name and bounds)+variableWithSize :: NamedGraph g+        => String -- ^ Variable name+        -> Int -- ^ Variable size+        -> NetworkMonad g e f DV+variableWithSize name e = do+  va <- addVariableIfNotFound name+  _initializeVariableBoundsWithSize va e++-- | Define a Bayesian variable (name and bounds)+unNamedVariableWithSize :: NamedGraph g+                        => Int -- ^ Variable size+                        -> NetworkMonad g e f DV+unNamedVariableWithSize e = do+  va <- getNewEmptyVariable Nothing (UninitializedNode "unamed" 0)+  _initializeVariableBoundsWithSize va e++-- | Create a  network using the simple graph implementation+-- The initialized nodes are replaced by the value.+-- Returns the monad values and the built graph.+runNetwork :: NetworkMonad DirectedSG e f a -> (a,DirectedSG e f)+runNetwork x = +  let (r,g) = runGraph x+      convertNodes (InitializedNode s d f) = f +      convertNodes (UninitializedNode s d) = error $ "All variables must be initialized with a factor: " ++ s ++ "(" ++ show d ++ ")"+  in +  (r,fmap convertNodes g)++-- | Create a  network but only returns the monad value.+-- Mainly used for testing.+execNetwork :: NetworkMonad DirectedSG e f a -> DirectedSG e f+execNetwork x = +  let g = execGraph x+      convertNodes (InitializedNode s d f) = f +      convertNodes (UninitializedNode s d) = error $ "All variables must be initialized with a factor: " ++ s ++ "(" ++ show d ++ ")"+  in +  fmap convertNodes g+++-- | Create a bayesian network but only returns the monad value.+-- Mainly used for testing.+evalNetwork :: Graph g => NetworkMonad g e f a -> a+evalNetwork = evalGraph
Bayes/PrivateTypes.hs view
@@ -23,8 +23,12 @@  , instantiationValue  , instantiationVariable  , fromDVSet- -- * Vertices + -- * Vertices, Graph  , Vertex(..)+ , Edge(..)+ , SimpleGraph(..)+ , DE(..)+ , UE(..)  -- * Misc  , getMinBound  -- * Indices @@ -45,6 +49,7 @@ import Test.QuickCheck.Arbitrary import System.Random(Random) import qualified Data.IntMap as IM+import qualified Data.Map as M   @@ -97,6 +102,28 @@ -} -- | Vertex type used to identify a vertex in a graph newtype Vertex = Vertex {vertexId :: Int} deriving(Eq,Ord)++-- | Edge type used to identify and edge in a graph+data Edge = Edge !Vertex !Vertex deriving(Eq,Ord,Show)++-- | Implementtaion of a SimpleGraph+data SimpleGraph local edgedata vertexdata = SP {+ -- | Mapping of edge to edge data+   edgeMap :: !(M.Map Edge edgedata) + -- ^ Mapping of vertex number to vertex neighborhood and vertex data+ , vertexMap :: !(IM.IntMap (local, vertexdata))+ -- ^ Vertex names. Used only to generate the graphviz representation. Names are useless for the algorithms+ -- and I don't want them to appear in the vertex values which should only be factor. Otherwise, the algorithms+ -- are less elegant since I have to extract the factors from the values+ , nameMap :: !(IM.IntMap String)+ } ++-- | Neighborhood structure for directed or undirected edges+-- | Directed edges+data DE = DE ![Edge] ![Edge] deriving(Eq,Show)++-- | Undirected edges+data UE = UE ![Edge] deriving(Eq,Show)  instance Show Vertex where      show (Vertex v) = "v" ++ show v
Bayes/Test.hs view
@@ -1,3 +1,6 @@+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-} {- | Testing of the implementation.  -}@@ -13,10 +16,12 @@ import Bayes.Factor.CPT(testProductProject_prop,testScale_prop,testProjectCommut_prop,testScalarProduct_prop,testProjectionToScalar_prop,testAssocProduct_prop) import Bayes.FactorElimination(junctionTreeProperty_prop,junctionTreeAllClusters_prop) import Bayes.PrivateTypes(instantiationProp)-+import Bayes.Test.InfluencePatterns(testStudentDecisions) #ifdef LOCAL-import Bayes.Test.ReferencePatterns(compareAsiaReference,compareCancerReference,comparePokerReference,compareFarmReference,compareMpeCancer)-#endif +import Bayes.Test.ReferencePatterns(compareAsiaReference,compareCancerReference,comparePokerReference,compareFarmReference,compareMpeAsia,testFileExport)+#else +import Bayes.Test.ReferencePatterns(testFileExport)+#endif  -- | Run all the tests runTests = defaultMain tests@@ -41,15 +46,19 @@                 testProperty "Test all clusters are included in the junction tree" junctionTreeAllClusters_prop             ]         , testGroup "Misc functions" [-                testProperty "Instantiation from multiindex" instantiationProp+                testProperty "Instantiation from multiindex" instantiationProp,+                testCase "Test import/export of bayesian network and junction tree" testFileExport             ]+        , testGroup "Influence Diagrams" [+                testCase "Test with reference patterns" testStudentDecisions+            ] #ifdef LOCAL         , testGroup "Reference patterns" [                  testCase "Asia reference pattern" compareAsiaReference,                 testCase "Cancer reference pattern" compareCancerReference,                 testCase "Poker reference pattern" comparePokerReference,                 testCase "Farm reference pattern" compareFarmReference,-                testCase "Test MPE and MAP with Cancer network" compareMpeCancer+                testCase "Test MPE and MAP with Asia network" compareMpeAsia         ] #endif 
+ Bayes/Test/InfluencePatterns.hs view
@@ -0,0 +1,24 @@+{- | A comparison of influence diagram solution with references++-}+module Bayes.Test.InfluencePatterns(+   testStudentDecisions+ ) where++import Test.HUnit.Base(assertBool)+import Data.Maybe(fromJust)++import Bayes.Examples.Influence+import Bayes.InfluenceDiagram ++testStudentDecisions = do +	let result = solveInfluenceDiagram student+	    (e,pr,s) = studentDecisionVars+	    l = map decisionToInstantiation result +	assertBool "Student Network" $ l == [[[e =: (0::Int)]],[[s =: (0::Int),pr =: False],[s =: (0::Int),pr =: True]]]+	let result = solveInfluenceDiagram studentSimple+	    e = studentSimpleDecisionVar+	    l = map decisionToInstantiation result +	assertBool "Simple Student Network" $ l == [[[ e =: (1 :: Int)]]]++
Bayes/Test/ReferencePatterns.hs view
@@ -5,12 +5,13 @@  -} module Bayes.Test.ReferencePatterns(+   testFileExport #ifdef LOCAL-   compareAsiaReference+ , compareAsiaReference  , compareCancerReference  , comparePokerReference  , compareFarmReference- , compareMpeCancer+ , compareMpeAsia #endif  ) where @@ -21,8 +22,11 @@ import Bayes import Bayes.FactorElimination import Bayes.VariableElimination(mpe)-import Bayes.Examples(anyExample)+import Bayes.Examples(anyExample,example) import Bayes.FactorElimination.JTree(root)+import Bayes.Tools(withTempFile)+import Bayes.ImportExport +import Bayes.BayesianNetwork  value varmap jt s =    let v =  fromJust $ Map.lookup s varmap@@ -37,6 +41,23 @@   putStrLn ""   assertBool s $ r ~=~ l +-- | Test that we can import / export the bayesian network, junction tree and variable map+testFileExport :: IO () +testFileExport = do +  let (vars,g) = example +      vm = varMap g+      jt = createJunctionTree nodeComparisonForTriangulation g+  withTempFile $ \f -> do +    writeNetworkToFile f g +    g' <- readNetworkFromFile f +    assertBool "Test graph import/export" $ g == g'+  withTempFile $ \f -> do +    writeVariableMapAndJunctionTreeToFile f vm jt +    (vm',jt') <- readVariableMapAndJunctionTreeToFile f +    assertBool "Test jt import/export" $ jt == jt'+    assertBool "Test variable map import/export" $ vm == vm'+     + -- Check that the float values are equal with an accuracy < 0.01% comparePercent :: Double -> Double -> Bool comparePercent a b = abs (a-b) < 1e-4@@ -52,7 +73,7 @@ rename g = \(a,s) -> (fromJust . vertexLabel g . vertex $ a, s)  -- | Test that a MAP is not always the projection of a MPE-compareMpeCancer = do +compareMpeAsia = do    (varmap,g) <- anyExample "asia.net"   let [x,b,d,a,s,l,t,e] = map tdv . fromJust $ mapM (flip Map.lookup varmap) ["X","B","D","A","S","L","T","E"] :: [TDV Positive]       m = mpe g [x,d] [b,a,s,l,t,e] [x =: Yes, d =: No]
Bayes/Tools.hs view
@@ -2,10 +2,16 @@ 	 -} module Bayes.Tools (-	nearlyEqual+	  nearlyEqual+  , withTempFile+  , minBoundForEnum +  , maxBoundForEnum +  , intValue 	) where  -+import System.IO(openTempFile,hClose)+import System.Directory(getTemporaryDirectory,removeFile)+import System.FilePath  -- | Floating point number comparisons which should take into account -- all the subtleties of that kind of comparison@@ -20,3 +26,26 @@         (x,y) | x == y -> True -- handle infinities               | x*y == 0 -> diff < (epsilon * epsilon)               | otherwise -> diff / (absA + absB) < epsilon+++-- | Execute an action with a temporary file. The file is deleted after.+-- The action must close the file.+-- (would be better to use handle to force the closing but it is used with action which are+-- using a filepath)+withTempFile :: (FilePath -> IO a) -> IO a +withTempFile action = do +  tempDir <- getTemporaryDirectory +  (filePath,fileHandle) <- openTempFile tempDir "bayestest" +  hClose fileHandle +  result <- action filePath +  removeFile (tempDir </> filePath)+  return result ++minBoundForEnum :: Bounded a => a -> a+minBoundForEnum _ = minBound++maxBoundForEnum :: Bounded a => a -> a+maxBoundForEnum _ = maxBound++intValue :: Enum a => a -> Int+intValue = fromEnum
Bayes/VariableElimination.hs view
@@ -19,7 +19,7 @@  import Bayes import Bayes.Factor-import Data.List(partition,minimumBy,(\\),find,foldl')+import Data.List(minimumBy,(\\),foldl') import Data.Maybe(fromJust) import Data.Function(on) import qualified Data.Map as M@@ -27,14 +27,14 @@ import Bayes.Factor.CPT  import Bayes.Factor.MaxCPT import Bayes.PrivateTypes(DVISet)+import Bayes.VariableElimination.Buckets  --import Debug.Trace   --debug s a = trace (s  ++ "\n" ++ show a ++ "\n") a --- | Elimination order-type EliminationOrder dv = [dv] + -- | Get all variables from a Bayesian Network allVariables :: (Graph g, Factor f)               => BayesianNetwork g f @@ -45,86 +45,15 @@   in    map createDV s --- | Used for bucket elimination. Factor are organized by their first DV-data Buckets f = Buckets !(EliminationOrder DV) !(M.Map DV [f]) -instance Show f => Show (Buckets f) where -  show (Buckets v m) = "BUCKET\n" ++ show v ++ "\n" ++ concatMap disp (M.toList m)-   where-    disp (v,f) = "Bucket for " ++ show v ++ "\n" ++ concatMap dispElem f ++ "\n----\n"-    dispElem f = show f ++ "\n"- convertToMaxCPT :: Buckets CPT -> Buckets MAXCPT  convertToMaxCPT (Buckets e m) = Buckets e (M.map (map convertToMaxFactor) m)   -createBuckets ::  (Factor f) -              => [f] -- ^ Factor to use for computing the marginal one-              -> EliminationOrder DV-- ^ Variables to eliminate-              -> EliminationOrder DV -- ^ Remaining variables-              -> Buckets f -createBuckets s e r = -  let -- We put the selected variables for elimination in the right order at the beginning-      -- Which means the function can work with a partial order which is completed with other-      -- variables by default.-      theOrder = e ++ r-      addDVToBucket (rf, m) dv  =-        let (fk,remaining) = partition (flip containsVariable dv) rf-        in -        (remaining, M.insert dv fk m)-      (_,b) = foldl' addDVToBucket (s,M.empty) theOrder-  in-  Buckets theOrder b --- | Get the factors for a bucket-getBucket :: DV -          -> Buckets f -          -> [f]-getBucket dv (Buckets _ m) = fromJust $ M.lookup dv m---- | Update bucket-updateBucket :: Factor f-             => DV -- ^ Variable that was eliminated-             -> f -- ^ New factor resulting from this elimination-             -> Buckets f -             -> Buckets f -updateBucket dv f b@(Buckets e m) = -  if isScalarFactor f -    then -      Buckets (remainingVarsToProcess e) (M.insert dv [f] m)-    else-      let b' = removeFromBucket dv b-      in-      addBucket b' f - where -  remainingVarsToProcess [] = []-  remainingVarsToProcess l = tail l---- | Add a factor to the right bucket-addBucket :: Factor f => Buckets f -> f -> Buckets f-addBucket (Buckets e b) f = -  let inBucket = find (f `containsVariable`) e-  in -  case inBucket of -    Nothing -> Buckets e b-    Just bucket -> Buckets e (M.insertWith' (++) bucket [f] b)---- | Remove a variable from the bucket-removeFromBucket :: DV -> Buckets f -> Buckets f -removeFromBucket dv (Buckets [] m) = Buckets [] (M.delete dv m) -removeFromBucket dv (Buckets e m) = Buckets (tail e) (M.delete dv m) --marginalizeOneVariable :: Factor f => Buckets f -> DV -> Buckets f-marginalizeOneVariable currentBucket dv   = -  let fk = getBucket dv currentBucket-      p = factorProduct fk-      f' = factorProjectOut [dv] p-  in-  updateBucket dv f' currentBucket- -- | Compute the prior marginal. All the variables in the -- elimination order are conditionning variables ( p( . | conditionning variables) )-marginal :: Factor f +marginal :: (IsBucketItem f, Factor f)          => [f] -- ^ Bayesian Network          -> EliminationOrder DV -- ^ Ordering of variables to marginalize          -> EliminationOrder DV -- ^ Ordering of remaining variables@@ -184,7 +113,7 @@     in      mpeInstantiations (resultFactor) -posteriorMarginal :: (Graph g, Factor f, Show f, BayesianDiscreteVariable dva, BayesianDiscreteVariable dvb) +posteriorMarginal :: (Graph g, IsBucketItem f, Factor f,Show f, BayesianDiscreteVariable dva, BayesianDiscreteVariable dvb)                    => BayesianNetwork g f -- ^ Bayesian Network                   -> EliminationOrder dva -- ^ Ordering of variables to marginzalie                   -> EliminationOrder dvb-- ^ Ordering of remaining variables@@ -202,7 +131,7 @@  -- | Compute the prior marginal. All the variables in the -- elimination order are conditionning variables ( p( . | conditionning variables) )-priorMarginal :: (Graph g, Factor f, Show f, BayesianDiscreteVariable dva, BayesianDiscreteVariable dvb) +priorMarginal :: (Graph g, IsBucketItem f, Factor f,Show f, BayesianDiscreteVariable dva, BayesianDiscreteVariable dvb)                => BayesianNetwork g f -- ^ Bayesian Network               -> EliminationOrder dva-- ^ Ordering of variables to marginalize               -> EliminationOrder dvb-- ^ Ordering of remaining to keep in result
+ Bayes/VariableElimination/Buckets.hs view
@@ -0,0 +1,111 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE UndecidableInstances #-}+{- | Bucket algorithms for variable elimination with enough flexibility to+also work with influence diagrams.+    +-}+module Bayes.VariableElimination.Buckets(+    -- * Types +      Buckets(..)+    , EliminationOrder(..)+    , IsBucketItem(..)+    -- * Functions +    , createBuckets +    , getBucket +    , updateBucket +    , addBucket +    , removeFromBucket +    , marginalizeOneVariable+    ) where ++import Bayes.PrivateTypes+import qualified Data.Map as M+import Data.List(partition,minimumBy,(\\),find,foldl')+import Data.Maybe(fromJust)++-- | Elimination order+type EliminationOrder dv = [dv]++-- | Used for bucket elimination. Factor are organized by their first DV+data Buckets f = Buckets !(EliminationOrder DV) !(M.Map DV [f])++instance Show f => Show (Buckets f) where +  show (Buckets v m) = "BUCKET\n" ++ show v ++ "\n" ++ concatMap disp (M.toList m)+   where+    disp (v,f) = "Bucket for " ++ show v ++ "\n" ++ concatMap dispElem f ++ "\n----\n"+    dispElem f = show f ++ "\n"++-- | Operations needed to process a bucket items+class IsBucketItem f where +    scalarItem :: f -> Bool +    itemProduct :: [f] -> f+    itemProjectOut :: DV -> f -> f+    itemContainsVariable :: f -> DV  -> Bool++++addDVToBucket :: IsBucketItem f => ([f],M.Map DV [f]) -> DV -> ([f],M.Map DV [f]) +addDVToBucket (rf, m) dv  =+  let (fk,remaining) = partition (flip itemContainsVariable dv) rf+  in +  (remaining, M.insert dv fk m)++createBuckets ::  (IsBucketItem f) +              => [f] -- ^ Factor to use for computing the marginal one+              -> EliminationOrder DV -- ^ Variables to eliminate+              -> EliminationOrder DV -- ^ Remaining variables+              -> Buckets f +createBuckets s e r = +  let -- We put the selected variables for elimination in the right order at the beginning+      -- Which means the function can work with a partial order which is completed with other+      -- variables by default.+      theOrder = e ++ r+      (_,b) = foldl' addDVToBucket (s,M.empty) theOrder+  in+  Buckets theOrder b++-- | Get the factors for a bucket+getBucket :: DV +          -> Buckets f +          -> [f]+getBucket dv (Buckets _ m) = fromJust $ M.lookup dv m++-- | Update bucket+updateBucket :: IsBucketItem f+             => DV -- ^ Variable that was eliminated+             -> f -- ^ New factor resulting from this elimination+             -> Buckets f +             -> Buckets f +updateBucket dv f b@(Buckets e m) = +  if scalarItem f +    then +      Buckets (remainingVarsToProcess e) (M.insert dv [f] m)+    else+      let b' = removeFromBucket dv b+      in+      addBucket b' f + where +  remainingVarsToProcess [] = []+  remainingVarsToProcess l = tail l++-- | Add a factor to the right bucket+addBucket :: IsBucketItem f => Buckets f -> f -> Buckets f+addBucket (Buckets e b) f = +  let inBucket = find (f `itemContainsVariable`) e+  in +  case inBucket of +    Nothing -> Buckets e b+    Just bucket -> Buckets e (M.insertWith' (++) bucket [f] b)++-- | Remove a variable from the bucket+removeFromBucket :: DV -> Buckets f -> Buckets f +removeFromBucket dv (Buckets [] m) = Buckets [] (M.delete dv m) +removeFromBucket dv (Buckets e m) = Buckets (tail e) (M.delete dv m) ++marginalizeOneVariable :: IsBucketItem f => Buckets f -> DV -> Buckets f+marginalizeOneVariable currentBucket dv   = +  let fk = getBucket dv currentBucket+      p = itemProduct fk+      f' = itemProjectOut dv p+  in+  updateBucket dv f' currentBucket
hbayes.cabal view
@@ -7,7 +7,7 @@ -- The package version. See the Haskell package versioning policy -- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for -- standards guiding when and how versions should be incremented.-Version:             0.3+Version:             0.4  -- A short (one-line) description of the package. Synopsis:            Inference with Discrete Bayesian Networks@@ -74,6 +74,12 @@     Bayes.Examples     Bayes.Examples.Tutorial     Bayes.Test.ReferencePatterns+    Bayes.Test.InfluencePatterns+    Bayes.ImportExport+    Bayes.BayesianNetwork+    Bayes.InfluenceDiagram+    Bayes.VariableElimination.Buckets+    Bayes.Examples.Influence   other-modules:     Paths_hbayes     Bayes.ImportExport.HuginNet.Splitting@@ -81,6 +87,7 @@     Bayes.FactorElimination.JTree     Bayes.Tools     Bayes.Factor.PrivateCPT+    Bayes.Network    GHC-Options: -funbox-strict-fields   Extensions: CPP@@ -105,6 +112,7 @@     parsec,     filepath,     directory,+    binary >= 0.5,     test-framework-quickcheck2,     test-framework,     test-framework-hunit,