/// <summary> /// Hard reweight by a condition that depends on associated item /// </summary> public static FiniteDist <A> ConditionHard <A>(this FiniteDist <A> distribution, Func <A, bool> condition) { return(new FiniteDist <A>( distribution.Explicit .Select(p => ItemProb(p.Item, condition(p.Item) ? p.Prob : Prob(0))) .Normalize() )); }
/// <summary> /// Display finite distribution as histogram /// </summary> /// <param name="showItem">Specifies a string representation of distribution item. Defaults to ToString.</param> public static string Histogram <A>(this FiniteDist <A> dist, Func <A, string> showItem = null, double scale = 100) { if (showItem == null) { showItem = a => a.ToString(); } return(ProbCSharp.Histogram.Finite(dist.Explicit, showItem, scale)); }
/// <summary> /// Reweight by a probability that depends on associated item /// </summary> public static FiniteDist <A> ConditionSoft <A>(this FiniteDist <A> distribution, Func <A, Prob> likelihood) { return(new FiniteDist <A>( distribution.Explicit .Select(p => ItemProb(p.Item, likelihood(p.Item).Mult(p.Prob))) .Normalize() )); }
/// <summary> /// Lifts a FiniteDist<A> into a SampleableDist<A> /// </summary> public static PrimitiveDist <A> ToSampleDist <A>(this FiniteDist <A> dist) { return(new SampleDist <A>(() => { var rand = new MathNet.Numerics.Distributions.ContinuousUniform().Sample(); return dist.Pick(Prob(rand)); })); }
/// <summary> /// Returns the probability of a certain event /// </summary> public static Prob ProbOf <A>(this FiniteDist <A> dist, Func <A, bool> eventTest) { var matches = dist.Explicit.Weights.Where(p => eventTest(p.Item)); if (!matches.Any()) { return(Prob(0)); } return(Prob(matches.Sum(p => p.Prob.Value))); }
/// <summary> /// (FiniteDist dist) >>= bind = FiniteDist $ do /// (x,p) <- dist /// (y,q) <- bind x /// return (y,p*q) /// </summary> public static FiniteDist <C> SelectMany <A, B, C>( this FiniteDist <A> self, Func <A, FiniteDist <B> > bind, Func <A, B, C> project ) { var itemProbs = from xp in self.Explicit.Weights from yq in bind(xp.Item).Explicit.Weights select ItemProb(project(xp.Item, yq.Item), xp.Prob.Mult(yq.Prob)); return(new FiniteDist <C>(Samples(itemProbs))); }
/// <summary> /// Pick a value from a distribution using a probability /// </summary> public static A Pick <A>(this FiniteDist <A> distribution, Prob pickProb) { var probVal = pickProb.Value; foreach (var prob in distribution.Explicit.Weights) { if (probVal < prob.Prob.Value) { return(prob.Item); } probVal -= prob.Prob.Value; } throw new ArgumentException("Sampling failed"); }
/// <summary> /// Calculates KL divergence of two finite distributions /// </summary> /// <param name="keyFunc">Groups identical samples</param> public static double KLDivergenceF <A, Key>(FiniteDist <A> distQ, FiniteDist <A> distP, Func <A, Key> keyFunc) where A : IComparable <A> { var qWeights = Enumerate(distQ, keyFunc); Func <A, Prob> qDensity = x => { var weight = qWeights.FirstOrDefault(ip => keyFunc(ip.Item).Equals(keyFunc(x))); if (weight == null) { return(Prob(0)); } return(weight.Prob); }; var pWeights = Enumerate(distP, keyFunc); return(pWeights.Weights .Sum(w => w.Prob.Value * Math.Log(w.Prob.Div(qDensity(w.Item)).Value))); }
/// <summary> /// Computes the posterior distribution, given a list of data and a likelihood function /// </summary> public static FiniteDist <A> UpdateOn <A, D>(this FiniteDist <A> prior, Func <A, D, Prob> likelihood, IEnumerable <D> data) { return(data.Aggregate(prior, (dist, datum) => dist.UpdateOn(likelihood, datum))); }
/// <summary> /// Computes the posterior distribution, given a piece of data and a likelihood function /// </summary> public static FiniteDist <A> UpdateOn <A, D>(this FiniteDist <A> prior, Func <A, D, Prob> likelihood, D datum) { return(prior.ConditionSoft(w => likelihood(w, datum))); }
/// <summary> /// Join two independent distributions /// </summary> public static FiniteDist <Tuple <A, B> > Join <A, B>(this FiniteDist <A> self, FiniteDist <B> other) { return(from a in self from b in other select new Tuple <A, B>(a, b)); }
/// <summary> /// Normalize a finite distribution /// </summary> public static FiniteDist <A> Normalize <A>(this FiniteDist <A> dist) { return(new FiniteDist <A>(dist.Explicit.Normalize())); }
/// <summary> /// Calculates KL divergence from list of samples and a finite distribution /// </summary> /// <param name="keyFunc">Groups identical samples</param> public static double KLDivergence <A, Key>(Samples <A> samples, FiniteDist <A> dist, Func <A, Key> keyFunc) where A : IComparable <A> { var sampleDist = CategoricalF(samples); return(KLDivergenceF(sampleDist, dist, keyFunc)); }
/// <summary> /// Aggregate & normalize samples /// The samples are arranged in ascending order /// </summary> public static Samples <A> Enumerate <A, Key>(FiniteDist <A> dist, Func <A, Key> keyFunc) where A : IComparable <A> { return(Importance.Normalize(Compact(dist.Explicit, keyFunc))); }
/// <summary> /// Primitive constructor for finite dists /// </summary> public static Dist <A> Primitive <A>(FiniteDist <A> dist) { return(new Primitive <A>(dist.ToSampleDist())); }
/// <summary> /// fmap f (FiniteDist (Samples xs)) = FiniteDist $ Samples $ map (first f) xs /// </summary> public static FiniteDist <B> Select <A, B>(this FiniteDist <A> self, Func <A, B> select) { return(new FiniteDist <B>(Samples(self.Explicit.Weights.Select(i => ItemProb(select(i.Item), i.Prob))))); }