module Harmonic.Evaluation.Analysis.Markov
( Edge
, TransitionCounts
, transitionCounts
, transitionProbabilities
) where
import Harmonic.Rules.Types.Harmony (Cadence)
import qualified Data.Map.Strict as Map
import Data.Map.Strict (Map)
import Data.List (foldl')
type Edge = (Cadence, Cadence)
type TransitionCounts = Map Edge Double
type Totals = Map Cadence Double
transitionCounts :: [Cadence] -> TransitionCounts
transitionCounts :: [Cadence] -> TransitionCounts
transitionCounts [Cadence]
cadences =
(TransitionCounts -> Edge -> TransitionCounts)
-> TransitionCounts -> [Edge] -> TransitionCounts
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' TransitionCounts -> Edge -> TransitionCounts
forall {k} {a}. (Ord k, Num a) => Map k a -> k -> Map k a
insertEdge TransitionCounts
forall k a. Map k a
Map.empty ([Cadence] -> [Cadence] -> [Edge]
forall a b. [a] -> [b] -> [(a, b)]
zip [Cadence]
cadences (Int -> [Cadence] -> [Cadence]
forall a. Int -> [a] -> [a]
drop Int
1 [Cadence]
cadences))
where
insertEdge :: Map k a -> k -> Map k a
insertEdge Map k a
acc k
edge = (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
edge a
1 Map k a
acc
transitionProbabilities :: [Cadence] -> Map Edge Double
transitionProbabilities :: [Cadence] -> TransitionCounts
transitionProbabilities [Cadence]
cadences =
let counts :: TransitionCounts
counts = [Cadence] -> TransitionCounts
transitionCounts [Cadence]
cadences
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