//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 GISModel.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; using System.Text; namespace BotSharp.Models { /// /// A maximum entropy model which has been trained using the Generalized /// Iterative Scaling procedure. /// /// /// Tom Morton and Jason Baldridge /// /// /// Richard J. Northedge /// /// /// based on GISModel.java, $Revision: 1.13 $, $Date: 2004/06/11 20:51:44 $ /// public sealed class GisModel : IMaximumEntropyModel { private readonly IO.IGisModelReader _reader; private readonly string[] _outcomeNames; private readonly int _outcomeCount; private readonly double _initialProbability; private readonly double _correctionConstantInverse; private readonly int[] _featureCounts; /// /// Constructor for a maximum entropy model trained using the /// Generalized Iterative Scaling procedure. /// /// /// A reader providing the data for the model. /// public GisModel(IO.IGisModelReader reader) { this._reader = reader; _outcomeNames = reader.GetOutcomeLabels(); CorrectionConstant = reader.CorrectionConstant; CorrectionParameter = reader.CorrectionParameter; _outcomeCount = _outcomeNames.Length; _initialProbability = Math.Log(1.0 / _outcomeCount); _correctionConstantInverse = 1.0 / CorrectionConstant; _featureCounts = new int[_outcomeCount]; } // implementation of IMaxentModel ------- /// /// Returns the number of outcomes for this model. /// /// /// The number of outcomes. /// public int OutcomeCount { get { return (_outcomeCount); } } /// /// Evaluates a context. /// /// /// A list of string names of the contextual predicates /// which are to be evaluated together. /// /// /// An array of the probabilities for each of the different /// outcomes, all of which sum to 1. /// public double[] Evaluate(string[] context) { return Evaluate(context, new double[_outcomeCount]); } /// /// Use this model to evaluate a context and return an array of the /// likelihood of each outcome given that context. /// /// /// The names of the predicates which have been observed at /// the present decision point. /// /// /// This is where the distribution is stored. /// /// /// The normalized probabilities for the outcomes given the /// context. The indexes of the double[] are the outcome /// ids, and the actual string representation of the /// outcomes can be obtained from the method /// GetOutcome(int outcomeIndex). /// public double[] Evaluate(string[] context, double[] outcomeSums) { for (int outcomeIndex = 0; outcomeIndex < _outcomeCount; outcomeIndex++) { outcomeSums[outcomeIndex] = _initialProbability; _featureCounts[outcomeIndex] = 0; } foreach (string con in context) { _reader.GetPredicateData(con, _featureCounts, outcomeSums); } double normal = 0.0; for (int outcomeIndex = 0;outcomeIndex < _outcomeCount; outcomeIndex++) { outcomeSums[outcomeIndex] = Math.Exp((outcomeSums[outcomeIndex] * _correctionConstantInverse) + ((1.0 - (_featureCounts[outcomeIndex] / CorrectionConstant)) * CorrectionParameter)); normal += outcomeSums[outcomeIndex]; } for (int outcomeIndex = 0; outcomeIndex < _outcomeCount;outcomeIndex++) { outcomeSums[outcomeIndex] /= normal; } return outcomeSums; } /// /// Return the name of the outcome corresponding to the highest likelihood /// in the parameter outcomes. /// /// /// A double[] as returned by the Evaluate(string[] context) /// method. /// /// /// The name of the most likely outcome. /// public string GetBestOutcome(double[] outcomes) { int bestOutcomeIndex = 0; for (int currentOutcome = 1; currentOutcome < outcomes.Length; currentOutcome++) if (outcomes[currentOutcome] > outcomes[bestOutcomeIndex]) { bestOutcomeIndex = currentOutcome; } return _outcomeNames[bestOutcomeIndex]; } /// /// Return a string matching all the outcome names with all the /// probabilities produced by the Evaluate(string[] context) /// method. /// /// /// A double[] as returned by the /// eval(string[] context) /// method. /// /// /// string containing outcome names paired with the normalized /// probability (contained in the double[] outcomes) /// for each one. /// public string GetAllOutcomes(double[] outcomes) { if (outcomes.Length != _outcomeNames.Length) { throw new ArgumentException("The double array sent as a parameter to GisModel.GetAllOutcomes() must not have been produced by this model."); } else { var outcomeInfo = new StringBuilder(outcomes.Length * 2); outcomeInfo.Append(_outcomeNames[0]).Append("[").Append(outcomes[0].ToString("0.0000", System.Globalization.CultureInfo.CurrentCulture)).Append("]"); for (int currentOutcome = 1; currentOutcome < outcomes.Length; currentOutcome++) { outcomeInfo.Append(" ").Append(_outcomeNames[currentOutcome]).Append("[").Append(outcomes[currentOutcome].ToString("0.0000", System.Globalization.CultureInfo.CurrentCulture)).Append("]"); } return outcomeInfo.ToString(); } } /// /// Return the name of an outcome corresponding to an integer ID value. /// /// /// An outcome ID. /// /// /// The name of the outcome associated with that ID. /// public string GetOutcomeName(int outcomeIndex) { return _outcomeNames[outcomeIndex]; } /// /// Gets the index associated with the string name of the given outcome. /// /// /// the string name of the outcome for which the /// index is desired /// /// /// the index if the given outcome label exists for this /// model, -1 if it does not. /// public int GetOutcomeIndex(string outcome) { for (int iCurrentOutcomeName = 0; iCurrentOutcomeName < _outcomeNames.Length; iCurrentOutcomeName++) { if (_outcomeNames[iCurrentOutcomeName] == outcome) { return iCurrentOutcomeName; } } return - 1; } /// /// Provides the predicates data structure which is part of the encoding of the maxent model /// information. This method will usually only be needed by /// GisModelWriters. /// /// /// Dictionary containing PatternedPredicate objects. /// public Dictionary GetPredicates() { return _reader.GetPredicates(); } /// /// Provides the list of outcome patterns used by the predicates. This method will usually /// only be needed by GisModelWriters. /// /// /// Array of outcome patterns. /// public int[][] GetOutcomePatterns() { return _reader.GetOutcomePatterns(); } /// /// Provides the outcome names data structure which is part of the encoding of the maxent model /// information. This method will usually only be needed by /// GisModelWriters. /// /// /// Array containing the outcome names. /// public string[] GetOutcomeNames() { return _outcomeNames; } /// /// Provides the model's correction constant. /// This property will usually only be needed by GisModelWriters. /// public int CorrectionConstant { get; private set; } /// /// Provides the model's correction parameter. /// This property will usually only be needed by GisModelWriters. /// public double CorrectionParameter { get; private set; } } }