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 Stat2Cursor(TCursor cursor, TKey width, Lookup lookup) : this() { var op = new Stat2OnlineOp <TKey, TValue, TCursor>(); var spanOp = new SpanOp <TKey, TValue, Stat2 <TKey>, TCursor, Stat2OnlineOp <TKey, TValue, TCursor> >(width, lookup, op, cursor.Comparer); _cursor = new SpanOpImpl <TKey, TValue, Stat2 <TKey>, SpanOp <TKey, TValue, Stat2 <TKey>, TCursor, Stat2OnlineOp <TKey, TValue, TCursor> >, TCursor >(cursor, spanOp); }
public bool TryGetValue(TKey key, out Stat2 <TKey> value) { if (_lookUpCursor.Equals(default(TCursor))) { _lookUpCursor = _cursor.Clone(); } if (_lookUpCursor.MoveAt(key, Lookup.EQ)) { value = _lookUpCursor.CurrentValue; return(true); } value = default; return(false); }
public bool TryGetValue(TKey key, out Series <TKey, TValue, Range <TKey, TValue, TCursor> > value) { if (_lookUpCursor.Equals(default(TCursor))) { _lookUpCursor = _cursor.Clone(); } if (_lookUpCursor.MoveAt(key, Lookup.EQ)) { value = _lookUpCursor.CurrentValue.Source; return(true); } value = default; return(false); }
internal Window(TCursor cursor, TKey width, Lookup lookup) : this() { if (cursor.IsIndexed) { throw new NotSupportedException("Window is not supported for indexed series, only for sorted ones."); } var op = new WindowOnlineOp <TKey, TValue, TCursor>(); var spanOp = new SpanOp <TKey, TValue, Range <TKey, TValue, TCursor>, TCursor, WindowOnlineOp <TKey, TValue, TCursor> >(width, lookup, op, cursor.Comparer); _cursor = new SpanOpImpl <TKey, TValue, Range <TKey, TValue, TCursor>, SpanOp <TKey, TValue, Range <TKey, TValue, TCursor>, TCursor, WindowOnlineOp <TKey, TValue, TCursor> >, TCursor >(cursor, spanOp); }
internal Stat2Cursor(TCursor cursor, int width = 1, bool allowIncomplete = false) : this() { if (width <= 0) { throw new ArgumentOutOfRangeException(nameof(width)); } var op = new Stat2OnlineOp <TKey, TValue, TCursor>(); var spanOp = new SpanOp <TKey, TValue, Stat2 <TKey>, TCursor, Stat2OnlineOp <TKey, TValue, TCursor> >(width, allowIncomplete, op, cursor.Comparer); _cursor = new SpanOpImpl <TKey, TValue, Stat2 <TKey>, SpanOp <TKey, TValue, Stat2 <TKey>, TCursor, Stat2OnlineOp <TKey, TValue, TCursor> >, TCursor >(cursor, spanOp); }
internal Window(TCursor cursor, int count, bool allowIncomplete = false) : this() { if (cursor.IsIndexed) { throw new NotSupportedException("Window is not supported for indexed series, only for sorted ones."); } if (count <= 0) { throw new ArgumentOutOfRangeException(nameof(count)); } var op = new WindowOnlineOp <TKey, TValue, TCursor>(); var spanOp = new SpanOp <TKey, TValue, Range <TKey, TValue, TCursor>, TCursor, WindowOnlineOp <TKey, TValue, TCursor> >(count, allowIncomplete, op, cursor.Comparer); _cursor = new SpanOpImpl <TKey, TValue, Range <TKey, TValue, TCursor>, SpanOp <TKey, TValue, Range <TKey, TValue, TCursor>, TCursor, WindowOnlineOp <TKey, TValue, TCursor> >, TCursor >(cursor, spanOp); }
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 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 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 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}"); } } }