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);
        }
Exemplo n.º 2
0
        //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);
        }