public void CouldCalculateSMAWithWidthEQ() { Assert.Throws <NotImplementedException>(() => { var count = 20; var sm = new SortedMap <int, double>(); sm.Add(0, 0); for (int i = 2; i <= count; i++) { sm.Add(i, i); } sm.Remove(11); sm.Remove(12); var onlineOp = new SumAvgOnlineOp <int, double, SortedMapCursor <int, double> >(); var smaOp = new SpanOpWidth <int, double, double, SortedMapCursor <int, double>, SumAvgOnlineOp <int, double, SortedMapCursor <int, double> > > (2, Lookup.EQ, onlineOp); var smaSeries = new SpanOpImpl <int, double, double, SpanOpWidth <int, double, double, SortedMapCursor <int, double>, SumAvgOnlineOp <int, double, SortedMapCursor <int, double> > >, SortedMapCursor <int, double> >(sm.GetEnumerator(), smaOp).Source; foreach (var keyValuePair in smaSeries) { Trace.WriteLine($"{keyValuePair.Key} - {keyValuePair.Value}"); } }); }
internal static Series <TKey, TValue, Range <TKey, TValue, SortedMapCursor <TKey, TValue> > > Range <TKey, TValue>( this SortedMap <TKey, TValue> series, Opt <TKey> startKey, Opt <TKey> endKey, bool startInclusive = true, bool endInclusive = true) { var cursor = new Range <TKey, TValue, SortedMapCursor <TKey, TValue> >( series.GetEnumerator(), startKey, endKey, startInclusive, endInclusive); return(cursor.Source); }
public void CouldFillThenAddValues() { var sm = new SortedMap <int, double> { { 1, 0 }, { 3, 2 }, { 5, 4 } }; var src = (sm.GetEnumerator() as ISpecializedCursor <int, double, SortedMapCursor <int, double> >).Source; var filled = src.Fill(0); var filled2 = (src as ISpecializedSeries <int, double, SortedMapCursor <int, double> >).Fill(0); var filled3 = sm.Fill(0); var fc = new Fill <int, double, Cursor <int, double> >(sm.GetSpecializedCursor(), 41).Initialize(); var c = (fc.Source + 1).GetEnumerator(); Assert.True(c.MoveNext()); Assert.AreEqual(1, c.CurrentValue); Assert.True(c.MoveNext()); Assert.AreEqual(3, c.CurrentValue); Assert.True(c.MoveNext()); Assert.AreEqual(5, c.CurrentValue); Assert.False(c.MoveNext()); Assert.AreEqual(5, c.CurrentValue); Assert.True(c.MoveLast()); Assert.AreEqual(5, c.CurrentValue); Assert.False(c.MoveAt(4, Lookup.EQ)); Assert.AreEqual(5, c.CurrentValue); Assert.True(c.MoveAt(4, Lookup.LE)); Assert.AreEqual(3, c.CurrentValue); Assert.True(c.TryGetValue(2, out var x)); Assert.AreEqual(3, c.CurrentValue); Assert.AreEqual(42, x); var clone = c.Clone(); Assert.True(c.MoveAt(4, Lookup.GT)); Assert.AreEqual(5, c.CurrentValue); Assert.AreEqual(3, clone.CurrentValue); Assert.True(clone.TryGetValue(0, out var y)); Assert.AreEqual(42, y); c.Dispose(); }
public void CouldAddTwoSeriesWithDifferentKeys() { var count = 10000; var sm1 = new SortedMap <int, double>(); var sm2 = new SortedMap <int, double>(); var result = new SortedMap <int, double>(); double expected = 0; for (int i = 0; i < count; i++) { sm1.Add(i, i); if (i % 3 == 0) { sm2.Add(i, 2 * i); expected += i + 2 * i; result.Add(i, i + 2 * i); } } for (int r = 0; r < 1; r++) { var c1 = sm1.GetEnumerator(); var c2 = sm2.GetEnumerator(); var zipCursor = new Zip <int, double, double, SortedMapCursor <int, double>, SortedMapCursor <int, double> >( c1, c2).Initialize(); double actual = 0; using (Benchmark.Run("ZipDiscrete MN", sm1.Count + sm2.Count)) { while (zipCursor.MoveNext()) { actual += zipCursor.Map((k, v) => v.Item1 + v.Item2).CurrentValue; } } Assert.AreEqual(expected, actual); zipCursor.Reset(); actual = 0; using (Benchmark.Run("ZipDiscrete MP", sm1.Count + sm2.Count)) { while (zipCursor.MovePrevious()) { actual += zipCursor.Map((k, v) => v.Item1 + v.Item2).CurrentValue; } } Assert.AreEqual(expected, actual); } Benchmark.Dump(); }
public void CouldMapValuesBenchmark() { var sm = new SortedMap <int, double>(); var count = 10000000; //sm.AddLast(0, 0); // make irregular for (int i = 2; i < count; i++) { sm.AddLast(i, i); } for (int r = 0; r < 10; r++) { var map = new ArithmeticSeries <int, double, MultiplyOp <double>, SortedMapCursor <int, double> >( sm.GetEnumerator(), 2.0); var map2 = new ArithmeticSeries <int, double, MultiplyOp <double>, ArithmeticSeries <int, double, MultiplyOp <double>, SortedMapCursor <int, double> > >( map, 2.0); var sum = 0.0; using (Benchmark.Run("ArithmeticSeries", count)) { foreach (var kvp in map2) { sum += kvp.Value; } } Assert.IsTrue(sum > 0); } for (int r = 0; r < 10; r++) { var map = sm //.Select(x => new KeyValuePair<int, double>(x.Key, x.Value * 2)) .Select(x => new KeyValuePair <int, double>(x.Key, x.Value * 2)); var sum = 0.0; using (Benchmark.Run("LINQ", count)) { foreach (var kvp in map) { sum += kvp.Value; } } Assert.IsTrue(sum > 0); } }
public void CouldUseRangeCursorStruct() { SortedMap <int, double> sm = null; Assert.Throws <NullReferenceException>(() => { var nullRange = new Range <int, double, SortedMapCursor <int, double> >(sm.GetEnumerator(), 0, Int32.MaxValue, true, true); }); var empty = new SortedMap <int, double>(); var rangeCursor = new Range <int, double, SortedMapCursor <int, double> >(empty.GetEnumerator(), 0, Int32.MaxValue, true, true); // NB Source just wraps the cursor in a new struct, // same as new CursorSeries<int, double, RangeCursor<int, double, SortedMapCursor<int, double>>>(rangeCursor); var range = rangeCursor.Source; Assert.True(range.IsEmpty); Assert.False(range.Any()); var nonEmpty = new SortedMap <int, double> { { 1, 1 } }; var rangeCursor1 = new Range <int, double, SortedMapCursor <int, double> >(nonEmpty.GetEnumerator(), 0, Int32.MaxValue, true, true); var range1 = rangeCursor1.Source; Assert.True(range1.Any()); }
public void CouldCalculateSMAWithCount() { var count = 20; var sm = new SortedMap <int, double>(); for (int i = 1; i <= count; i++) { sm.Add(i, i); } DoTest(true); DoTest(false); DoTestViaSpanOpCount(true); DoTestViaSpanOpCount(false); void DoTest(bool allowIncomplete) { // TODO separate tests/cases for true/false var smaOp = new MAvgCount <int, double, SortedMapCursor <int, double> >(10, allowIncomplete); var smaCursor = new SpanOpImpl <int, double, double, MAvgCount <int, double, SortedMapCursor <int, double> >, SortedMapCursor <int, double> >(sm.GetEnumerator(), smaOp); // this monster type must be hidden in the same way Lag hides its implementation Series <int, double, SpanOpImpl <int, double, double, MAvgCount <int, double, SortedMapCursor <int, double> >, SortedMapCursor <int, double> > > smaSeries; smaSeries = smaCursor.Source; var sm2 = smaSeries.ToSortedMap(); Assert.AreEqual(sm2.First, smaSeries.First); Assert.AreEqual(sm2.Last, smaSeries.Last); Assert.True(SeriesContract.MoveAtShouldWorkOnLazySeries(smaSeries)); Assert.True(SeriesContract.ClonedCursorsAreIndependent(smaSeries)); if (!allowIncomplete) { var trueSma = sm.Window(10).Map(x => x.Values.Average()); Assert.True(trueSma.Keys.SequenceEqual(smaSeries.Keys)); Assert.True(trueSma.Values.SequenceEqual(smaSeries.Values)); } Debug.WriteLine("SMA"); foreach (var keyValuePair in smaSeries) { Debug.WriteLine($"{keyValuePair.Key} - {keyValuePair.Value}"); } } void DoTestViaSpanOpCount(bool allowIncomplete) { // TODO separate tests/cases for true/false var onlineOp = new SumAvgOnlineOp <int, double, SortedMapCursor <int, double> >(); var smaOp = new SpanOpCount <int, double, double, SortedMapCursor <int, double>, SumAvgOnlineOp <int, double, SortedMapCursor <int, double> > >(10, allowIncomplete, onlineOp); var smaCursor = new SpanOpImpl <int, double, double, SpanOpCount <int, double, double, SortedMapCursor <int, double>, SumAvgOnlineOp <int, double, SortedMapCursor <int, double> > >, SortedMapCursor <int, double> >(sm.GetEnumerator(), smaOp); // this monster type must be hidden in the same way Lag hides its implementation Series <int, double, SpanOpImpl <int, double, double, SpanOpCount <int, double, double, SortedMapCursor <int, double>, SumAvgOnlineOp <int, double, SortedMapCursor <int, double> > >, SortedMapCursor <int, double> > > smaSeries; smaSeries = smaCursor.Source; var sm2 = smaSeries.ToSortedMap(); Assert.AreEqual(sm2.First, smaSeries.First); Assert.AreEqual(sm2.Last, smaSeries.Last); Assert.True(SeriesContract.MoveAtShouldWorkOnLazySeries(smaSeries)); Assert.True(SeriesContract.ClonedCursorsAreIndependent(smaSeries)); if (!allowIncomplete) { var trueSma = sm.Window(10).Map(x => x.Values.Average()); Assert.True(trueSma.Keys.SequenceEqual(smaSeries.Keys)); Assert.True(trueSma.Values.SequenceEqual(smaSeries.Values)); } Debug.WriteLine("SMA"); foreach (var keyValuePair in smaSeries) { Debug.WriteLine($"{keyValuePair.Key} - {keyValuePair.Value}"); } } }
public void CouldUseStructSeries() { var sm = new SortedMap <int, double>(); var count = 10000000; sm.AddLast(0, 0); // make irregular for (int i = 2; i < count; i++) { sm.AddLast(i, i); } for (int r = 0; r < 10; r++) { var sum = 0.0; { using (Benchmark.Run("SortedMap", count)) { foreach (var kvp in sm) { sum += kvp.Value; } } Assert.IsTrue(sum > 0); } sum = 0.0; { var map = new ArithmeticSeries <int, double, MultiplyOp <double>, SortedMapCursor <int, double> >( sm.GetEnumerator(), 2.0); var map2 = new ArithmeticSeries <int, double, AddOp <double>, ArithmeticSeries <int, double, MultiplyOp <double>, SortedMapCursor <int, double> > >( map, 2.0); using (Benchmark.Run("ArithmeticSeries", count)) { foreach (var kvp in map2) { sum += kvp.Value; } } Assert.IsTrue(sum > 0); } var sum1 = 0.0; { var c = new Op <int, double, MultiplyOp <double>, SortedMapCursor <int, double> >( sm.GetEnumerator(), 2.0); var c1 = new Op <int, double, AddOp <double>, Op <int, double, MultiplyOp <double>, SortedMapCursor <int, double> > >( c, 2.0); using (Benchmark.Run("ArithmeticCursor", count)) { foreach (var kvp in c1.Source) { sum1 += kvp.Value; } } Assert.IsTrue(sum1 > 0); } Assert.AreEqual(sum, sum1); } Benchmark.Dump("Compare enumeration speed of SortedMap and two arithmetic implementations using class and struct (item workload is multiply by 2 then add 2)."); }
public void EnumerateScmSpeed() { const int count = 10_000_000; var sl = new SortedList <int, int>(); var sm = new SortedMap <int, int>(); sm.IsSynchronized = false; var scm = new SortedChunkedMap <int, int>(); scm.IsSynchronized = false; for (int i = 0; i < count; i++) { if (i % 1000 != 0) { sl.Add(i, i); sm.Add(i, i); scm.Add(i, i); } } //var ism = new ImmutableSortedMap<int, int>(sm); long sum; for (int r = 0; r < 20; r++) { sum = 0L; using (Benchmark.Run("SL", count)) { using (var c = sl.GetEnumerator()) { while (c.MoveNext()) { sum += c.Current.Value; } } } Assert.True(sum > 0); sum = 0L; using (Benchmark.Run("SM", count)) { using (var c = sm.GetEnumerator()) { while (c.MoveNext()) { sum += c.Current.Value; } } } Assert.True(sum > 0); //sum = 0L; //using (Benchmark.Run("ISM", count)) //{ // foreach (var item in ism) // { // sum += item.Value; // } //} //Assert.True(sum > 0); sum = 0L; using (Benchmark.Run("SCM", count)) { using (var c = scm.GetEnumerator()) { while (c.MoveNext()) { sum += c.Current.Value; } } } Assert.True(sum > 0); } Benchmark.Dump(); }
public void CouldMapValuesBenchmark() { var sm = new SortedMap <int, double>(); var count = 10000000; sm.AddLast(0, 0); for (int i = 2; i < count; i++) { sm.AddLast(i, i); } for (int r = 0; r < 10; r++) { var sw = new Stopwatch(); sw.Restart(); var map = new MapValuesSeries <int, double, double, SortedMapCursor <int, double> >(sm.GetEnumerator(), i => i * 2); var map2 = new MapValuesSeries <int, double, double, MapValuesSeries <int, double, double, SortedMapCursor <int, double> > >(map, i => i * 2); var sum = 0.0; foreach (var kvp in map2) { sum += kvp.Value; } sw.Stop(); Assert.IsTrue(sum > 0); Console.WriteLine($"Mops {sw.MOPS(count)}"); } //for (int r = 0; r < 10; r++) //{ // var sw = new Stopwatch(); // sw.Restart(); // var map = sm // //.Select(x => new KeyValuePair<int, double>(x.Key, x.Value * 2)) // .Select(x => new KeyValuePair<int, double>(x.Key, x.Value * 2)); // var sum = 0.0; // foreach (var kvp in map) // { // sum += kvp.Value; // } // sw.Stop(); // Assert.IsTrue(sum > 0); // Console.WriteLine($"LINQ Mops {sw.MOPS(count)}"); //} }
public void CouldMapValues() { var sm = new SortedMap <int, double> { { 1, 1 } }; Series <int, double, Range <int, double, SortedMapCursor <int, double> > > s1; s1 = sm.After(1); // TODO see the monster signature! // try to swap Map with Range (or any CursorSeries) so that this signature could // be automatically reduced to just two step var m2 = s1.Map((x) => x + 1).After(1) .Map((x) => x + 1).After(1).Map((x) => x + 1).After(1).Map((x) => x + 1) .Map((x) => x + 1).After(1).Map((x) => x + 1).After(1).Map((x) => x + 1) .Map((x) => x + 1).After(1).Map((x) => x + 1).After(1).Map((x) => x + 1) .Map((x) => x + 1).After(1).Map((x) => x + 1).After(1).Map((x) => x + 1) .Map((x) => x + 1).After(1).Map((x) => x + 1).After(1).Map((x) => x + 1) .Map((x) => x + 1).After(1).Map((x) => x + 1).After(1).Map((x) => x + 1) .Map((x) => x + 1).After(1).Map((x) => x + 1).After(1).Map((x) => x + 1); var map = new MapValuesSeries <int, double, double, SortedMapCursor <int, double> >(sm.GetEnumerator(), i => i * 2); var map1 = new MapValuesSeries <int, double, double, MapValuesSeries <int, double, double, SortedMapCursor <int, double> > >(map, i => i * 2); var map2 = new MapValuesSeries <int, double, double, Cursor <int, double> >(new Cursor <int, double>(map.Range(0, Int32.MaxValue, true, true).GetEnumerator()), i => i * 2); var map3 = new MapValuesSeries <int, double, double, Cursor <int, double> >(new Cursor <int, double>(map.Range(2, Int32.MaxValue, true, true).GetEnumerator()), i => i * 2); Assert.AreEqual(2, map.First.Value); Assert.AreEqual(4, map1.First.Value); Assert.AreEqual(4, map2.First.Value); Assert.True(map3.IsEmpty); }
public void Stat2StDevBenchmark() { var comparer = KeyComparer <int> .Default; var count = 1_000_000; var width = 20; var sm = new SortedMap <int, double>(count, comparer); sm.Add(0, 0); for (int i = 2; i <= count; i++) { sm.Add(i, i); } // var ds1 = new Deedle.Series<int, double>(sm.Keys.ToArray(), sm.Values.ToArray()); var sum = 0.0; for (int r = 0; r < 10; r++) { var sum1 = 0.0; using (Benchmark.Run("Stat2 Online N", count * width)) { foreach (var stat2 in sm.Stat2(width).Values) { sum1 += stat2.StDev; } } Assert.True(sum1 != 0); var sum2 = 0.0; using (Benchmark.Run("Stat2 Online Width GE", count * width)) { foreach (var stat2 in sm.Stat2(width - 1, Lookup.GE).Values) { sum2 += stat2.StDev; } } Assert.True(sum2 != 0); var sum3 = 0.0; using (Benchmark.Run("Stat2 Window N", count * width)) { foreach (var stat2 in sm.Window(width).Map(x => x.Stat2()).Values) { sum3 += stat2.StDev; } } Assert.True(sum3 != 0); var sum4 = 0.0; using (Benchmark.Run("Stat2 Window Width GE", count * width)) { foreach (var stat2 in sm.Window(width - 1, Lookup.GE).Map(x => x.Stat2()).Values) { sum4 += stat2.StDev; } } Assert.True(sum4 != 0); //var sum5 = 0.0; //using (Benchmark.Run("Deedle (online)", count * width)) //{ // var deedleStDev = Deedle.Stats.movingStdDev(width, ds1); // foreach (var keyValuePair in deedleStDev.Values) // { // sum5 += keyValuePair; // } //} //Assert.True(sum5 != 0); Assert.True(Math.Abs(sum1 / sum2 - 1) < 0.000001); Assert.True(Math.Abs(sum1 / sum3 - 1) < 0.000001); Assert.True(Math.Abs(sum1 / sum4 - 1) < 0.000001); // Assert.True(Math.Abs(sum1 / sum5 - 1) < 0.000001); sum = 0.0; using (Benchmark.Run("SortedMap enumeration", count)) { var cursor = sm.GetEnumerator(); while (cursor.MoveNext()) { sum += cursor.CurrentValue; } } Assert.True(sum != 0); } Benchmark.Dump($"The window width is {width}. Stat2 MOPS are calculated as a number of calculated values multiplied by width, " + $"which is equivalent to the total number of cursor moves for Window case. SortedMap line is for reference - it is the " + $"speed of raw iteration over SM without Stat2/Windows overheads (and not multiplied by width)."); }
public void WindowDirectAndIndirectSpanOpBenchmark() { Settings.DoAdditionalCorrectnessChecks = false; var count = 100000; var width = 20; var sm = new SortedMap <int, double>(); sm.Add(0, 0); // make irregular, it's faster but more memory for (int i = 2; i <= count; i++) { sm.Add(i, i); } var op = new WindowOnlineOp <int, double, SortedMapCursor <int, double> >(); var spanOp = new SpanOpCount <int, double, Range <int, double, SortedMapCursor <int, double> >, SortedMapCursor <int, double>, WindowOnlineOp <int, double, SortedMapCursor <int, double> > >(20, false, op); var window = new SpanOpImpl <int, double, Range <int, double, SortedMapCursor <int, double> >, SpanOpCount <int, double, Range <int, double, SortedMapCursor <int, double> >, SortedMapCursor <int, double>, WindowOnlineOp <int, double, SortedMapCursor <int, double> > >, SortedMapCursor <int, double> >(sm.GetEnumerator(), spanOp).Source .Map(x => { var sum = 0.0; var c = 0; foreach (var keyValuePair in x.Source) { sum += keyValuePair.Value; c++; } return(sum / c); // x.CursorDefinition.Count TODO }); var spanOpCombined = new SpanOp <int, double, Range <int, double, SortedMapCursor <int, double> >, SortedMapCursor <int, double>, WindowOnlineOp <int, double, SortedMapCursor <int, double> > >(20, false, op, sm.comparer); var windowCombined = new SpanOpImpl <int, double, Range <int, double, SortedMapCursor <int, double> >, SpanOp <int, double, Range <int, double, SortedMapCursor <int, double> >, SortedMapCursor <int, double>, WindowOnlineOp <int, double, SortedMapCursor <int, double> > >, SortedMapCursor <int, double> >(sm.GetEnumerator(), spanOpCombined).Source .Map(x => { var sum = 0.0; var c = 0; foreach (var keyValuePair in x.Source) { sum += keyValuePair.Value; c++; } return(sum / c); // x.CursorDefinition.Count TODO }); var windowExtension = sm.Window(width).Map(x => { var sum = 0.0; var c = 0; foreach (var keyValuePair in x) { sum += keyValuePair.Value; c++; } return(sum / c); // x.CursorDefinition.Count TODO }); for (int round = 0; round < 20; round++) { double sum1 = 0.0; using (Benchmark.Run("Window SpanOpCount", count * width)) { foreach (var keyValuePair in window) { sum1 += keyValuePair.Value; } } double sum2 = 0.0; using (Benchmark.Run("Window SpanOp", count * width)) { foreach (var keyValuePair in windowCombined) { sum2 += keyValuePair.Value; } } double sum3 = 0.0; using (Benchmark.Run("Window Extension", count * width)) { foreach (var keyValuePair in windowExtension) { sum3 += keyValuePair.Value; } } Assert.AreEqual(sum1, sum2); Assert.AreEqual(sum1, sum3); } Benchmark.Dump($"The window width is {width}."); }
public void CouldCalculateSMAWithWidth() { var count = 20; var sm = new SortedMap <int, double>(); for (int i = 1; i <= count; i++) { sm.Add(i, i); } DoTest(Lookup.EQ); DoTest(Lookup.GE); DoTest(Lookup.GT); DoTest(Lookup.LE); DoTest(Lookup.LT); DoTestViaSpanOpWidth(Lookup.EQ); DoTestViaSpanOpWidth(Lookup.GE); DoTestViaSpanOpWidth(Lookup.GT); DoTestViaSpanOpWidth(Lookup.LE); DoTestViaSpanOpWidth(Lookup.LT); void DoTest(Lookup lookup) { // width 9 is the same as count = 10 for the regular int series var smaOp = new MAvgWidth <int, double, SortedMapCursor <int, double> >(9, lookup); var smaCursor = new SpanOpImpl <int, double, double, MAvgWidth <int, double, SortedMapCursor <int, double> >, SortedMapCursor <int, double> >(sm.GetEnumerator(), smaOp); // this monster type must be hidden in the same way Lag hides its implementation Series <int, double, SpanOpImpl <int, double, double, MAvgWidth <int, double, SortedMapCursor <int, double> >, SortedMapCursor <int, double> > > smaSeries; smaSeries = smaCursor.Source; var sm2 = smaSeries.ToSortedMap(); Assert.AreEqual(sm2.First, smaSeries.First); Assert.AreEqual(sm2.Last, smaSeries.Last); Assert.True(SeriesContract.MoveAtShouldWorkOnLazySeries(smaSeries)); Assert.True(SeriesContract.ClonedCursorsAreIndependent(smaSeries)); if (lookup == Lookup.EQ || lookup == Lookup.GE) { var trueSma = sm.Window(10).Map(x => x.Values.Average()); Assert.True(trueSma.Keys.SequenceEqual(smaSeries.Keys)); Assert.True(trueSma.Values.SequenceEqual(smaSeries.Values)); } if (lookup == Lookup.GT) { var trueSma = sm.Window(11).Map(x => x.Values.Average()); Assert.True(trueSma.Keys.SequenceEqual(smaSeries.Keys)); Assert.True(trueSma.Values.SequenceEqual(smaSeries.Values)); } if (lookup == Lookup.LE) { var smaOp1 = new MAvgCount <int, double, SortedMapCursor <int, double> >(10, true); var trueSma = new SpanOpImpl <int, double, double, MAvgCount <int, double, SortedMapCursor <int, double> >, SortedMapCursor <int, double> >(sm.GetEnumerator(), smaOp1).Source; Assert.True(trueSma.Keys.SequenceEqual(smaSeries.Keys)); Assert.True(trueSma.Values.SequenceEqual(smaSeries.Values)); } if (lookup == Lookup.LT) { var smaOp1 = new MAvgCount <int, double, SortedMapCursor <int, double> >(9, true); var trueSma = new SpanOpImpl <int, double, double, MAvgCount <int, double, SortedMapCursor <int, double> >, SortedMapCursor <int, double> >(sm.GetEnumerator(), smaOp1).Source; Assert.True(trueSma.Keys.SequenceEqual(smaSeries.Keys)); Assert.True(trueSma.Values.SequenceEqual(smaSeries.Values)); } Debug.WriteLine("SMA"); foreach (var keyValuePair in smaSeries) { Debug.WriteLine($"{keyValuePair.Key} - {keyValuePair.Value}"); } } void DoTestViaSpanOpWidth(Lookup lookup) { // width 9 is the same as count = 10 for the regular int series var onlineOp = new SumAvgOnlineOp <int, double, SortedMapCursor <int, double> >(); var smaOp = new SpanOpWidth <int, double, double, SortedMapCursor <int, double>, SumAvgOnlineOp <int, double, SortedMapCursor <int, double> > >(9, lookup, onlineOp); var smaCursor = new SpanOpImpl <int, double, double, SpanOpWidth <int, double, double, SortedMapCursor <int, double>, SumAvgOnlineOp <int, double, SortedMapCursor <int, double> > >, SortedMapCursor <int, double> >(sm.GetEnumerator(), smaOp); // this monster type must be hidden in the same way Lag hides its implementation Series <int, double, SpanOpImpl <int, double, double, SpanOpWidth <int, double, double, SortedMapCursor <int, double>, SumAvgOnlineOp <int, double, SortedMapCursor <int, double> > >, SortedMapCursor <int, double> > > smaSeries; smaSeries = smaCursor.Source; var sm2 = smaSeries.ToSortedMap(); Assert.AreEqual(sm2.First, smaSeries.First); Assert.AreEqual(sm2.Last, smaSeries.Last); Assert.True(SeriesContract.MoveAtShouldWorkOnLazySeries(smaSeries)); Assert.True(SeriesContract.ClonedCursorsAreIndependent(smaSeries)); if (lookup == Lookup.EQ || lookup == Lookup.GE) { var trueSma = sm.Window(10).Map(x => x.Values.Average()); Assert.True(trueSma.Keys.SequenceEqual(smaSeries.Keys)); Assert.True(trueSma.Values.SequenceEqual(smaSeries.Values)); } if (lookup == Lookup.GT) { var trueSma = sm.Window(11).Map(x => x.Values.Average()); Assert.True(trueSma.Keys.SequenceEqual(smaSeries.Keys)); Assert.True(trueSma.Values.SequenceEqual(smaSeries.Values)); } if (lookup == Lookup.LE) { var smaOp1 = new MAvgCount <int, double, SortedMapCursor <int, double> >(10, true); var trueSma = new SpanOpImpl <int, double, double, MAvgCount <int, double, SortedMapCursor <int, double> >, SortedMapCursor <int, double> >(sm.GetEnumerator(), smaOp1).Source; Assert.True(trueSma.Keys.SequenceEqual(smaSeries.Keys)); Assert.True(trueSma.Values.SequenceEqual(smaSeries.Values)); } if (lookup == Lookup.LT) { var smaOp1 = new MAvgCount <int, double, SortedMapCursor <int, double> >(9, true); var trueSma = new SpanOpImpl <int, double, double, MAvgCount <int, double, SortedMapCursor <int, double> >, SortedMapCursor <int, double> >(sm.GetEnumerator(), smaOp1).Source; Assert.True(trueSma.Keys.SequenceEqual(smaSeries.Keys)); Assert.True(trueSma.Values.SequenceEqual(smaSeries.Values)); } Debug.WriteLine("SMA"); foreach (var keyValuePair in smaSeries) { Debug.WriteLine($"{keyValuePair.Key} - {keyValuePair.Value}"); } } }
public void CouldMoveAt() { var count = 100; var sm0 = new SortedMap <int, double>(); var sm1 = new SortedMap <int, double>(); var sm2 = new SortedMap <int, double>(); double expected = 0; for (int i = 1; i < count; i++) { sm0.Add(i, i); if (i % 3 == 0) { sm2.Add(i, 2 * i); expected += 123 + 2 * i; } else { sm1.Add(i, i); expected += i + 42; } } var fc = new Fill <int, double, SortedMapCursor <int, double> >(sm0.GetEnumerator(), -1); var fc1 = new Fill <int, double, SortedMapCursor <int, double> >(sm1.GetEnumerator(), 123); var fc2 = new Fill <int, double, SortedMapCursor <int, double> >(sm2.GetEnumerator(), 42); var zipCursor = new Zip <int, double, double, Fill <int, double, SortedMapCursor <int, double> >, Fill <int, double, SortedMapCursor <int, double> > >( fc, fc2).Map((k, v) => v.Item1 + v.Item2) .Initialize(); Assert.IsTrue(zipCursor.MoveAt(2, Lookup.EQ)); Assert.AreEqual(44, zipCursor.CurrentValue); Assert.IsTrue(zipCursor.MoveAt(2, Lookup.LE)); Assert.AreEqual(44, zipCursor.CurrentValue); Assert.IsTrue(zipCursor.MoveAt(2, Lookup.GE)); Assert.AreEqual(44, zipCursor.CurrentValue); Assert.IsTrue(zipCursor.MoveAt(2, Lookup.LT)); Assert.AreEqual(43, zipCursor.CurrentValue); Assert.IsTrue(zipCursor.MoveAt(2, Lookup.GT)); Assert.AreEqual(9, zipCursor.CurrentValue); var zipCursor1 = new Zip <int, double, double, Fill <int, double, SortedMapCursor <int, double> >, Fill <int, double, SortedMapCursor <int, double> > >( fc1, fc2).Map((k, v) => v.Item1 + v.Item2) .Initialize(); Assert.IsTrue(zipCursor1.MoveAt(2, Lookup.EQ)); Assert.AreEqual(44, zipCursor1.CurrentValue); Assert.IsTrue(zipCursor1.MoveAt(2, Lookup.LE)); Assert.AreEqual(44, zipCursor1.CurrentValue); Assert.IsTrue(zipCursor1.MoveAt(2, Lookup.GE)); Assert.AreEqual(44, zipCursor1.CurrentValue); Assert.IsTrue(zipCursor1.MoveAt(2, Lookup.LT)); Assert.AreEqual(43, zipCursor1.CurrentValue); Assert.IsTrue(zipCursor1.MoveAt(2, Lookup.GT)); Assert.AreEqual(129, zipCursor1.CurrentValue); }
public void CouldAddContinuousSeries() { var count = 10000; //0; var sm1 = new SortedMap <int, double>(); var sm2 = new SortedMap <int, double>(); double expected = 0; for (int i = 1; i < count; i++) { if (i % 2 == 0) { sm2.Add(i, 2 * i); expected += 123 + 2 * i; } else { sm1.Add(i, i); expected += i + 42; } } for (int r = 0; r < 20; r++) { var fc1 = new Fill <int, double, SortedMapCursor <int, double> >(sm1.GetEnumerator(), 123); var fc2 = new Fill <int, double, SortedMapCursor <int, double> >(sm2.GetEnumerator(), 42); var zipCursor = new Zip <int, double, double, Fill <int, double, SortedMapCursor <int, double> >, Fill <int, double, SortedMapCursor <int, double> > >( fc1, fc2).Map((k, v) => v.Item1 + v.Item2) .Initialize(); double actual = 0; using (Benchmark.Run("ZipContinuous MN", (sm1.Count + sm2.Count) * 2) ) // NB multiply by 2, we evaluate on missing, should count virtual values as well { while (zipCursor.MoveNext()) { actual += zipCursor.CurrentValue; } } Assert.AreEqual(expected, actual); zipCursor.Reset(); actual = 0; using (Benchmark.Run("ZipContinuous MP", (sm1.Count + sm2.Count) * 2) ) // NB multiply by 2, we evaluate on missing, should count virtual values as well { while (zipCursor.MoveNext()) { actual += zipCursor.CurrentValue; } } Assert.AreEqual(expected, actual); } Benchmark.Dump(); }
public void CouldAddTwoSeriesWithSameKeys(double expected, SortedMap <int, double> sm1, SortedMap <int, double> sm2) { var count = sm1.Count; var c1 = sm1.GetEnumerator(); var c2 = sm2.GetEnumerator(); //var ds1 = new Deedle.Series<int, double>(sm1.Keys.ToArray(), sm1.Values.ToArray()); //var ds2 = new Deedle.Series<int, double>(sm2.Keys.ToArray(), sm2.Values.ToArray()); Assert.NotNull(c1.Comparer); Assert.NotNull(c2.Comparer); var zipSum = (sm1 + sm2); double actual = 0; var zipCursor = //zipSum.GetAsyncEnumerator(); new Zip <int, double, double, SortedMapCursor <int, double>, SortedMapCursor <int, double> >( c1, c2); //.Map((k, v) => v.Item1 + v.Item2) var op2 = new Op2 <int, double, AddOp <double>, Zip <int, double, double, SortedMapCursor <int, double>, SortedMapCursor <int, double> > >(zipCursor).Source; var zipCursorOp2 = op2.GetEnumerator(); using (Benchmark.Run("Zip", count * 2)) { while (zipCursorOp2.MoveNext()) { actual += zipCursorOp2.CurrentValue; } } Assert.AreEqual(expected, actual); //var zipped = sm1.Zip(sm2, (k, l, r) => l + r); // sm1.Zip(sm2).Map((k, v) => v.Item1 + v.Item2); // //actual = 0; //using (Benchmark.Run("Zip MN Extension", count * 2)) //{ // foreach (var keyValuePair in zipped) // { // actual += keyValuePair.Value; // } //} //Assert.AreEqual(expected, actual); //var zipN = new[] { sm1, sm2 }.Zip((k, varr) => varr[0] + varr[1], true).GetCursor(); //actual = 0; //using (Benchmark.Run("ZipN", count * 2)) //{ // while (zipN.MoveNextAsync()) // { // actual += zipN.CurrentValue; // } //} //Assert.AreEqual(expected, actual); //var zipNOld = new[] { sm1, sm2 }.ZipOld((k, varr) => varr[0] + varr[1]).GetCursor(); //actual = 0; //using (Benchmark.Run("ZipN (old)", count * 2)) //{ // while (zipNOld.MoveNextAsync()) // { // actual += zipNOld.CurrentValue; // } //} //Assert.AreEqual(expected, actual); //zipCursor.Reset(); //actual = 0; //using (Benchmark.Run("Zip MP", count * 2)) //{ // while (zipCursor.MovePrevious()) // { // actual += zipCursor.CurrentValue; // } //} //Assert.AreEqual(expected, actual); //actual = 0; //using (Benchmark.Run("LINQ", count * 2)) //{ // var linq = sm1.Zip(sm2, (l, r) => l.Value + r.Value); // foreach (var d in linq) // { // actual += d; // } //} //Assert.AreEqual(expected, actual); //actual = 0; //using (Benchmark.Run("Deedle", count * 2)) //{ // var sum = ds1 + ds2; // foreach (var v in sum.Values) // ds1.ZipInner(ds2).Values) // { // actual += v; //.Item1 + v.Item2; // } //} //Assert.AreEqual(expected, actual); }
public void CouldMapValuesBenchmarkArithmeticVsMapCursor() { var sm = new SortedMap <int, double>(); var count = 10000000; sm.AddLast(0, 0); for (int i = 2; i < count; i++) { sm.AddLast(i, i); } for (int r = 0; r < 10; r++) { { var sum = 0.0; using (Benchmark.Run("SortedMap", count)) { foreach (var kvp in sm) { sum += kvp.Value; } } Assert.IsTrue(sum > 0); } { var map = new ArithmeticSeries <int, double, MultiplyOp <double>, SortedMapCursor <int, double> >(sm.GetEnumerator(), 2.0); var map2 = map + 2; //new ArithmeticSeries<int, double, MultiplyOp<double>, ArithmeticSeries<int, double, // MultiplyOp<double>, SortedMapCursor<int, double>>>( // map.Initialize, 2.0); var sum = 0.0; using (Benchmark.Run("ArithmeticSeries", count)) { foreach (var kvp in map2) { sum += kvp.Value; } } Assert.IsTrue(sum > 0); } { var c = new Op <int, double, MultiplyOp <double>, SortedMapCursor <int, double> >( sm.GetEnumerator(), 2.0); var c1 = new Op <int, double, AddOp <double>, Op <int, double, MultiplyOp <double>, SortedMapCursor <int, double> > >( c, 2.0); var series = new Series <int, double, Op <int, double, AddOp <double>, Op <int, double, MultiplyOp <double>, SortedMapCursor <int, double> > > >(c1); var sum = 0.0; using (Benchmark.Run("ArithmeticCursor", count)) { foreach (var kvp in series) { sum += kvp.Value; } } Assert.IsTrue(sum > 0); } { var map = new MapValuesSeries <int, double, double, SortedMapCursor <int, double> >(sm.GetEnumerator(), i => Apply(i, 2.0)); var map2 = new MapValuesSeries <int, double, double, MapValuesSeries <int, double, double, SortedMapCursor <int, double> > >(map, i => Apply2(i, 2.0)); var sum = 0.0; using (Benchmark.Run("MapValuesSeries", count)) { foreach (var kvp in map2) { sum += kvp.Value; } } Assert.IsTrue(sum > 0); } { var map = (sm * 2) + 2; var sum = 0.0; using (Benchmark.Run("BaseSeries operator", count)) { foreach (var kvp in map) { sum += kvp.Value; } } Assert.IsTrue(sum > 0); } { var map = sm .Select(x => new KeyValuePair <int, double>(x.Key, x.Value * 2)) .Select(x => new KeyValuePair <int, double>(x.Key, x.Value + 2)); var sum = 0.0; using (Benchmark.Run("LINQ", count)) { foreach (var kvp in map) { sum += kvp.Value; } } Assert.IsTrue(sum > 0); } } Benchmark.Dump(); }
// TODO learn how to use dotMemory for total allocatoins count //[DotMemoryUnit(FailIfRunWithoutSupport = false)] public void MultipleEnumerationDoesntAllocate() { var sm = new SortedMap <int, double>(); var count = 100; sm.AddLast(0, 0); for (int i = 2; i < count; i++) { sm.AddLast(i, i); } for (int r = 0; r < 10; r++) { var map = new ArithmeticSeries <int, double, MultiplyOp <double>, SortedMapCursor <int, double> >( sm.GetEnumerator(), 2.0); var sum = 0.0; var sum1 = 0.0; var sum2 = 0.0; var iterations = 100000; void Run(ref double s) { try { // using it here completely eliminates allocations, an instance is created for // all iterations inside each thread //using (var mapX = map + 2) { for (int i = 0; i < iterations; i++) { // here static caching helps, but not completely eliminates allocations because // two threads compete for a single static slot very often using (var mapX = map + 2) using (var c = (mapX).GetEnumerator()) { //Assert.IsTrue(c.State == CursorState.Initialized); //Assert.IsTrue(c._cursor.State == CursorState.Initialized); var countCheck = 0; while (c.MoveNext()) { s += c.CurrentKey; countCheck++; } if (sm.Count != countCheck) { Console.WriteLine($"Expected {sm.Count} vs actual {countCheck}"); } if (sm.Count != countCheck) { Assert.Fail(); } } } } } catch (Exception ex) { Console.WriteLine(ex.Message + Environment.NewLine + ex); } } var cc = new Op <int, double, MultiplyOp <double>, SortedMapCursor <int, double> >( sm.GetEnumerator(), 2.0); var cc1 = new Op <int, double, AddOp <double>, Op <int, double, MultiplyOp <double>, SortedMapCursor <int, double> > >( cc, 2.0); var series = new Series <int, double, Op <int, double, AddOp <double>, Op <int, double, MultiplyOp <double>, SortedMapCursor <int, double> > > >(cc1); void Run2(ref double s) { try { for (int i = 0; i < iterations; i++) { using (var c = series.GetEnumerator()) { var countCheck = 0; while (c.MoveNext()) { s += c.CurrentKey; countCheck++; } if (sm.Count != countCheck) { Console.WriteLine($"Expected {sm.Count} vs actual {countCheck}"); } if (sm.Count != countCheck) { Assert.Fail(); } } } } catch (Exception ex) { Console.WriteLine(ex.Message + Environment.NewLine + ex); } } using (Benchmark.Run("ArithmeticSeries", count * iterations)) { var t = Task.Run(() => Run(ref sum1)); var t1 = Task.Run(() => Run(ref sum2)); Run(ref sum); t.Wait(); t1.Wait(); //dotMemory.Check(memory => //{ // Assert.That( // memory.GetObjects(where => // where.Type.Is<ArithmeticSeries<int, double, MultiplyOp<double>, SortedMapCursor<int, double>>>()).ObjectsCount, // Is.EqualTo(1) // ); //}); } Assert.IsTrue(sum > 0); Assert.AreEqual(sum, sum1); Assert.AreEqual(sum, sum2); using (Benchmark.Run("ArithmeticCursor", count * iterations)) { var t = Task.Run(() => Run2(ref sum1)); var t1 = Task.Run(() => Run2(ref sum2)); Run2(ref sum); t.Wait(); t1.Wait(); } Assert.IsTrue(sum > 0); Assert.AreEqual(sum, sum1); Assert.AreEqual(sum, sum2); } Benchmark.Dump("Compare multiple allocations and subsequent enumerations of arithmetic series."); }
public void SMADirectAndIndirectSpanOpBenchmark() { Settings.DoAdditionalCorrectnessChecks = false; var count = 1000000; var width = 20; var sm = new SortedMap <int, double>(); sm.Add(0, 0); // make irregular, it's faster but more memory for (int i = 2; i <= count; i++) { sm.Add(i, i); } var directSMA = new SpanOpImpl <int, double, double, MAvgCount <int, double, SortedMapCursor <int, double> >, SortedMapCursor <int, double> >(sm.GetEnumerator(), new MAvgCount <int, double, SortedMapCursor <int, double> >(width, false)).Source; var indirectSma = new SpanOpImpl <int, double, double, SpanOpCount <int, double, double, SortedMapCursor <int, double>, SumAvgOnlineOp <int, double, SortedMapCursor <int, double> > >, SortedMapCursor <int, double> >(sm.GetEnumerator(), new SpanOpCount <int, double, double, SortedMapCursor <int, double>, SumAvgOnlineOp <int, double, SortedMapCursor <int, double> > >(width, false, new SumAvgOnlineOp <int, double, SortedMapCursor <int, double> >())).Source; var indirectSmaCombined = new SpanOpImpl <int, double, double, SpanOp <int, double, double, SortedMapCursor <int, double>, SumAvgOnlineOp <int, double, SortedMapCursor <int, double> > >, SortedMapCursor <int, double> >(sm.GetEnumerator(), new SpanOp <int, double, double, SortedMapCursor <int, double>, SumAvgOnlineOp <int, double, SortedMapCursor <int, double> > >(width, false, new SumAvgOnlineOp <int, double, SortedMapCursor <int, double> >(), sm.comparer)).Source; var extensionSma = sm.SMA(width); var windowSma = sm.Window(width).Map(x => { var sum = 0.0; var c = 0; foreach (var keyValuePair in x) { sum += keyValuePair.Value; c++; } return(sum / c); // x.CursorDefinition.Count TODO }); for (int round = 0; round < 20; round++) { double sum1 = 0.0; using (Benchmark.Run("SMA Direct", count * width)) { foreach (var keyValuePair in directSMA) { sum1 += keyValuePair.Value; } } double sum2 = 0.0; using (Benchmark.Run("SMA Indirect", count * width)) { foreach (var keyValuePair in indirectSma) { sum2 += keyValuePair.Value; } } double sum2_2 = 0.0; using (Benchmark.Run("SMA Indirect Combined", count * width)) { foreach (var keyValuePair in indirectSmaCombined) { sum2_2 += keyValuePair.Value; } } double sum2_3 = 0.0; using (Benchmark.Run("SMA Extension", count * width)) { foreach (var keyValuePair in extensionSma) { sum2_3 += keyValuePair.Value; } } double sum3 = 0.0; using (Benchmark.Run("SMA Window", count * width)) { foreach (var keyValuePair in windowSma) { sum3 += keyValuePair.Value; } } var sumxx = 0.0; using (Benchmark.Run("SortedMap", count)) { foreach (var keyValuePair in sm) { sumxx += keyValuePair.Value; } } Assert.AreEqual(sum1, sum2); Assert.AreEqual(sum1, sum2_2); Assert.AreEqual(sum1, sum2_3); Assert.AreEqual(sum1, sum3); } Benchmark.Dump($"The window width is {width}. SMA MOPS are calculated as a number of calculated values multiplied by width, " + $"which is equivalent to the total number of cursor moves for Window case. SortedMap line is for reference - it is the " + $"speed of raw iteration over SM without Windows overheads."); }
public void CouldUseWindowCursor() { SortedMap <int, double> sm = new SortedMap <int, double>(); var count = 100; for (int i = 0; i < count; i++) { sm.Add(i, i); } var window = sm.Window(10); // NB no type annotations needed to get the same result // Even though `.Source` saves a great deal of typing, manual construction is still a dealbreaker // Extension methods are smart and keep all types info without requiring any type annotations var windowLong = new Window <int, double, SortedMapCursor <int, double> >(sm.GetEnumerator(), 10).Source; foreach (var pair in window) { var expected = ((2 * pair.Key - 10 + 1) / 2.0) * 10; Assert.AreEqual(expected, pair.Value.Values.Sum()); Console.WriteLine(pair.Value.Values.Sum()); //Console.WriteLine(keyValuePair.Value.Aggregate("", (st,kvp) => st + "," + kvp.Value)); } }
public void EnumerateScmSpeed() { const int count = 10_000_000; var sl = new SortedList <int, int>(); var sm = new SortedMap <int, int>(); var scm = new SortedChunkedMap <int, int>(); for (int i = 0; i < count; i++) { if (i % 1000 != 0) { sl.Add(i, i); sm.Add(i, i); //scm.Add(i, i); } } sm.Complete(); // scm.Complete(); for (int r = 0; r < 20; r++) { //var sum1 = 0L; //using (Benchmark.Run("SL", count)) //{ // using (var c = sl.GetEnumerator()) // { // while (c.MoveNext()) // { // sum1 += c.Current.Value; // } // } //} //Assert.True(sum1 > 0); var sum2 = 0L; using (Benchmark.Run("SM Current.Value", count)) { using (var c = sm.GetEnumerator()) { while (c.MoveNext()) { sum2 += c.Current.Value; } } } //Assert.AreEqual(sum1, sum2); var sum3 = 0L; using (Benchmark.Run("SM CurrentValue", count)) { using (var c = sm.GetEnumerator()) { while (c.MoveNext()) { sum3 += c.CurrentValue; } } } //Assert.AreEqual(sum1, sum3); //var sum4 = 0L; //using (Benchmark.Run("SCM Current.Value", count)) //{ // using (var c = scm.GetEnumerator()) // { // while (c.MoveNext()) // { // sum4 += c.Current.Value; // } // } //} //Assert.AreEqual(sum1, sum4); //var sum5 = 0L; //using (Benchmark.Run("SCM CurrentValue", count)) //{ // using (var c = scm.GetEnumerator()) // { // while (c.MoveNext()) // { // sum5 += c.CurrentValue; // } // } //} //Assert.AreEqual(sum1, sum5); } Benchmark.Dump(); }
public void CouldMapValues() { var sm = new SortedMap <int, double> { { 1, 1 } }; var map = new ArithmeticSeries <int, double, MultiplyOp <double>, SortedMapCursor <int, double> >((sm.GetEnumerator()), 2); var map1 = new ArithmeticSeries <int, double, MultiplyOp <double>, ArithmeticSeries <int, double, MultiplyOp <double>, SortedMapCursor <int, double> > >(map, 2); Assert.AreEqual(2, map.First.Value); Assert.AreEqual(4, map1.First.Value); }