//Copyright (C) 2005 Richard J. Northedge // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. //This file is based on the OnePassDataIndexer.java source file found in the //original java implementation of MaxEnt. That source file contains the following header: // Copyright (C) 2001 Jason Baldridge and Gann Bierner // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. using System; using System.Collections.Generic; namespace BotSharp.Models { /// /// An indexer for maxent model data which handles cutoffs for uncommon /// contextual predicates and provides a unique integer index for each of the /// predicates. The data structures built in the constructor of this class are /// used by the GIS trainer. /// /// /// Jason Baldridge /// /// /// Richard J. Northedge /// /// /// based on OnePassDataIndexer.java, $Revision: 1.1 $, $Date: 2003/12/13 16:41:29 $ /// public class OnePassDataIndexer : AbstractDataIndexer { /// /// One argument constructor for OnePassDataIndexer which calls the two argument /// constructor assuming no cutoff. /// /// /// An ITrainingEventReader which contains the a list of all the Events /// seen in the training data. /// public OnePassDataIndexer(ITrainingEventReader eventReader) : this(eventReader, 0) { } /// /// Two argument constructor for OnePassDataIndexer. /// /// /// An ITrainingEventReader which contains the a list of all the Events /// seen in the training data. /// /// /// The minimum number of times a predicate must have been /// observed in order to be included in the model. /// public OnePassDataIndexer(ITrainingEventReader eventReader, int cutoff) { Dictionary predicateIndex; List events; List eventsToCompare; predicateIndex = new Dictionary(); //NotifyProgress("Indexing events using cutoff of " + cutoff + "\n"); //NotifyProgress("\tComputing event counts... "); events = ComputeEventCounts(eventReader, predicateIndex, cutoff); //NotifyProgress("done. " + events.Count + " events"); //NotifyProgress("\tIndexing... "); eventsToCompare = Index(events, predicateIndex); //NotifyProgress("done."); //NotifyProgress("Sorting and merging oEvents... "); SortAndMerge(eventsToCompare); //NotifyProgress("Done indexing."); } /// /// Reads events from eventReader into a List<TrainingEvent>. The /// predicates associated with each event are counted and any which /// occur at least cutoff times are added to the /// predicatesInOut dictionary along with a unique integer index. /// /// /// an ITrainingEventReader value /// /// /// a Dictionary value /// /// /// an int value /// /// /// an List of TrainingEvents value /// private List ComputeEventCounts(ITrainingEventReader eventReader, Dictionary predicatesInOut, int cutoff) { var counter = new Dictionary(); var events = new List(); int predicateIndex = 0; while (eventReader.HasNext()) { TrainingEvent trainingEvent = eventReader.ReadNextEvent(); events.Add(trainingEvent); string[] eventContext = trainingEvent.Context; for (int currentEventContext = 0; currentEventContext < eventContext.Length; currentEventContext++) { if (!predicatesInOut.ContainsKey(eventContext[currentEventContext])) { if (counter.ContainsKey(eventContext[currentEventContext])) { counter[eventContext[currentEventContext]]++; } else { counter.Add(eventContext[currentEventContext], 1); } if (counter[eventContext[currentEventContext]] >= cutoff) { predicatesInOut.Add(eventContext[currentEventContext], predicateIndex++); counter.Remove(eventContext[currentEventContext]); } } } } return events; } private List Index(List events, Dictionary predicateIndex) { var map = new Dictionary(); int eventCount = events.Count; int outcomeCount = 0; var eventsToCompare = new List(eventCount); var indexedContext = new List(); for (int eventIndex = 0; eventIndex < eventCount; eventIndex++) { TrainingEvent currentTrainingEvent = events[eventIndex]; string[] eventContext = currentTrainingEvent.Context; ComparableEvent comparableEvent; int outcomeIndex; string outcome = currentTrainingEvent.Outcome; if (map.ContainsKey(outcome)) { outcomeIndex = map[outcome]; } else { outcomeIndex = outcomeCount++; map.Add(outcome, outcomeIndex); } for (int currentEventContext = 0; currentEventContext < eventContext.Length; currentEventContext++) { string predicate = eventContext[currentEventContext]; if (predicateIndex.ContainsKey(predicate)) { indexedContext.Add(predicateIndex[predicate]); } } // drop events with no active features if (indexedContext.Count > 0) { comparableEvent = new ComparableEvent(outcomeIndex, indexedContext.ToArray()); eventsToCompare.Add(comparableEvent); } else { //"Dropped event " + oEvent.Outcome + ":" + oEvent.Context); } // recycle the list indexedContext.Clear(); } SetOutcomeLabels(ToIndexedStringArray(map)); SetPredicateLabels(ToIndexedStringArray(predicateIndex)); return eventsToCompare; } } }