module Harmonic.Evaluation.Analysis.Markov
( Edge
, TransitionCounts
, probabilitiesFromCounts
) where
import Harmonic.Rules.Types.Harmony (Cadence)
import qualified Data.Map.Strict as Map
import Data.Map.Strict (Map)
type Edge = (Cadence, Cadence)
type TransitionCounts = Map Edge Double
type Totals = Map Cadence Double
probabilitiesFromCounts :: TransitionCounts -> Map Edge Double
probabilitiesFromCounts :: TransitionCounts -> TransitionCounts
probabilitiesFromCounts TransitionCounts
counts =
let totals :: Totals
totals = TransitionCounts -> Totals
buildTotals TransitionCounts
counts
in (Edge -> Double -> Double) -> TransitionCounts -> TransitionCounts
forall k a b. (k -> a -> b) -> Map k a -> Map k b
Map.mapWithKey (Totals -> Edge -> Double -> Double
normalise Totals
totals) TransitionCounts
counts
where
buildTotals :: TransitionCounts -> Totals
buildTotals :: TransitionCounts -> Totals
buildTotals = (Totals -> (Edge, Double) -> Totals)
-> Totals -> [(Edge, Double)] -> Totals
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Totals -> (Edge, Double) -> Totals
forall {k} {a} {b}.
(Ord k, Num a) =>
Map k a -> ((k, b), a) -> Map k a
accumulate Totals
forall k a. Map k a
Map.empty ([(Edge, Double)] -> Totals)
-> (TransitionCounts -> [(Edge, Double)])
-> TransitionCounts
-> Totals
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TransitionCounts -> [(Edge, Double)]
forall k a. Map k a -> [(k, a)]
Map.toList
where
accumulate :: Map k a -> ((k, b), a) -> Map k a
accumulate Map k a
acc ((k
from,b
_), a
weight) = (a -> a -> a) -> k -> a -> Map k a -> Map k a
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
Map.insertWith a -> a -> a
forall a. Num a => a -> a -> a
(+) k
from a
weight Map k a
acc
normalise :: Totals -> Edge -> Double -> Double
normalise :: Totals -> Edge -> Double -> Double
normalise Totals
totals (Cadence
from, Cadence
_) Double
weight =
case Cadence -> Totals -> Maybe Double
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup Cadence
from Totals
totals of
Just Double
total | Double
total Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
> Double
0 -> Double
weight Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
total
Maybe Double
_ -> Double
0