public IEnumerable <TimePoint <ChemicalSystem> > GetPath(IList <Reaction> reactions, ChemicalSystem initialSystem, double endTime, int numPoints) { double t = 0; var evolvingSystem = initialSystem; int numReactions = reactions.Count; double reportingInterval = endTime / (double)numPoints; double nextPoint = reportingInterval; do { var randoms = _random.GetNext(); var propensities = reactions.Select(r => r.Propensity(evolvingSystem)); var totalPropensity = propensities.Sum(); var normalisedPropensities = propensities.Select(p => p / totalPropensity).ToList(); var selectedReaction = Partitioner.ToIntervals(normalisedPropensities) .Zip(reactions, (interval, reaction) => new Tuple <Tuple <double, double>, Reaction>(interval, reaction)) .Single(pair => randoms.r2 > pair.Item1.Item1 && randoms.r2 < pair.Item1.Item2) .Item2; t += Math.Log(1.0 / randoms.r1) / totalPropensity; evolvingSystem = evolvingSystem.React(selectedReaction); if (t > nextPoint) { yield return(new TimePoint <ChemicalSystem>(t, evolvingSystem)); nextPoint += reportingInterval; } } while (t <= endTime); }
public void should_partition_unit_interval() { var sequence = new [] { 0.5, 0.25, 0.125, 0.06025 }; var expected = new [] { new Tuple <double, double>(0, 0.5), new Tuple <double, double>(0.5, 0.75), new Tuple <double, double>(0.75, 0.875), new Tuple <double, double>(0.875, 1.0) }; Assert.Equal(expected, Partitioner.ToIntervals(sequence)); }