protected internal override IList index(LinkedList <Event> events, IDictionary <string, int?> predicateIndex)
        {
            IDictionary <string, int?> omap = new Dictionary <string, int?>();

            int numEvents    = events.Count;
            int outcomeCount = 0;
            IList <ComparableEvent> eventsToCompare = new List <ComparableEvent>(numEvents);
            IList <int?>            indexedContext  = new List <int?>();

            for (int eventIndex = 0; eventIndex < numEvents; eventIndex++)
            {
                var   evNode = events.First;
                Event ev     = evNode.Value;
                events.RemoveFirst();
                string[]        econtext = ev.Context;
                ComparableEvent ce;

                int    ocID;
                string oc = ev.Outcome;

                if (omap.ContainsKey(oc))
                {
                    ocID = omap[oc].GetValueOrDefault();
                }
                else
                {
                    ocID     = outcomeCount++;
                    omap[oc] = ocID;
                }

                foreach (string pred in econtext)
                {
                    if (predicateIndex.ContainsKey(pred))
                    {
                        indexedContext.Add(predicateIndex[pred]);
                    }
                }

                //drop events with no active features
                if (indexedContext.Count > 0)
                {
                    int[] cons = new int[indexedContext.Count];
                    for (int ci = 0; ci < cons.Length; ci++)
                    {
                        cons[ci] = indexedContext[ci].GetValueOrDefault();
                    }
                    ce = new ComparableEvent(ocID, cons, ev.Values);
                    eventsToCompare.Add(ce);
                }
                else
                {
                    Console.Error.WriteLine("Dropped event " + ev.Outcome + ":" + ev.Context.ToList());
                }
                //    recycle the TIntArrayList
                indexedContext.Clear();
            }
            outcomeLabels = toIndexedStringArray(omap);
            predLabels    = toIndexedStringArray(predicateIndex);
            return(eventsToCompare as IList);
        }
        /// <summary>
        /// Sorts and uniques the array of comparable events and return the number of unique events.
        /// This method will alter the eventsToCompare array -- it does an in place
        /// sort, followed by an in place edit to remove duplicates.
        /// </summary>
        /// <param name="eventsToCompare"> a <code>ComparableEvent[]</code> value </param>
        /// <returns> The number of unique events in the specified list.
        /// @since maxent 1.2.6 </returns>
        protected internal virtual int sortAndMerge(List <ComparableEvent> eventsToCompare, bool sort)
        {
            int numUniqueEvents = 1;

            numEvents = eventsToCompare.Count;
            if (sort)
            {
                eventsToCompare.Sort();
                if (numEvents <= 1)
                {
                    return(numUniqueEvents); // nothing to do; edge case (see assertion)
                }

                ComparableEvent ce = eventsToCompare[0];
                for (int i = 1; i < numEvents; i++)
                {
                    ComparableEvent ce2 = eventsToCompare[i];

                    if (ce.CompareTo(ce2) == 0)
                    {
                        ce.seen++;                 // increment the seen count
                        eventsToCompare[i] = null; // kill the duplicate
                    }
                    else
                    {
                        ce = ce2;          // a new champion emerges...
                        numUniqueEvents++; // increment the # of unique events
                    }
                }
            }
            else
            {
                numUniqueEvents = eventsToCompare.Count;
            }
            if (sort)
            {
                Console.WriteLine("done. Reduced " + numEvents + " events to " + numUniqueEvents + ".");
            }

            contexts           = new int[numUniqueEvents][];
            outcomeList        = new int[numUniqueEvents];
            numTimesEventsSeen = new int[numUniqueEvents];

            for (int i = 0, j = 0; i < numEvents; i++)
            {
                ComparableEvent evt = eventsToCompare[i];
                if (null == evt)
                {
                    continue; // this was a dupe, skip over it.
                }
                numTimesEventsSeen[j] = evt.seen;
                outcomeList[j]        = evt.outcome;
                contexts[j]           = evt.predIndexes;
                ++j;
            }
            return(numUniqueEvents);
        }
        private List <ComparableEvent> index(int numEvents, EventStream es, IDictionary <string, int?> predicateIndex)
        {
            IDictionary <string, int?> omap = new Dictionary <string, int?>();
            int outcomeCount = 0;
            List <ComparableEvent> eventsToCompare = new List <ComparableEvent>(numEvents);
            IList <int?>           indexedContext  = new List <int?>();

            while (es.hasNext())
            {
                Event           ev       = es.next();
                string[]        econtext = ev.Context;
                ComparableEvent ce;

                int    ocID;
                string oc = ev.Outcome;

                if (omap.ContainsKey(oc))
                {
                    ocID = omap[oc].GetValueOrDefault();
                }
                else
                {
                    ocID     = outcomeCount++;
                    omap[oc] = ocID;
                }

                foreach (string pred in econtext)
                {
                    if (predicateIndex.ContainsKey(pred))
                    {
                        indexedContext.Add(predicateIndex[pred]);
                    }
                }

                // drop events with no active features
                if (indexedContext.Count > 0)
                {
                    int[] cons = new int[indexedContext.Count];
                    for (int ci = 0; ci < cons.Length; ci++)
                    {
                        cons[ci] = indexedContext[ci].GetValueOrDefault();
                    }
                    ce = new ComparableEvent(ocID, cons);
                    eventsToCompare.Add(ce);
                }
                else
                {
                    Console.Error.WriteLine("Dropped event " + ev.Outcome + ":" + ev.Context.ToList());
                }
                // recycle the TIntArrayList
                indexedContext.Clear();
            }
            outcomeLabels = toIndexedStringArray(omap);
            predLabels    = toIndexedStringArray(predicateIndex);
            return(eventsToCompare);
        }
        protected internal override int sortAndMerge(List <ComparableEvent> eventsToCompare, bool sort)
        {
            int numUniqueEvents = base.sortAndMerge(eventsToCompare, sort);

            values = new float[numUniqueEvents][];
            int numEvents = eventsToCompare.Count;

            for (int i = 0, j = 0; i < numEvents; i++)
            {
                ComparableEvent evt = (ComparableEvent)eventsToCompare[i];
                if (null == evt)
                {
                    continue; // this was a dupe, skip over it.
                }
                values[j++] = evt.values;
            }
            return(numUniqueEvents);
        }