protected override GroupByState <V> UpdateState(K key, GroupByState <V> state, int updateRootIndex) { if (state.elements.Array == null) { state.elements = new ResizeableSubArray <Weighted <V> >(0); } updateAccumulator.Clear(); resultAccumulator.Clear(); // first determine and subtract the previous outputs groupContent.Clear(); for (int i = 0; i < state.elements.Count; i++) { // set the weight associated with this record updateAccumulator[state.elements.Array[i].record] = state.elements.Array[i].weight; // add the element to the materialized list groupContent.Add(state.elements.Array[i].record); var weight = (state.elements.Array[i].weight - (i == state.elements.Count - 1 ? 0 : state.elements.Array[i + 1].weight)) / 2; if (weight != 0) { var result = resultSelector(key, groupContent); if (!resultAccumulator.ContainsKey(result)) { resultAccumulator.Add(result, 0); } resultAccumulator[result] -= weight; } } // update the accumulation based on the updates we see. for (int index = updateRootIndex; index >= 0; index = updateChain[index].previous) { var selected = selector(updateChain[index].update.record); if (!updateAccumulator.ContainsKey(selected)) { updateAccumulator.Add(selected, 0); } updateAccumulator[selected] += updateChain[index].update.weight; } // load the new accumulation into state state.elements.Clear(); foreach (var pair in updateAccumulator.OrderByDescending(x => x.Value)) { if (pair.Value > 0) { state.elements.Add(new Weighted <V>(pair.Key, pair.Value)); } if (pair.Value < 0) { Console.Error.WriteLine("Negative accumulation in GroupBy; probably a bug somewhere"); } } // second determine and add the current outputs groupContent.Clear(); for (int i = 0; i < state.elements.Count; i++) { // add the element to the materialized list groupContent.Add(state.elements.Array[i].record); var weight = (state.elements.Array[i].weight - (i == state.elements.Count - 1 ? 0 : state.elements.Array[i + 1].weight)) / 2; if (weight != 0) { var result = resultSelector(key, groupContent); if (!resultAccumulator.ContainsKey(result)) { resultAccumulator.Add(result, 0); } // subtract half the difference to the next weight, with zero for the last weight resultAccumulator[result] += weight; } } foreach (var pair in resultAccumulator) { if (pair.Value != 0) { Send(new Weighted <R>(pair.Key, pair.Value)); } } return(state); }
//protected override S UpdateState(K key, S state, int updateRootIndex1, int updateRootIndex2) { return state; } #if false protected override JoinState <V1, V2> UpdateState(K key, JoinState <V1, V2> state, int updateRootIndex1, int updateRootIndex2) { if (state.elements1.Array == null) { state.elements1 = new ResizeableSubArray <Weighted <V1> >(0); } if (state.elements2.Array == null) { state.elements2 = new ResizeableSubArray <Weighted <V2> >(0); } var elements1 = state.elements1.Array; // makes things look a bit cleaner var elements2 = state.elements2.Array; // makes things look a bit cleaner updates1.Clear(); for (int index = updateRootIndex1; index >= 0; index = updateChain1[index].previous) { updates1.Add(updateChain1[index].update); } updates2.Clear(); for (int index = updateRootIndex2; index >= 0; index = updateChain2[index].previous) { updates2.Add(updateChain2[index].update); } //var updates1 = update.inputs1.Array; // makes things look a bit cleaner //var updates2 = update.inputs2.Array; // makes things look a bit cleaner // these sums assume that db weights do not go negative Int64 oldNormalization = 0; for (int i = 0; i < state.elements1.Count; i++) { oldNormalization += elements1[i].weight; } for (int i = 0; i < state.elements2.Count; i++) { oldNormalization += elements2[i].weight; } // compute new normalization from the old var newNormalization = oldNormalization; for (int i = 0; i < updates1.Count; i++) { newNormalization += updates1.Array[i].weight; } for (int i = 0; i < updates2.Count; i++) { newNormalization += updates2.Array[i].weight; } if (oldNormalization != newNormalization) { for (int i = 0; i < state.elements1.Count; i++) { for (int j = 0; j < state.elements2.Count; j++) { var product = (((double)elements1[i].weight)) * (((double)elements2[j].weight)); Int64 result = 0; if (oldNormalization != 0) { result -= (Int64)(product / oldNormalization); } if (newNormalization != 0) { result += (Int64)(product / newNormalization); } if (result != 0) { Send(new Weighted <R>(resultSelector(key, elements1[i].record, elements2[j].record), result)); } if (result < -(1L << 58)) { Console.WriteLine("!!!!"); } } } } if (newNormalization != 0) { // var newReciprocal = 1.0 / newNormalization; // match updates1 against elements2 for (int i = 0; i < updates1.Count; i++) { if (updates1.Array[i].weight != 0) { for (int j = 0; j < state.elements2.Count; j++) { if (elements2[j].weight != 0) { var product = (((double)updates1.Array[i].weight)) * (((double)elements2[j].weight)); var result = (Int64)(product / newNormalization); if (result != 0) { Send(new Weighted <R>(resultSelector(key, updates1.Array[i].record, elements2[j].record), result)); } if (result < -(1L << 58)) { Console.WriteLine("!!!!"); } } } } } // match elements1 against updates2 for (int i = 0; i < updates2.Count; i++) { if (updates2.Array[i].weight != 0) { for (int j = 0; j < state.elements1.Count; j++) { if (elements1[j].weight != 0) { var product = (((double)updates2.Array[i].weight)) * (((double)elements1[j].weight)); var result = (Int64)(product / newNormalization); if (result != 0) { Send(new Weighted <R>(resultSelector(key, elements1[j].record, updates2.Array[i].record), result)); } if (result < -(1L << 58)) { Console.WriteLine("!!!!"); } } } } } // match updates1 against updates2 for (int i = 0; i < updates1.Count; i++) { if (updates1.Array[i].weight != 0) { for (int j = 0; j < updates2.Count; j++) { if (updates2.Array[j].weight != 0) { var product = (((double)updates1.Array[i].weight)) * (((double)updates2.Array[j].weight)); var result = (Int64)(product / newNormalization); if (result != 0) { Send(new Weighted <R>(resultSelector(key, updates1.Array[i].record, updates2.Array[j].record), result)); } if (result < -(1L << 58)) { Console.WriteLine("!!!!"); } } } } } } #region Folding updates1 into elements1 for (int i = 0; i < updates1.Count; i++) { if (!input1Accumulator.ContainsKey(updates1.Array[i].record)) { input1Accumulator.Add(updates1.Array[i].record, updates1.Array[i].weight); } else { input1Accumulator[updates1.Array[i].record] += updates1.Array[i].weight; } } for (int i = 0; i < state.elements1.Count; i++) { if (input1Accumulator.ContainsKey(elements1[i].record)) { elements1[i].weight += input1Accumulator[elements1[i].record]; input1Accumulator.Remove(elements1[i].record); } if (elements1[i].weight == 0) { state.elements1.Count--; state.elements1.Array[i] = state.elements1.Array[state.elements1.Count]; i--; } } if (state.elements1.Count == 0) { state.elements1.Clear(); } foreach (var entry in input1Accumulator) { state.elements1.Add(new Weighted <V1>(entry.Key, entry.Value)); } input1Accumulator.Clear(); #endregion #region Folding updates2 into elements2 for (int i = 0; i < updates2.Count; i++) { if (!input2Accumulator.ContainsKey(updates2.Array[i].record)) { input2Accumulator.Add(updates2.Array[i].record, updates2.Array[i].weight); } else { input2Accumulator[updates2.Array[i].record] += updates2.Array[i].weight; } } for (int i = 0; i < state.elements2.Count; i++) { if (input2Accumulator.ContainsKey(elements2[i].record)) { elements2[i].weight += input2Accumulator[elements2[i].record]; input2Accumulator.Remove(elements2[i].record); } if (elements2[i].weight == 0) { state.elements2.Count--; state.elements2.Array[i] = state.elements2.Array[state.elements2.Count]; i--; } } if (state.elements2.Count == 0) { state.elements2.Clear(); } foreach (var entry in input2Accumulator) { state.elements2.Add(new Weighted <V2>(entry.Key, entry.Value)); } input2Accumulator.Clear(); #endregion return(state); }