add information entropy

This commit is contained in:
Oceania2018 2018-07-28 13:01:22 -05:00
parent 535854df1f
commit 6f1ea96289
40 changed files with 4715 additions and 14 deletions

View file

@ -8,4 +8,10 @@
<Folder Include="Fasttext\" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Data.Sqlite">
<HintPath>..\..\..\..\..\..\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.data.sqlite.core\2.1.0\lib\netstandard2.0\Microsoft.Data.Sqlite.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View file

@ -0,0 +1,230 @@
// 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 AbstractDataIndexer.java source file found in the
//original java implementation of MaxEnt.
using System;
using System.Collections.Generic;
namespace BotSharp.MachineLearning
{
/// <summary>
/// Abstract base for DataIndexer implementations.
/// </summary>
/// <author>
/// Tom Morton
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
public abstract class AbstractDataIndexer : ITrainingDataIndexer
{
private int[][] mContexts;
private int[] mOutcomeList;
private int[] mNumTimesEventsSeen;
private string[] mPredicateLabels;
private string[] mOutcomeLabels;
/// <summary>
/// Gets an array of context data calculated from the training data.
/// </summary>
/// <returns>
/// Array of integer arrays, each containing the context data for an event.
/// </returns>
public virtual int[][] GetContexts()
{
return mContexts;
}
/// <summary>
/// Sets the array of context data calculated from the training data.
/// </summary>
/// <param name="newContexts">
/// Array of integer arrays, each containing the context data for an event.
/// </param>
protected internal void SetContexts(int[][] newContexts)
{
mContexts = newContexts;
}
/// <summary>
/// Gets an array indicating how many times each event is seen.
/// </summary>
/// <returns>
/// Integer array with event frequencies.
/// </returns>
public virtual int[] GetNumTimesEventsSeen()
{
return mNumTimesEventsSeen;
}
/// <summary>
/// Sets an array indicating how many times each event is seen.
/// </summary>
/// <param name="newNumTimesEventsSeen">
/// Integer array with event frequencies.
/// </param>
protected internal void SetNumTimesEventsSeen(int[] newNumTimesEventsSeen)
{
mNumTimesEventsSeen = newNumTimesEventsSeen;
}
/// <summary>
/// Gets an outcome list.
/// </summary>
/// <returns>
/// Integer array of outcomes.
/// </returns>
public virtual int[] GetOutcomeList()
{
return mOutcomeList;
}
/// <summary>
/// Sets an outcome list.
/// </summary>
/// <param name="newOutcomeList">
/// Integer array of outcomes.
/// </param>
protected internal void SetOutcomeList(int[] newOutcomeList)
{
mOutcomeList = newOutcomeList;
}
/// <summary>
/// Gets an array of predicate labels.
/// </summary>
/// <returns>
/// Array of predicate labels.
/// </returns>
public virtual string[] GetPredicateLabels()
{
return mPredicateLabels;
}
/// <summary>
/// Sets an array of predicate labels.
/// </summary>
/// <param name="newPredicateLabels">
/// Array of predicate labels.
/// </param>
protected internal void SetPredicateLabels(string[] newPredicateLabels)
{
mPredicateLabels = newPredicateLabels;
}
/// <summary>
/// Gets an array of outcome labels.
/// </summary>
/// <returns>
/// Array of outcome labels.
/// </returns>
public virtual string[] GetOutcomeLabels()
{
return mOutcomeLabels;
}
/// <summary>
/// Sets an array of outcome labels.
/// </summary>
/// <param name="newOutcomeLabels">
/// Array of outcome labels.
/// </param>
protected internal void SetOutcomeLabels(string[] newOutcomeLabels)
{
mOutcomeLabels = newOutcomeLabels;
}
/// <summary>
/// Sorts and uniques the array of comparable 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 List of <code>ComparableEvent</code> values
/// </param>
protected internal virtual void SortAndMerge(List<ComparableEvent> eventsToCompare)
{
eventsToCompare.Sort();
int eventCount = eventsToCompare.Count;
int uniqueEventCount = 1; // assertion: eventsToCompare.length >= 1
if (eventCount <= 1)
{
return; // nothing to do; edge case (see assertion)
}
ComparableEvent comparableEvent = eventsToCompare[0];
for (int currentEvent = 1; currentEvent < eventCount; currentEvent++)
{
ComparableEvent eventToCompare = eventsToCompare[currentEvent];
if (comparableEvent.Equals(eventToCompare))
{
comparableEvent.SeenCount++; // increment the seen count
eventsToCompare[currentEvent] = null; // kill the duplicate
}
else
{
comparableEvent = eventToCompare; // a new champion emerges...
uniqueEventCount++; // increment the # of unique events
}
}
//NotifyProgress("done. Reduced " + eventCount + " events to " + uniqueEventCount + ".");
mContexts = new int[uniqueEventCount][];
mOutcomeList = new int[uniqueEventCount];
mNumTimesEventsSeen = new int[uniqueEventCount];
for (int currentEvent = 0, currentStoredEvent = 0; currentEvent < eventCount; currentEvent++)
{
ComparableEvent eventToStore = eventsToCompare[currentEvent];
if (null == eventToStore)
{
continue; // this was a dupe, skip over it.
}
mNumTimesEventsSeen[currentStoredEvent] = eventToStore.SeenCount;
mOutcomeList[currentStoredEvent] = eventToStore.Outcome;
mContexts[currentStoredEvent] = eventToStore.GetPredicateIndexes();
++currentStoredEvent;
}
}
/// <summary>
/// Utility method for creating a string[] array from a dictionary whose
/// keys are labels (strings) to be stored in the array and whose
/// values are the indices (integers) at which the corresponding
/// labels should be inserted.
/// </summary>
/// <param name="labelToIndexMap">
/// a <code>Dictionary</code> value
/// </param>
/// <returns>
/// a <code>string[]</code> value
/// </returns>
protected internal static string[] ToIndexedStringArray(Dictionary<string, int> labelToIndexMap)
{
string[] indexedArray = new string[labelToIndexMap.Count];
int[] indices = new int[labelToIndexMap.Count];
labelToIndexMap.Keys.CopyTo(indexedArray, 0);
labelToIndexMap.Values.CopyTo(indices, 0);
Array.Sort(indices, indexedArray);
return indexedArray;
}
}
}

View file

@ -0,0 +1,70 @@
//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 BasicContextGenerator.java source file found in the
//original java implementation of MaxEnt. That source file contains the following header:
// Copyright (C) 2001 Jason Baldridge
//
// 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.
using System;
namespace BotSharp.MachineLearning
{
/// <summary>
/// Generate contexts for maxent decisions, assuming that the input
/// given to the GetContext() method is a string containing contextual
/// predicates separated by spaces, e.g:
/// <p>
/// cp_1 cp_2 ... cp_n
/// </p>
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>based on BasicContextGenerator.java, $Revision: 1.2 $, $Date: 2002/04/30 08:48:35 $
/// </version>
public class BasicContextGenerator : IContextGenerator<string>
{
/// <summary>
/// Builds up the list of contextual predicates given a string.
/// </summary>
/// <param name="input">
/// string with contextual predicates separated by spaces.
/// </param>
/// <returns>string array of contextual predicates.</returns>
public virtual string[] GetContext(string input)
{
return input.Split(' ');
}
}
}

View file

@ -0,0 +1,125 @@
//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 BasicEventStream.java source file found in the
//original java implementation of MaxEnt. That source file contains the following header:
// Copyright (C) 2001 Jason Baldridge
//
// 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.
using System;
namespace BotSharp.MachineLearning
{
/// <summary>
/// An object which can deliver a stream of training events assuming
/// that each event is represented as a space separated list containing
/// all the contextual predicates, with the last item being the
/// outcome, e.g.:
///
/// <p> cp_1 cp_2 ... cp_n outcome</p>
/// </summary>
public class BasicEventReader : ITrainingEventReader
{
private IContextGenerator<string> mContext;
private ITrainingDataReader<string> mDataReader;
private TrainingEvent mNextEvent;
/// <summary>
/// Constructor sets up the training event reader based on a stream of training data.
/// </summary>
/// <param name="dataReader">
/// Stream of training data.
/// </param>
public BasicEventReader(ITrainingDataReader<string> dataReader)
{
mContext = new BasicContextGenerator();
mDataReader = dataReader;
if (mDataReader.HasNext())
{
mNextEvent = CreateEvent(mDataReader.NextToken());
}
}
/// <summary>
/// Returns the next Event object held in this EventReader. Each call to ReadNextEvent advances the EventReader.
/// </summary>
/// <returns>
/// the Event object which is next in this EventReader
/// </returns>
public virtual TrainingEvent ReadNextEvent()
{
while (mNextEvent == null && mDataReader.HasNext())
{
mNextEvent = CreateEvent(mDataReader.NextToken());
}
TrainingEvent currentEvent = mNextEvent;
if (mDataReader.HasNext())
{
mNextEvent = CreateEvent(mDataReader.NextToken());
}
else
{
mNextEvent = null;
}
return currentEvent;
}
/// <summary>
/// Test whether there are any Events remaining in this EventReader.
/// </summary>
/// <returns>
/// true if this EventReader has more Events
/// </returns>
public virtual bool HasNext()
{
while (mNextEvent == null && mDataReader.HasNext())
{
mNextEvent = CreateEvent(mDataReader.NextToken());
}
return mNextEvent != null;
}
private TrainingEvent CreateEvent(string observation)
{
int lastSpace = observation.LastIndexOf((char)' ');
if (lastSpace == -1)
{
return null;
}
else
{
return new TrainingEvent(observation.Substring(lastSpace + 1), mContext.GetContext(observation.Substring(0, (lastSpace) - (0))));
}
}
}
}

View file

@ -0,0 +1,220 @@
//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 ComparableEvent.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.Text;
namespace BotSharp.MachineLearning
{
/// <summary>
/// A Maximum Entropy event representation which we can use to sort based on the
/// predicates indexes contained in the events.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on ComparableEvent.java, $Revision: 1.2 $, $Date: 2001/12/27 19:20:26 $
/// </version>
public class ComparableEvent : IComparable<ComparableEvent>
{
private int mOutcome;
private int[] mPredicateIndexes ;
private int mSeenCount = 1;
/// <summary>
/// The outcome ID of this event.
/// </summary>
public int Outcome
{
get
{
return mOutcome;
}
set
{
mOutcome = value;
}
}
/// <summary>
/// Returns an array containing the indexes of the predicates in this event.
/// </summary>
/// <returns>
/// Integer array of predicate indexes.
/// </returns>
public int[] GetPredicateIndexes()
{
return mPredicateIndexes;
}
/// <summary>
/// Sets the array containing the indices of the predicates in this event.
/// </summary>
/// <param name="predicateIndexes">
/// Integer array of predicate indexes.
/// </param>
public void SetPredicateIndexes(int[] predicateIndexes)
{
mPredicateIndexes = predicateIndexes;
}
/// <summary>
/// The number of times this event
/// has been seen.
/// </summary>
public int SeenCount
{
get
{
return mSeenCount;
}
set
{
mSeenCount = value;
}
}
/// <summary>
/// Constructor for the ComparableEvent.
/// </summary>
/// <param name="outcome">
/// The ID of the outcome for this event.
/// </param>
/// <param name="predicateIndexes">
/// Array of indexes for the predicates in this event.
/// </param>
public ComparableEvent(int outcome, int[] predicateIndexes)
{
mOutcome = outcome;
System.Array.Sort(predicateIndexes);
mPredicateIndexes = predicateIndexes;
}
/// <summary>
/// Implementation of the IComparable interface.
/// </summary>
/// <param name="eventToCompare">
/// ComparableEvent to compare this event to.
/// </param>
/// <returns>
/// A value indicating if the compared object is smaller, greater or the same as this event.
/// </returns>
public virtual int CompareTo(ComparableEvent eventToCompare)
{
if (mOutcome < eventToCompare.Outcome)
{
return - 1;
}
else if (mOutcome > eventToCompare.Outcome)
{
return 1;
}
int smallerLength = (mPredicateIndexes .Length > eventToCompare.GetPredicateIndexes().Length ? eventToCompare.GetPredicateIndexes().Length : GetPredicateIndexes().Length);
for (int currentIndex = 0; currentIndex < smallerLength; currentIndex++)
{
if (mPredicateIndexes [currentIndex] < eventToCompare.GetPredicateIndexes()[currentIndex])
{
return - 1;
}
else if (mPredicateIndexes [currentIndex] > eventToCompare.GetPredicateIndexes()[currentIndex])
{
return 1;
}
}
if (mPredicateIndexes .Length < eventToCompare.GetPredicateIndexes().Length)
{
return - 1;
}
else if (mPredicateIndexes .Length > eventToCompare.GetPredicateIndexes().Length)
{
return 1;
}
return 0;
}
/// <summary>
/// Tests if this event is equal to another object.
/// </summary>
/// <param name="o">
/// Object to test against.
/// </param>
/// <returns>
/// True if the objects are equal.
/// </returns>
public override bool Equals (object o)
{
if (!(o is ComparableEvent))
{
return false;
}
return (this.CompareTo(o as ComparableEvent)== 0);
}
/// <summary>
/// Provides a hashcode for storing events in a dictionary or hashtable.
/// </summary>
/// <returns>
/// A hashcode value.
/// </returns>
public override int GetHashCode()
{
return this.ToString().GetHashCode();
}
/// <summary>
/// Override to provide a succint summary of the ComparableEvent object.
/// </summary>
/// <returns>
/// string representation of the ComparableEvent object.
/// </returns>
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
for (int currentIndex = 0; currentIndex < mPredicateIndexes.Length; currentIndex++)
{
stringBuilder.Append(" ").Append(mPredicateIndexes [currentIndex]);
}
return stringBuilder.ToString();
}
}
}

View file

@ -0,0 +1,308 @@
//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.MachineLearning
{
/// <summary>
/// A maximum entropy model which has been trained using the Generalized
/// Iterative Scaling procedure.
/// </summary>
/// <author>
/// Tom Morton and Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on GISModel.java, $Revision: 1.13 $, $Date: 2004/06/11 20:51:44 $
/// </version>
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;
/// <summary>
/// Constructor for a maximum entropy model trained using the
/// Generalized Iterative Scaling procedure.
/// </summary>
/// <param name="reader">
/// A reader providing the data for the model.
/// </param>
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 -------
/// <summary>
/// Returns the number of outcomes for this model.
/// </summary>
/// <returns>
/// The number of outcomes.
/// </returns>
public int OutcomeCount
{
get
{
return (_outcomeCount);
}
}
/// <summary>
/// Evaluates a context.
/// </summary>
/// <param name="context">
/// A list of string names of the contextual predicates
/// which are to be evaluated together.
/// </param>
/// <returns>
/// An array of the probabilities for each of the different
/// outcomes, all of which sum to 1.
/// </returns>
public double[] Evaluate(string[] context)
{
return Evaluate(context, new double[_outcomeCount]);
}
/// <summary>
/// Use this model to evaluate a context and return an array of the
/// likelihood of each outcome given that context.
/// </summary>
/// <param name="context">
/// The names of the predicates which have been observed at
/// the present decision point.
/// </param>
/// <param name="outcomeSums">
/// This is where the distribution is stored.
/// </param>
/// <returns>
/// 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).
/// </returns>
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;
}
/// <summary>
/// Return the name of the outcome corresponding to the highest likelihood
/// in the parameter outcomes.
/// </summary>
/// <param name="outcomes">
/// A double[] as returned by the Evaluate(string[] context)
/// method.
/// </param>
/// <returns>
/// The name of the most likely outcome.
/// </returns>
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];
}
/// <summary>
/// Return a string matching all the outcome names with all the
/// probabilities produced by the <code>Evaluate(string[] context)</code>
/// method.
/// </summary>
/// <param name="outcomes">
/// A <code>double[]</code> as returned by the
/// <code>eval(string[] context)</code>
/// method.
/// </param>
/// <returns>
/// string containing outcome names paired with the normalized
/// probability (contained in the <code>double[] outcomes</code>)
/// for each one.
/// </returns>
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();
}
}
/// <summary>
/// Return the name of an outcome corresponding to an integer ID value.
/// </summary>
/// <param name="outcomeIndex">
/// An outcome ID.
/// </param>
/// <returns>
/// The name of the outcome associated with that ID.
/// </returns>
public string GetOutcomeName(int outcomeIndex)
{
return _outcomeNames[outcomeIndex];
}
/// <summary>
/// Gets the index associated with the string name of the given outcome.
/// </summary>
/// <param name="outcome">
/// the string name of the outcome for which the
/// index is desired
/// </param>
/// <returns>
/// the index if the given outcome label exists for this
/// model, -1 if it does not.
/// </returns>
public int GetOutcomeIndex(string outcome)
{
for (int iCurrentOutcomeName = 0; iCurrentOutcomeName < _outcomeNames.Length; iCurrentOutcomeName++)
{
if (_outcomeNames[iCurrentOutcomeName] == outcome)
{
return iCurrentOutcomeName;
}
}
return - 1;
}
/// <summary>
/// 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.
/// </summary>
/// <returns>
/// Dictionary containing PatternedPredicate objects.
/// </returns>
public Dictionary<string, PatternedPredicate> GetPredicates()
{
return _reader.GetPredicates();
}
/// <summary>
/// Provides the list of outcome patterns used by the predicates. This method will usually
/// only be needed by GisModelWriters.
/// </summary>
/// <returns>
/// Array of outcome patterns.
/// </returns>
public int[][] GetOutcomePatterns()
{
return _reader.GetOutcomePatterns();
}
/// <summary>
/// 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.
/// </summary>
/// <returns>
/// Array containing the outcome names.
/// </returns>
public string[] GetOutcomeNames()
{
return _outcomeNames;
}
/// <summary>
/// Provides the model's correction constant.
/// This property will usually only be needed by GisModelWriters.
/// </summary>
public int CorrectionConstant { get; private set; }
/// <summary>
/// Provides the model's correction parameter.
/// This property will usually only be needed by GisModelWriters.
/// </summary>
public double CorrectionParameter { get; private set; }
}
}

View file

@ -0,0 +1,886 @@
//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 GISTrainer.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;
using System.Collections.Generic;
namespace BotSharp.MachineLearning
{
/// <summary>
/// An implementation of Generalized Iterative Scaling. The reference paper
/// for this implementation was Adwait Ratnaparkhi's tech report at the
/// University of Pennsylvania's Institute for Research in Cognitive Science,
/// and is available at <a href ="ftp://ftp.cis.upenn.edu/pub/ircs/tr/97-08.ps.Z"><code>ftp://ftp.cis.upenn.edu/pub/ircs/tr/97-08.ps.Z</code></a>.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J, Northedge
/// </author>
/// <version>
/// based on GISTrainer.java, $Revision: 1.15 $, $Date: 2004/06/14 20:52:41 $
/// </version>
public class GisTrainer : IO.IGisModelReader
{
private int mTokenCount; // # of event tokens
private int mPredicateCount; // # of predicates
private int mOutcomeCount; // # of mOutcomes
private int mTokenID; // global index variable for Tokens
private int mPredicateId; // global index variable for Predicates
private int mOutcomeId; // global index variable for Outcomes
// records the array of predicates seen in each event
private int[][] mContexts;
// records the array of outcomes seen in each event
private int[] mOutcomes;
// records the num of times an event has been seen, paired to
// int[][] mContexts
private int[] mNumTimesEventsSeen;
// stores the string names of the outcomes. The GIS only tracks outcomes
// as ints, and so this array is needed to save the model to disk and
// thereby allow users to know what the outcome was in human
// understandable terms.
private string[] mOutcomeLabels;
// stores the string names of the predicates. The GIS only tracks
// predicates as ints, and so this array is needed to save the model to
// disk and thereby allow users to know what the outcome was in human
// understandable terms.
private string[] mPredicateLabels;
// stores the observed expections of each of the events
private double[][] mObservedExpections;
// stores the estimated parameter value of each predicate during iteration
private double[][] mParameters;
// Stores the expected values of the features based on the current models
private double[][] mModelExpections;
//The maximum number of features fired in an event. Usually referred to as C.
private int mMaximumFeatureCount;
// stores inverse of constant, 1/C.
private double mMaximumFeatureCountInverse;
// the correction parameter of the model
private double mCorrectionParameter;
// observed expectation of correction feature
private double mCorrectionFeatureObservedExpectation;
// a global variable to help compute the amount to modify the correction
// parameter
private double mCorrectionFeatureModifier;
private const double mNearZero = 0.01;
private const double mLLThreshold = 0.0001;
// Stores the output of the current model on a single event durring
// training. This will be reset for every event for every iteration.
private double[] mModelDistribution;
// Stores the number of features that get fired per event
private int[] mFeatureCounts;
// initial probability for all outcomes.
private double mInitialProbability;
private Dictionary<string, PatternedPredicate> mPredicates;
private int[][] mOutcomePatterns;
// smoothing algorithm (unused) --------
// internal class UpdateParametersWithSmoothingProcedure : Trove.IIntDoubleProcedure
// {
// private double mdSigma = 2.0;
// public UpdateParametersWithSmoothingProcedure(GisTrainer enclosingInstance)
// {
// moEnclosingInstance = enclosingInstance;
// }
//
// private GisTrainer moEnclosingInstance;
//
// public virtual bool Execute(int outcomeID, double input)
// {
// double x = 0.0;
// double x0 = 0.0;
// double tmp;
// double f;
// double fp;
// for (int i = 0; i < 50; i++)
// {
// // check what domain these parameters are in
// tmp = moEnclosingInstance.maoModelExpections[moEnclosingInstance.miPredicateID][outcomeID] * System.Math.Exp(moEnclosingInstance.miConstant * x0);
// f = tmp + (input + x0) / moEnclosingInstance.mdSigma - moEnclosingInstance.maoObservedExpections[moEnclosingInstance.miPredicateID][outcomeID];
// fp = tmp * moEnclosingInstance.miConstant + 1 / moEnclosingInstance.mdSigma;
// if (fp == 0)
// {
// break;
// }
// x = x0 - f / fp;
// if (System.Math.Abs(x - x0) < 0.000001)
// {
// x0 = x;
// break;
// }
// x0 = x;
// }
// moEnclosingInstance.maoParameters[moEnclosingInstance.miPredicateID].Put(outcomeID, input + x0);
// return true;
// }
// }
// training progress event -----------
/// <summary>
/// Used to provide informational messages regarding the
/// progress of the training algorithm.
/// </summary>
public event TrainingProgressEventHandler TrainingProgress;
/// <summary>
/// Used to raise events providing messages with information
/// about training progress.
/// </summary>
/// <param name="e">
/// Contains the message with information about the progress of
/// the training algorithm.
/// </param>
protected virtual void OnTrainingProgress(TrainingProgressEventArgs e)
{
if (TrainingProgress != null)
{
TrainingProgress(this, e);
}
}
private void NotifyProgress(string message)
{
OnTrainingProgress(new TrainingProgressEventArgs(message));
}
// training options --------------
/// <summary>
/// Sets whether this trainer will use smoothing while training the model.
/// This can improve model accuracy, though training will potentially take
/// longer and use more memory. Model size will also be larger.
/// </summary>
/// <remarks>
/// Initial testing indicates improvements for models built on small data sets and
/// few outcomes, but performance degradation for those with large data
/// sets and lots of outcomes.
/// </remarks>
public bool Smoothing { get; set; }
/// <summary>
/// Sets whether this trainer will use slack parameters while training the model.
/// </summary>
public bool UseSlackParameter { get; set; }
/// <summary>
/// If smoothing is in use, this value indicates the "number" of
/// times we want the trainer to imagine that it saw a feature that it
/// actually didn't see. Defaulted to 0.1.
/// </summary>
public double SmoothingObservation { get; set; }
/// <summary>
/// Creates a new <code>GisTrainer</code> instance.
/// </summary>
public GisTrainer()
{
Smoothing = false;
UseSlackParameter = false;
SmoothingObservation = 0.1;
}
/// <summary>
/// Creates a new <code>GisTrainer</code> instance.
/// </summary>
/// <param name="useSlackParameter">
/// Sets whether this trainer will use slack parameters while training the model.
/// </param>
public GisTrainer(bool useSlackParameter)
{
Smoothing = false;
UseSlackParameter = useSlackParameter;
SmoothingObservation = 0.1;
}
/// <summary>
/// Creates a new <code>GisTrainer</code> instance.
/// </summary>
/// <param name="smoothingObservation">
/// If smoothing is in use, this value indicates the "number" of
/// times we want the trainer to imagine that it saw a feature that it
/// actually didn't see. Defaulted to 0.1.
/// </param>
public GisTrainer(double smoothingObservation)
{
Smoothing = true;
UseSlackParameter = false;
SmoothingObservation = smoothingObservation;
}
/// <summary>
/// Creates a new <code>GisTrainer</code> instance.
/// </summary>
/// <param name="useSlackParameter">
/// Sets whether this trainer will use slack parameters while training the model.
/// </param>
/// <param name="smoothingObservation">
/// If smoothing is in use, this value indicates the "number" of
/// times we want the trainer to imagine that it saw a feature that it
/// actually didn't see. Defaulted to 0.1.
/// </param>
public GisTrainer(bool useSlackParameter, double smoothingObservation)
{
Smoothing = true;
UseSlackParameter = useSlackParameter;
SmoothingObservation = smoothingObservation;
}
// alternative TrainModel signatures --------------
/// <summary>
/// Train a model using the GIS algorithm.
/// </summary>
/// <param name="eventReader">
/// The ITrainingEventReader holding the data on which this model
/// will be trained.
/// </param>
public virtual void TrainModel(ITrainingEventReader eventReader)
{
TrainModel(eventReader, 100, 0);
}
/// <summary>
/// Train a model using the GIS algorithm.
/// </summary>
/// <param name="eventReader">
/// The ITrainingEventReader holding the data on which this model will be trained
/// </param>
/// <param name="iterations">The number of GIS iterations to perform</param>
/// <param name="cutoff">
/// The number of times a predicate must be seen in order
/// to be relevant for training.
/// </param>
public virtual void TrainModel(ITrainingEventReader eventReader, int iterations, int cutoff)
{
TrainModel(iterations, new OnePassDataIndexer(eventReader, cutoff));
}
// training algorithm -----------------------------
/// <summary>
/// Train a model using the GIS algorithm.
/// </summary>
/// <param name="iterations">
/// The number of GIS iterations to perform.
/// </param>
/// <param name="dataIndexer">
/// The data indexer used to compress events in memory.
/// </param>
public virtual void TrainModel(int iterations, ITrainingDataIndexer dataIndexer)
{
int[] outcomeList;
//incorporate all of the needed info
NotifyProgress("Incorporating indexed data for training...");
mContexts = dataIndexer.GetContexts();
mOutcomes = dataIndexer.GetOutcomeList();
mNumTimesEventsSeen = dataIndexer.GetNumTimesEventsSeen();
mTokenCount = mContexts.Length;
// determine the correction constant and its inverse
mMaximumFeatureCount = mContexts[0].Length;
for (mTokenID = 1; mTokenID < mContexts.Length; mTokenID++)
{
if (mContexts[mTokenID].Length > mMaximumFeatureCount)
{
mMaximumFeatureCount = mContexts[mTokenID].Length;
}
}
mMaximumFeatureCountInverse = 1.0 / mMaximumFeatureCount;
NotifyProgress("done.");
mOutcomeLabels = dataIndexer.GetOutcomeLabels();
outcomeList = dataIndexer.GetOutcomeList();
mOutcomeCount = mOutcomeLabels.Length;
mInitialProbability = Math.Log(1.0 / mOutcomeCount);
mPredicateLabels = dataIndexer.GetPredicateLabels();
mPredicateCount = mPredicateLabels.Length;
NotifyProgress("\tNumber of Event Tokens: " + mTokenCount);
NotifyProgress("\t Number of Outcomes: " + mOutcomeCount);
NotifyProgress("\t Number of Predicates: " + mPredicateCount);
// set up feature arrays
var predicateCounts = new int[mPredicateCount][];
for (mPredicateId = 0; mPredicateId < mPredicateCount; mPredicateId++)
{
predicateCounts[mPredicateId] = new int[mOutcomeCount];
}
for (mTokenID = 0; mTokenID < mTokenCount; mTokenID++)
{
for (int currentContext = 0; currentContext < mContexts[mTokenID].Length; currentContext++)
{
predicateCounts[mContexts[mTokenID][currentContext]][outcomeList[mTokenID]] += mNumTimesEventsSeen[mTokenID];
}
}
// A fake "observation" to cover features which are not detected in
// the data. The default is to assume that we observed "1/10th" of a
// feature during training.
double smoothingObservation = SmoothingObservation;
// Get the observed expectations of the features. Strictly speaking,
// we should divide the counts by the number of Tokens, but because of
// the way the model's expectations are approximated in the
// implementation, this is cancelled out when we compute the next
// iteration of a parameter, making the extra divisions wasteful.
mOutcomePatterns = new int[mPredicateCount][];
mParameters = new double[mPredicateCount][];
mModelExpections = new double[mPredicateCount][];
mObservedExpections = new double[mPredicateCount][];
for (mPredicateId = 0; mPredicateId < mPredicateCount; mPredicateId++)
{
int activeOutcomeCount;
if (Smoothing)
{
activeOutcomeCount = mOutcomeCount;
}
else
{
activeOutcomeCount = 0;
for (mOutcomeId = 0; mOutcomeId < mOutcomeCount; mOutcomeId++)
{
if (predicateCounts[mPredicateId][mOutcomeId] > 0)
{
activeOutcomeCount++;
}
}
}
mOutcomePatterns[mPredicateId] = new int[activeOutcomeCount];
mParameters[mPredicateId] = new double[activeOutcomeCount];
mModelExpections[mPredicateId] = new double[activeOutcomeCount];
mObservedExpections[mPredicateId] = new double[activeOutcomeCount];
int currentOutcome = 0;
for (mOutcomeId = 0; mOutcomeId < mOutcomeCount; mOutcomeId++)
{
if (predicateCounts[mPredicateId][mOutcomeId] > 0)
{
mOutcomePatterns[mPredicateId][currentOutcome] = mOutcomeId;
mObservedExpections[mPredicateId][currentOutcome] = Math.Log(predicateCounts[mPredicateId][mOutcomeId]);
currentOutcome++;
}
else if (Smoothing)
{
mOutcomePatterns[mPredicateId][currentOutcome] = mOutcomeId;
mObservedExpections[mPredicateId][currentOutcome] = Math.Log(smoothingObservation);
currentOutcome++;
}
}
}
// compute the expected value of correction
if (UseSlackParameter)
{
int correctionFeatureValueSum = 0;
for (mTokenID = 0; mTokenID < mTokenCount; mTokenID++)
{
for (int currentContext = 0; currentContext < mContexts[mTokenID].Length; currentContext++)
{
mPredicateId = mContexts[mTokenID][currentContext];
if ((!Smoothing) && predicateCounts[mPredicateId][mOutcomes[mTokenID]] == 0)
{
correctionFeatureValueSum += mNumTimesEventsSeen[mTokenID];
}
}
correctionFeatureValueSum += (mMaximumFeatureCount - mContexts[mTokenID].Length) * mNumTimesEventsSeen[mTokenID];
}
if (correctionFeatureValueSum == 0)
{
mCorrectionFeatureObservedExpectation = Math.Log(mNearZero); //nearly zero so log is defined
}
else
{
mCorrectionFeatureObservedExpectation = Math.Log(correctionFeatureValueSum);
}
mCorrectionParameter = 0.0;
}
NotifyProgress("...done.");
mModelDistribution = new double[mOutcomeCount];
mFeatureCounts = new int[mOutcomeCount];
//Find the parameters
NotifyProgress("Computing model parameters...");
FindParameters(iterations);
NotifyProgress("Converting to new predicate format...");
ConvertPredicates();
}
/// <summary>
/// Estimate and return the model parameters.
/// </summary>
/// <param name="iterations">
/// Number of iterations to run through.
/// </param>
private void FindParameters(int iterations)
{
double previousLogLikelihood = 0.0;
NotifyProgress("Performing " + iterations + " iterations.");
for (int currentIteration = 1; currentIteration <= iterations; currentIteration++)
{
if (currentIteration < 10)
{
NotifyProgress(" " + currentIteration + ": ");
}
else if (currentIteration < 100)
{
NotifyProgress(" " + currentIteration + ": ");
}
else
{
NotifyProgress(currentIteration + ": ");
}
double currentLogLikelihood = NextIteration();
if (currentIteration > 1)
{
if (previousLogLikelihood > currentLogLikelihood)
{
throw new SystemException("Model Diverging: loglikelihood decreased");
}
if (currentLogLikelihood - previousLogLikelihood < mLLThreshold)
{
break;
}
}
previousLogLikelihood = currentLogLikelihood;
}
// kill a bunch of these big objects now that we don't need them
mObservedExpections = null;
mModelExpections = null;
mNumTimesEventsSeen = null;
mContexts = null;
}
/// <summary>
/// Use this model to evaluate a context and return an array of the
/// likelihood of each outcome given that context.
/// </summary>
/// <param name="context">
/// The integers of the predicates which have been
/// observed at the present decision point.
/// </param>
/// <param name="outcomeSums">
/// The normalized probabilities for the outcomes given the
/// context. The indexes of the double[] are the outcome
/// ids.
/// </param>
protected virtual void Evaluate(int[] context, double[] outcomeSums)
{
for (int outcomeIndex = 0; outcomeIndex < mOutcomeCount; outcomeIndex++)
{
outcomeSums[outcomeIndex] = mInitialProbability;
mFeatureCounts[outcomeIndex] = 0;
}
int[] activeOutcomes;
int outcomeId;
int predicateId;
int currentActiveOutcome;
for (int currentContext = 0; currentContext < context.Length; currentContext++)
{
predicateId = context[currentContext];
activeOutcomes = mOutcomePatterns[predicateId];
for (currentActiveOutcome = 0; currentActiveOutcome < activeOutcomes.Length; currentActiveOutcome++)
{
outcomeId = activeOutcomes[currentActiveOutcome];
mFeatureCounts[outcomeId]++;
outcomeSums[outcomeId] += mMaximumFeatureCountInverse * mParameters[predicateId][currentActiveOutcome];
}
}
double sum = 0.0;
for (int currentOutcomeId = 0; currentOutcomeId < mOutcomeCount; currentOutcomeId++)
{
outcomeSums[currentOutcomeId] = System.Math.Exp(outcomeSums[currentOutcomeId]);
if (UseSlackParameter)
{
outcomeSums[currentOutcomeId] += ((1.0 - ((double) mFeatureCounts[currentOutcomeId] / mMaximumFeatureCount)) * mCorrectionParameter);
}
sum += outcomeSums[currentOutcomeId];
}
for (int currentOutcomeId = 0; currentOutcomeId < mOutcomeCount; currentOutcomeId++)
{
outcomeSums[currentOutcomeId] /= sum;
}
}
/// <summary>
/// Compute one iteration of GIS and retutn log-likelihood.
/// </summary>
/// <returns>The log-likelihood.</returns>
private double NextIteration()
{
// compute contribution of p(a|b_i) for each feature and the new
// correction parameter
double logLikelihood = 0.0;
mCorrectionFeatureModifier = 0.0;
int eventCount = 0;
int numCorrect = 0;
int outcomeId;
for (mTokenID = 0; mTokenID < mTokenCount; mTokenID++)
{
Evaluate(mContexts[mTokenID], mModelDistribution);
for (int currentContext = 0; currentContext < mContexts[mTokenID].Length; currentContext++)
{
mPredicateId = mContexts[mTokenID][currentContext];
for (int currentActiveOutcome = 0; currentActiveOutcome < mOutcomePatterns[mPredicateId].Length; currentActiveOutcome++)
{
outcomeId = mOutcomePatterns[mPredicateId][currentActiveOutcome];
mModelExpections[mPredicateId][currentActiveOutcome] += (mModelDistribution[outcomeId] * mNumTimesEventsSeen[mTokenID]);
if (UseSlackParameter)
{
mCorrectionFeatureModifier += mModelDistribution[mOutcomeId] * mNumTimesEventsSeen[mTokenID];
}
}
}
if (UseSlackParameter)
{
mCorrectionFeatureModifier += (mMaximumFeatureCount - mContexts[mTokenID].Length) * mNumTimesEventsSeen[mTokenID];
}
logLikelihood += System.Math.Log(mModelDistribution[mOutcomes[mTokenID]]) * mNumTimesEventsSeen[mTokenID];
eventCount += mNumTimesEventsSeen[mTokenID];
//calculation solely for the information messages
int max = 0;
for (mOutcomeId = 1; mOutcomeId < mOutcomeCount; mOutcomeId++)
{
if (mModelDistribution[mOutcomeId] > mModelDistribution[max])
{
max = mOutcomeId;
}
}
if (max == mOutcomes[mTokenID])
{
numCorrect += mNumTimesEventsSeen[mTokenID];
}
}
NotifyProgress(".");
// compute the new parameter values
for (mPredicateId = 0; mPredicateId < mPredicateCount; mPredicateId++)
{
for (int currentActiveOutcome = 0; currentActiveOutcome < mOutcomePatterns[mPredicateId].Length; currentActiveOutcome++)
{
outcomeId = mOutcomePatterns[mPredicateId][currentActiveOutcome];
mParameters[mPredicateId][currentActiveOutcome] += (mObservedExpections[mPredicateId][currentActiveOutcome] - Math.Log(mModelExpections[mPredicateId][currentActiveOutcome]));
mModelExpections[mPredicateId][currentActiveOutcome] = 0.0;// re-initialize to 0.0's
}
}
if (mCorrectionFeatureModifier > 0.0 && UseSlackParameter)
{
mCorrectionParameter += (mCorrectionFeatureObservedExpectation - Math.Log(mCorrectionFeatureModifier));
}
NotifyProgress(". logLikelihood=" + logLikelihood + "\t" + ((double) numCorrect / eventCount));
return (logLikelihood);
}
/// <summary>
/// Convert the predicate data into the outcome pattern / patterned predicate format used by the GIS models.
/// </summary>
private void ConvertPredicates()
{
var predicates = new PatternedPredicate[mParameters.Length];
for (mPredicateId = 0; mPredicateId < mPredicateCount; mPredicateId++)
{
double[] parameters = mParameters[mPredicateId];
predicates[mPredicateId] = new PatternedPredicate(mPredicateLabels[mPredicateId], parameters);
}
var comparer = new OutcomePatternComparer();
Array.Sort(mOutcomePatterns, predicates, comparer);
List<int[]> outcomePatterns = new List<int[]>();
int currentPatternId = 0;
int predicatesInPattern = 0;
int[] currentPattern = mOutcomePatterns[0];
for (mPredicateId = 0; mPredicateId < mPredicateCount; mPredicateId++)
{
if (comparer.Compare(currentPattern, mOutcomePatterns[mPredicateId]) == 0)
{
predicates[mPredicateId].OutcomePattern = currentPatternId;
predicatesInPattern++;
}
else
{
int[] pattern = new int[currentPattern.Length + 1];
pattern[0] = predicatesInPattern;
currentPattern.CopyTo(pattern, 1);
outcomePatterns.Add(pattern);
currentPattern = mOutcomePatterns[mPredicateId];
currentPatternId++;
predicates[mPredicateId].OutcomePattern = currentPatternId;
predicatesInPattern = 1;
}
}
int[] finalPattern = new int[currentPattern.Length + 1];
finalPattern[0] = predicatesInPattern;
currentPattern.CopyTo(finalPattern, 1);
outcomePatterns.Add(finalPattern);
mOutcomePatterns = outcomePatterns.ToArray();
mPredicates = new Dictionary<string, PatternedPredicate>(predicates.Length);
for (mPredicateId = 0; mPredicateId < mPredicateCount; mPredicateId++)
{
mPredicates.Add(predicates[mPredicateId].Name, predicates[mPredicateId]);
}
}
// IGisModelReader implementation --------------------
/// <summary>
/// The correction constant for the model produced as a result of training.
/// </summary>
public int CorrectionConstant
{
get
{
return mMaximumFeatureCount;
}
}
/// <summary>
/// The correction parameter for the model produced as a result of training.
/// </summary>
public double CorrectionParameter
{
get
{
return mCorrectionParameter;
}
}
/// <summary>
/// Obtains the outcome labels for the model produced as a result of training.
/// </summary>
/// <returns>
/// Array of outcome labels.
/// </returns>
public string[] GetOutcomeLabels()
{
return mOutcomeLabels;
}
/// <summary>
/// Obtains the outcome patterns for the model produced as a result of training.
/// </summary>
/// <returns>
/// Array of outcome patterns.
/// </returns>
public int[][] GetOutcomePatterns()
{
return mOutcomePatterns;
}
/// <summary>
/// Obtains the predicate data for the model produced as a result of training.
/// </summary>
/// <returns>
/// Dictionary containing PatternedPredicate objects.
/// </returns>
public Dictionary<string, PatternedPredicate> GetPredicates()
{
return mPredicates;
}
/// <summary>
/// Returns trained model information for a predicate, given the predicate label.
/// </summary>
/// <param name="predicateLabel">
/// The predicate label to fetch information for.
/// </param>
/// <param name="featureCounts">
/// Array to be passed in to the method; it should have a length equal to the number of outcomes
/// in the model. The method increments the count of each outcome that is active in the specified
/// predicate.
/// </param>
/// <param name="outcomeSums">
/// Array to be passed in to the method; it should have a length equal to the number of outcomes
/// in the model. The method adds the parameter values for each of the active outcomes in the
/// predicate.
/// </param>
public void GetPredicateData(string predicateLabel, int[] featureCounts, double[] outcomeSums)
{
if (mPredicates.ContainsKey(predicateLabel))
{
PatternedPredicate predicate = mPredicates[predicateLabel];
if (predicate != null)
{
int[] activeOutcomes = mOutcomePatterns[predicate.OutcomePattern];
for (int currentActiveOutcome = 1; currentActiveOutcome < activeOutcomes.Length; currentActiveOutcome++)
{
int outcomeIndex = activeOutcomes[currentActiveOutcome];
featureCounts[outcomeIndex]++;
outcomeSums[outcomeIndex] += predicate.GetParameter(currentActiveOutcome - 1);
}
}
}
}
private class OutcomePatternComparer : IComparer<int[]>
{
internal OutcomePatternComparer()
{
}
/// <summary>
/// Compare two outcome patterns and determines which comes first,
/// based on the outcome ids (lower outcome ids first)
/// </summary>
/// <param name="firstPattern">
/// First outcome pattern to compare.
/// </param>
/// <param name="secondPattern">
/// Second outcome pattern to compare.
/// </param>
/// <returns></returns>
public virtual int Compare(int[] firstPattern, int[] secondPattern)
{
int smallerLength = (firstPattern.Length > secondPattern.Length ? secondPattern.Length : firstPattern.Length);
for (int currentOutcome = 0; currentOutcome < smallerLength; currentOutcome++)
{
if (firstPattern[currentOutcome] < secondPattern[currentOutcome])
{
return - 1;
}
else if (firstPattern[currentOutcome] > secondPattern[currentOutcome])
{
return 1;
}
}
if (firstPattern.Length < secondPattern.Length)
{
return - 1;
}
else if (firstPattern.Length > secondPattern.Length)
{
return 1;
}
return 0;
}
}
}
/// <summary>
/// Event arguments class for training progress events.
/// </summary>
public class TrainingProgressEventArgs : EventArgs
{
private string mMessage;
/// <summary>
/// Constructor for the training progress event arguments.
/// </summary>
/// <param name="message">
/// Information message about the progress of training.
/// </param>
public TrainingProgressEventArgs(string message)
{
mMessage = message;
}
/// <summary>
/// Information message about the progress of training.
/// </summary>
public string Message
{
get
{
return mMessage;
}
}
}
/// <summary>
/// Event handler delegate for the training progress event.
/// </summary>
public delegate void TrainingProgressEventHandler(object sender, TrainingProgressEventArgs e);
}

View file

@ -0,0 +1,71 @@
//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 ContextGenerator.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;
namespace BotSharp.MachineLearning
{
/// <summary>
/// Generate contexts for maximum entropy decisions.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on ContextGenerator.java, $Revision: 1.1.1.1 $, $Date: 2001/10/23 14:06:53 $
/// </version>
public interface IContextGenerator
{
/// <summary>
/// Builds up the list of contextual predicates given an object.
/// </summary>
string[] GetContext(object input);
}
/// <summary>
/// Generate contexts for maximum entropy decisions.
/// </summary>
public interface IContextGenerator<T>
{
/// <summary>
/// Builds up the list of contextual predicates given an object of type T.
/// </summary>
string[] GetContext(T input);
}
}

View file

@ -0,0 +1,151 @@
//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 MaxentModel.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;
namespace BotSharp.MachineLearning
{
/// <summary>
/// Interface for maximum entropy models.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on MaxentModel.java, $Revision: 1.4 $, $Date: 2003/12/09 23:13:53 $
/// </version>
public interface IMaximumEntropyModel
{
/// <summary>
/// Returns the number of outcomes for this model.
/// </summary>
/// <returns>
/// The number of outcomes.
/// </returns>
int OutcomeCount
{
get;
}
/// <summary>
/// Evaluates a context.
/// </summary>
/// <param name="context">
/// A list of string names of the contextual predicates
/// which are to be evaluated together.
/// </param>
/// <returns>
/// An array of the probabilities for each of the different
/// outcomes, all of which sum to 1.
/// </returns>
double[] Evaluate(string[] context);
/// <summary>
/// Evaluates a context.
/// </summary>
/// <param name="context">
/// A list of string names of the contextual predicates
/// which are to be evaluated together.
/// </param>
/// <param name="probabilities">
/// An array which is populated with the probabilities for each of the different
/// outcomes, all of which sum to 1.
/// </param>
/// <returns>
/// an array of the probabilities for each of the different
/// outcomes, all of which sum to 1. The <code>probabilities</code> array is returned if it is appropiately sized.
/// </returns>
double[] Evaluate(string[] context, double[] probabilities);
/// <summary>
/// Simple function to return the outcome associated with the index
/// containing the highest probability in the double[].
/// </summary>
/// <param name="outcomes">
/// A <code>double[]</code> as returned by the
/// <code>Evaluate(string[] context)</code>
/// method.
/// </param>
/// <returns>
/// the string name of the best outcome
/// </returns>
string GetBestOutcome(double[] outcomes);
/// <summary>
/// Return a string matching all the outcome names with all the
/// probabilities produced by the <code>eval(string[]
/// context)</code> method.
/// </summary>
/// <param name="outcomes">
/// A <code>double[]</code> as returned by the
/// <code>eval(string[] context)</code>
/// method.
/// </param>
/// <returns>
/// string containing outcome names paired with the normalized
/// probability (contained in the <code>double[] ocs</code>)
/// for each one.
/// </returns>
string GetAllOutcomes(double[] outcomes);
/// <summary>
/// Gets the string name of the outcome associated with the supplied index
/// </summary>
/// <param name="index">
/// the index for which the name of the associated outcome is desired.
/// </param>
/// <returns>
/// the string name of the outcome
/// </returns>
string GetOutcomeName(int index);
/// <summary>
/// Gets the index associated with the string name of the given
/// outcome.
/// </summary>
/// <param name="outcome">
/// the string name of the outcome for which the
/// index is desired
/// </param>
/// <returns>
/// the index if the given outcome label exists for this
/// model, -1 if it does not.
/// </returns>
int GetOutcomeIndex(string outcome);
}
}

View file

@ -0,0 +1,175 @@
//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 BinaryGISModelReader.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.IO;
using System.Collections.Generic;
using System.Text;
namespace BotSharp.MachineLearning.IO
{
/// <summary>
/// A reader for GIS models stored in a binary format. This format is not the one
/// used by the <see cref="SharpEntropy.IO.JavaBinaryGisModelReader">java version of MaxEnt</see>.
/// It has two main differences, designed for performance when loading the data
/// from file: first, it uses big endian data values, which is native for C#, and secondly it
/// encodes the outcome patterns and values in a more efficient manner.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on BinaryGISModelReader.java, $Revision: 1.1.1.1 $, $Date: 2001/10/23 14:06:53 $
/// </version>
public class BinaryGisModelReader : GisModelReader
{
private readonly Stream _input;
private readonly byte[] _buffer;
private int _stringLength = 0;
private readonly Encoding _encoding = Encoding.UTF8;
/// <summary>
/// Constructor which directly instantiates the Stream containing
/// the model contents.
/// </summary>
/// <param name="dataInputStream">
/// The Stream containing the model information.
/// </param>
public BinaryGisModelReader(Stream dataInputStream)
{
using (_input = dataInputStream)
{
_buffer = new byte[256];
base.ReadModel();
}
}
/// <summary>
/// Constructor which takes a filename and creates a reader for it.
/// </summary>
/// <param name="fileName">
/// The full path and name of the file in which the model is stored.
/// </param>
public BinaryGisModelReader(string fileName)
{
using (_input = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
_buffer = new byte[256];
base.ReadModel();
}
}
/// <summary>
/// Reads a 32-bit signed integer from the model file.
/// </summary>
protected override int ReadInt32()
{
_input.Read(_buffer, 0, 4);
return BitConverter.ToInt32(_buffer, 0);
}
/// <summary>
/// Reads a double-precision floating point number from the model file.
/// </summary>
protected override double ReadDouble()
{
_input.Read(_buffer, 0, 8);
return BitConverter.ToDouble(_buffer, 0);
}
/// <summary>
/// Reads a UTF-8 encoded string from the model file.
/// </summary>
protected override string ReadString()
{
_stringLength = _input.ReadByte();
_input.Read(_buffer, 0, _stringLength);
return _encoding.GetString(_buffer, 0, _stringLength);
}
/// <summary>
/// Reads the predicate data from the file in a more efficient format to that implemented by
/// GisModelReader.
/// </summary>
/// <param name="outcomePatterns">
/// Jagged 2-dimensional array of integers that will contain the outcome patterns for the model
/// after this method is called.
/// </param>
/// <param name="predicates">
/// Dictionary that will contain the predicate information for the model
/// after this method is called.
/// </param>
protected override void ReadPredicates(out int[][] outcomePatterns, out Dictionary<string, PatternedPredicate> predicates)
{
//read from the model how many outcome patterns there are
int outcomePatternCount = ReadInt32();
outcomePatterns = new int[outcomePatternCount][];
//read from the model how many predicates there are
predicates = new Dictionary<string, PatternedPredicate>(ReadInt32());
//for each outcome pattern in the model
for (int currentOutcomePattern = 0; currentOutcomePattern < outcomePatternCount; currentOutcomePattern++)
{
//read the number of outcomes in this pattern. This number is 1 greater than the real number of outcomes
//in the pattern, because the 0th value contains the number of predicates that use this pattern.
var currentOutcomePatternLength = ReadInt32();
outcomePatterns[currentOutcomePattern] = new int[currentOutcomePatternLength];
//read in the outcomes for this pattern
for (int currentOutcome = 0; currentOutcome <currentOutcomePatternLength; currentOutcome++)
{
outcomePatterns[currentOutcomePattern][currentOutcome] = ReadInt32();
}
//read in the details of the predicates in this pattern
for (int currentPredicate = 0; currentPredicate < outcomePatterns[currentOutcomePattern][0]; currentPredicate++)
{
string predicateName = ReadString();
//we know that the number of parameters in this predicate will be the number of outcomes in the pattern
double[] parameters = new double[currentOutcomePatternLength - 1];
//read in the parameters for this predicate
for (int currentParameter = 0; currentParameter < currentOutcomePatternLength - 1; currentParameter++)
{
parameters[currentParameter] = ReadDouble();
}
predicates.Add(predicateName, new PatternedPredicate(currentOutcomePattern, parameters));
}
}
}
}
}

View file

@ -0,0 +1,186 @@
//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 BinaryGISModelWriter.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.IO;
namespace BotSharp.MachineLearning.IO
{
/// <summary>
/// A writer for GIS models that saves models in a binary format. This format is not the one
/// used by the <see cref="SharpEntropy.IO.JavaBinaryGisModelWriter">java version of MaxEnt</see>.
/// It has two main differences, designed for performance when loading the data
/// from file: first, it uses big endian data values, which is native for C#, and secondly it
/// encodes the outcome patterns and values in a more efficient manner.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on BinaryGISModelWriter.java $Revision: 1.1.1.1 $, $Date: 2001/10/23 14:06:53 $
/// </version>
public class BinaryGisModelWriter : GisModelWriter
{
private Stream _output;
private byte[] _buffer = new byte[7];
private readonly System.Text.Encoding _encoding = System.Text.Encoding.UTF8;
/// <summary>
/// Default constructor.
/// </summary>
public BinaryGisModelWriter(){}
/// <summary>
/// Takes a GIS model and a file and
/// writes the model to that file.
/// </summary>
/// <param name="model">
/// The GisModel which is to be persisted.
/// </param>
/// <param name="fileName">
/// The full path and name of the file in which the model is to be persisted.
/// </param>
public void Persist(GisModel model, string fileName)
{
using (_output = new FileStream(fileName, FileMode.Create))
{
base.Persist(model);
}
}
/// <summary>
/// Takes a GIS model and a Stream and
/// writes the model to that Stream.
/// </summary>
/// <param name="model">
/// The GIS model which is to be persisted.
/// </param>
/// <param name="dataOutputStream">
/// The Stream which will be used to persist the model.
/// </param>
public void Persist(GisModel model, Stream dataOutputStream)
{
using (_output = dataOutputStream)
{
base.Persist(model);
}
}
/// <summary>
/// Writes a UTF-8 encoded string to the model file.
/// </summary>
/// <param name="data">
/// The string data to be persisted.
/// </param>
protected override void WriteString(string data)
{
_output.WriteByte((byte)_encoding.GetByteCount(data));
_output.Write(_encoding.GetBytes(data), 0, _encoding.GetByteCount(data));
}
/// <summary>
/// Writes a 32-bit signed integer to the model file.
/// </summary>
/// <param name="data">
/// The integer data to be persisted.
/// </param>
protected override void WriteInt32(int data)
{
_buffer = BitConverter.GetBytes(data);
_output.Write(_buffer, 0, 4);
}
/// <summary>
/// Writes a double-precision floating point number to the model file.
/// </summary>
/// <param name="data">
/// The floating point data to be persisted.
/// </param>
protected override void WriteDouble(double data)
{
_buffer = BitConverter.GetBytes(data);
_output.Write(_buffer, 0, 8);
}
/// <summary>
/// Writes the predicate data to the file in a more efficient format to that implemented by
/// GisModelWriter.
/// </summary>
/// <param name="model">
/// The GIS model containing the predicate data to be persisted.
/// </param>
protected override void WritePredicates(GisModel model)
{
int[][] outcomePatterns = model.GetOutcomePatterns();
PatternedPredicate[] predicates = GetPredicates();
//write the number of outcome patterns
WriteInt32(outcomePatterns.Length);
//write the number of predicates
WriteInt32(predicates.Length);
int currentPredicate = 0;
for (int currentOutcomePattern = 0; currentOutcomePattern < outcomePatterns.Length; currentOutcomePattern++)
{
//write how many outcomes in this pattern
WriteInt32(outcomePatterns[currentOutcomePattern].Length);
//write the outcomes in this pattern (the first value contains the number of predicates in the pattern
//rather than an outcome)
for (int currentOutcome = 0; currentOutcome < outcomePatterns[currentOutcomePattern].Length; currentOutcome++)
{
WriteInt32(outcomePatterns[currentOutcomePattern][currentOutcome]);
}
//write predicates for this pattern
while (currentPredicate < predicates.Length && predicates[currentPredicate].OutcomePattern == currentOutcomePattern)
{
WriteString(predicates[currentPredicate].Name);
for (int currentParameter = 0; currentParameter < predicates[currentPredicate].ParameterCount; currentParameter++)
{
WriteDouble(predicates[currentPredicate].GetParameter(currentParameter));
}
currentPredicate++;
}
}
}
}
}

View file

@ -0,0 +1,347 @@
//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 GISModelReader.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.MachineLearning.IO
{
/// <summary>
/// Abstract parent class for readers of GIS models.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on GISModelReader.java, $Revision: 1.5 $, $Date: 2004/06/11 20:51:36 $
/// </version>
public abstract class GisModelReader : IGisModelReader
{
private char[] _spaces;
private int _correctionConstant;
private double _correctionParameter;
private string[] _outcomeLabels;
private int[][] _outcomePatterns;
private int _predicateCount;
private Dictionary<string, PatternedPredicate> _predicates;
/// <summary>
/// The number of predicates contained in the model.
/// </summary>
protected int PredicateCount
{
get
{
return _predicateCount;
}
}
/// <summary>
/// Retrieve a model from disk.
///
/// <p>This method delegates to worker methods for each part of this
/// sequence. If you are creating a reader that conforms largely to this
/// sequence but varies at one or more points, override the relevant worker
/// method(s) to achieve the required format.</p>
///
/// <p>If you are creating a reader for a format which does not follow this
/// sequence at all, override this method and ignore the
/// other ReadX methods provided in this abstract class.</p>
/// </summary>
/// <remarks>
/// Thie method assumes that models are saved in the
/// following sequence:
///
/// <p>GIS (model type identifier)</p>
/// <p>1. the correction constant (int)</p>
/// <p>2. the correction constant parameter (double)</p>
/// <p>3. outcomes</p>
/// <p>3a. number of outcomes (int)</p>
/// <p>3b. outcome names (string array - length specified in 3a)</p>
/// <p>4. predicates</p>
/// <p>4a. outcome patterns</p>
/// <p>4ai. number of outcome patterns (int)</p>
/// <p>4aii. outcome pattern values (each stored in a space delimited string)</p>
/// <p>4b. predicate labels</p>
/// <p>4bi. number of predicates (int)</p>
/// <p>4bii. predicate names (string array - length specified in 4bi)</p>
/// <p>4c. predicate parameters (double values)</p>
/// </remarks>
protected virtual void ReadModel()
{
_spaces = new char[] {' '}; //cached constant to improve performance
CheckModelType();
_correctionConstant = ReadCorrectionConstant();
_correctionParameter = ReadCorrectionParameter();
_outcomeLabels = ReadOutcomes();
ReadPredicates(out _outcomePatterns, out _predicates);
}
/// <summary>
/// Checks the model file being read from begins with the sequence of characters
/// "GIS".
/// </summary>
protected virtual void CheckModelType()
{
string modelType = ReadString();
if (modelType != "GIS")
{
throw new ApplicationException("Error: attempting to load a " + modelType + " model as a GIS model." + " You should expect problems.");
}
}
/// <summary>
/// Reads the correction constant from the model file.
/// </summary>
protected virtual int ReadCorrectionConstant()
{
return ReadInt32();
}
/// <summary>
/// Reads the correction constant parameter from the model file.
/// </summary>
protected virtual double ReadCorrectionParameter()
{
return ReadDouble();
}
/// <summary>
/// Reads the outcome names from the model file.
/// </summary>
protected virtual string[] ReadOutcomes()
{
int outcomeCount = ReadInt32();
var outcomeLabels = new string[outcomeCount];
for (int currentLabel = 0; currentLabel < outcomeCount; currentLabel++)
{
outcomeLabels[currentLabel] = ReadString();
}
return outcomeLabels;
}
/// <summary>
/// Reads the predicate information from the model file, placing the data in two
/// structures - an array of outcome patterns, and a Dictionary of predicates
/// keyed by predicate name.
/// </summary>
protected virtual void ReadPredicates(out int[][] outcomePatterns, out Dictionary<string, PatternedPredicate> predicates)
{
outcomePatterns = ReadOutcomePatterns();
string[] asPredicateLabels = ReadPredicateLabels();
predicates = ReadParameters(outcomePatterns, asPredicateLabels);
}
/// <summary>
/// Reads the outcome pattern information from the model file.
/// </summary>
protected virtual int[][] ReadOutcomePatterns()
{
//get the number of outcome patterns (that is, the number of unique combinations of outcomes in the model)
int outcomePatternCount = ReadInt32();
//initialize an array of outcome patterns. Each outcome pattern is itself an array of integers
var outcomePatterns = new int[outcomePatternCount][];
//for each outcome pattern
for (int currentOutcomePattern = 0; currentOutcomePattern < outcomePatternCount; currentOutcomePattern++)
{
//read a space delimited string from the model file containing the information for the integer array.
//The first value in the integer array is the number of predicates related to this outcome pattern; the
//other values make up the outcome IDs for this pattern.
string[] tokens = ReadString().Split(_spaces);
//convert this string to the array of integers required for the pattern
var patternData = new int[tokens.Length];
for (int currentPatternValue = 0; currentPatternValue < tokens.Length; currentPatternValue++)
{
patternData[currentPatternValue] = int.Parse(tokens[currentPatternValue], System.Globalization.CultureInfo.InvariantCulture);
}
outcomePatterns[currentOutcomePattern] = patternData;
}
return outcomePatterns;
}
/// <summary>
/// Reads the outcome labels from the model file.
/// </summary>
protected virtual string[] ReadPredicateLabels()
{
_predicateCount = ReadInt32();
var predicateLabels = new string[_predicateCount];
for (int currentPredicate = 0; currentPredicate < _predicateCount; currentPredicate++)
{
predicateLabels[currentPredicate] = ReadString();
}
return predicateLabels;
}
/// <summary>
/// Reads the predicate parameter information from the model file.
/// </summary>
protected virtual Dictionary<string, PatternedPredicate> ReadParameters(int[][] outcomePatterns, string[] predicateLabels)
{
var predicates = new Dictionary<string, PatternedPredicate>(predicateLabels.Length);
int parameterIndex = 0;
for (int currentOutcomePattern = 0; currentOutcomePattern < outcomePatterns.Length; currentOutcomePattern++)
{
for (int currentOutcomeInfo = 0; currentOutcomeInfo < outcomePatterns[currentOutcomePattern][0]; currentOutcomeInfo++)
{
var parameters = new double[outcomePatterns[currentOutcomePattern].Length - 1];
for (int currentParameter = 0; currentParameter < outcomePatterns[currentOutcomePattern].Length - 1; currentParameter++)
{
parameters[currentParameter] = ReadDouble();
}
predicates.Add(predicateLabels[parameterIndex], new PatternedPredicate(currentOutcomePattern, parameters));
parameterIndex++;
}
}
return predicates;
}
/// <summary>
/// Implement as needed for the format the model is stored in.
/// </summary>
protected abstract int ReadInt32();
/// <summary>
/// Implement as needed for the format the model is stored in.
/// </summary>
protected abstract double ReadDouble();
/// <summary>
/// Implement as needed for the format the model is stored in.
/// </summary>
protected abstract string ReadString();
/// <summary>
/// The model's correction constant.
/// </summary>
public int CorrectionConstant
{
get
{
return _correctionConstant;
}
}
/// <summary>
/// The model's correction constant parameter.
/// </summary>
public double CorrectionParameter
{
get
{
return _correctionParameter;
}
}
/// <summary>
/// Returns the labels for all the outcomes in the model.
/// </summary>
/// <returns>
/// string array containing outcome labels.
/// </returns>
public string[] GetOutcomeLabels()
{
return _outcomeLabels;
}
/// <summary>
/// Returns the outcome patterns in the model.
/// </summary>
/// <returns>
/// Array of integer arrays containing the information for
/// each outcome pattern in the model.
/// </returns>
public int[][] GetOutcomePatterns()
{
return _outcomePatterns;
}
/// <summary>
/// Returns the predicates in the model.
/// </summary>
/// <returns>
/// Dictionary containing PatternedPredicate objects keyed
/// by predicate label.
/// </returns>
public Dictionary<string, PatternedPredicate> GetPredicates()
{
return _predicates;
}
/// <summary>
/// Returns model information for a predicate, given the predicate label.
/// </summary>
/// <param name="predicateLabel">
/// The predicate label to fetch information for.
/// </param>
/// <param name="featureCounts">
/// Array to be passed in to the method; it should have a length equal to the number of outcomes
/// in the model. The method increments the count of each outcome that is active in the specified
/// predicate.
/// </param>
/// <param name="outcomeSums">
/// Array to be passed in to the method; it should have a length equal to the number of outcomes
/// in the model. The method adds the parameter values for each of the active outcomes in the
/// predicate.
/// </param>
public virtual void GetPredicateData(string predicateLabel, int[] featureCounts, double[] outcomeSums)
{
try
{
if (predicateLabel != null && _predicates.ContainsKey(predicateLabel))
{
PatternedPredicate predicate = _predicates[predicateLabel];
int[] activeOutcomes = _outcomePatterns[predicate.OutcomePattern];
for (int currentActiveOutcome = 1; currentActiveOutcome < activeOutcomes.Length; currentActiveOutcome++)
{
int outcomeIndex = activeOutcomes[currentActiveOutcome];
featureCounts[outcomeIndex]++;
outcomeSums[outcomeIndex] += predicate.GetParameter(currentActiveOutcome - 1);
}
}
}
catch (ArgumentNullException ex)
{
throw new ArgumentException(string.Format("Try to find key '{0}' in predicates dictionary ({1} entries)", predicateLabel, _predicates.Count), ex);
}
}
}
}

View file

@ -0,0 +1,313 @@
//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 GISModeWriter.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.MachineLearning.IO
{
/// <summary> Abstract parent class for GIS model writers that save data to a single
/// file. It provides the persist method which takes care of the structure of a stored
/// document, and requires an extending class to define precisely how the data should
/// be stored.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on GISModelWriter.java, $Revision: 1.5 $, $Date: 2004/06/11 20:51:36 $
/// </version>
public abstract class GisModelWriter
{
private PatternedPredicate[] mPredicates;
/// <summary>
/// Implement as needed for the format the model is stored in.
/// </summary>
/// <param name="data">
/// string data to be written to storage.
/// </param>
protected abstract void WriteString(string data);
/// <summary>
/// Implement as needed for the format the model is stored in.
/// </summary>
/// <param name="data">
/// Integer data to be written to storage.
/// </param>
protected abstract void WriteInt32(int data);
/// <summary>
/// Implement as needed for the format the model is stored in.
/// </summary>
/// <param name="data">
/// Double precision floating point data to be written to storage.
/// </param>
protected abstract void WriteDouble(double data);
/// <summary>
/// Obtains a list of the predicates in the model to be written to storage.
/// </summary>
/// <returns>
/// Array of PatternedPredicate objects containing the predicate data for the model.
/// </returns>
protected PatternedPredicate[] GetPredicates()
{
return mPredicates;
}
/// <summary>
/// Sets the list of predicates to be written to storage.
/// </summary>
/// <param name="predicates">
/// Array of PatternedPredicate objects to be persisted.
/// </param>
protected void SetPredicates(PatternedPredicate[] predicates)
{
mPredicates = predicates;
}
/// <summary>
/// Writes the model to persistent storage, using the <code>writeX()</code> methods
/// provided by extending classes.
///
/// <p>This method delegates to worker methods for each part of this
/// sequence. If you are creating a writer that conforms largely to this
/// sequence but varies at one or more points, override the relevant worker
/// method(s) to achieve the required format.</p>
///
/// <p>If you are creating a writer for a format which does not follow this
/// sequence at all, override this method and ignore the
/// other WriteX methods provided in this abstract class.</p>
/// </summary>
/// <param name="model">
/// GIS model whose data is to be persisted.
/// </param>
protected void Persist(GisModel model)
{
Initialize(model);
WriteModelType("GIS");
WriteCorrectionConstant(model.CorrectionConstant);
WriteCorrectionParameter(model.CorrectionParameter);
WriteOutcomes(model.GetOutcomeNames());
WritePredicates(model);
}
/// <summary>
/// Organises the data available in the GIS model into a structure that is easier to
/// persist from.
/// </summary>
/// <param name="model">
/// The GIS model to be persisted.
///</param>
protected virtual void Initialize(GisModel model)
{
//read the predicates from the model
Dictionary<string, PatternedPredicate> predicates = model.GetPredicates();
//build arrays of predicates and predicate names from the dictionary
mPredicates = new PatternedPredicate[predicates.Count];
var predicateNames = new string[predicates.Count];
predicates.Values.CopyTo(mPredicates, 0);
predicates.Keys.CopyTo(predicateNames, 0);
//give each PatternedPredicate in the array the name taken from the dictionary keys
for (int currentPredicate = 0; currentPredicate < predicates.Count; currentPredicate++)
{
mPredicates[currentPredicate].Name = predicateNames[currentPredicate];
}
//sort the PatternedPredicate array based on the outcome pattern that each predicate uses
Array.Sort(mPredicates, new OutcomePatternIndexComparer());
}
/// <summary>
/// Writes the model type identifier at the beginning of the file.
/// </summary>
/// <param name="modelType">string identifying the model type.</param>
protected virtual void WriteModelType(string modelType)
{
WriteString(modelType);
}
/// <summary>
/// Writes the value of the correction constant
/// </summary>
/// <param name="correctionConstant">the model's correction constant value.</param>
protected virtual void WriteCorrectionConstant(int correctionConstant)
{
WriteInt32(correctionConstant);
}
/// <summary>
/// Writes the value of the correction constant parameter.
/// </summary>
/// <param name="correctionParameter">the model's correction constant parameter.</param>
protected virtual void WriteCorrectionParameter(double correctionParameter)
{
WriteDouble(correctionParameter);
}
/// <summary>
/// Writes the outcome labels to the file.
/// </summary>
/// <param name="outcomeLabels">string array of outcome labels.</param>
protected virtual void WriteOutcomes(string[] outcomeLabels)
{
//write the number of outcomes
WriteInt32(outcomeLabels.Length);
//write each label
foreach (string label in outcomeLabels)
{
WriteString(label);
}
}
/// <summary>
/// Writes the predicate information to the model file.
/// </summary>
/// <param name="model">The GIS model to write the data from.</param>
protected virtual void WritePredicates(GisModel model)
{
WriteOutcomePatterns(model.GetOutcomePatterns());
WritePredicateNames();
WriteParameters();
}
/// <summary>
/// Writes the outcome pattern data to the file.
/// </summary>
/// <param name="outcomePatterns">
/// Array of outcome patterns, each an integer array containing
/// the number of predicates using the pattern, and then the list of
/// outcome IDs in the pattern.
/// </param>
protected void WriteOutcomePatterns(int[][] outcomePatterns)
{
//write the number of outcome patterns
WriteInt32(outcomePatterns.Length);
//for each pattern
foreach (int[] pattern in outcomePatterns)
{
//build a string with the pattern values separated by spaces
var outcomePatternBuilder = new StringBuilder();
for (int currentOutcome = 0; currentOutcome < pattern.Length; currentOutcome++)
{
if (currentOutcome > 0)
{
outcomePatternBuilder.Append(" ");
}
outcomePatternBuilder.Append(pattern[currentOutcome]);
}
//write the string containing pattern values to the file
WriteString(outcomePatternBuilder.ToString());
}
}
/// <summary>
/// Write the names of the predicates to the model file.
/// </summary>
protected void WritePredicateNames()
{
//write the number of predicates
WriteInt32(mPredicates.Length);
//for each predicate, write its name to the file
foreach (PatternedPredicate predicate in mPredicates)
{
WriteString(predicate.Name);
}
}
/// <summary>
/// Writes out the parameter values for all the predicates to the model file.
/// </summary>
protected void WriteParameters()
{
foreach (PatternedPredicate predicate in mPredicates)
{
for (int currentParameter = 0; currentParameter < predicate.ParameterCount; currentParameter++)
{
WriteDouble(predicate.GetParameter(currentParameter));
}
}
}
/// <summary>
/// Class to enable sorting PatternedPredicates into order based on the
/// outcome pattern index.
/// </summary>
private class OutcomePatternIndexComparer : IComparer<PatternedPredicate>
{
/// <summary>
/// Default constructor.
/// </summary>
internal OutcomePatternIndexComparer(){}
/// <summary>
/// Implementation of the IComparer interface.
/// Compares two PatternedPredicate objects and returns a value indicating whether
/// one is less than, equal to or greater than the other.
/// </summary>
/// <param name="firstPredicate">
/// First object to compare.
/// </param>
/// <param name="secondPredicate">
/// Second object to compare.
/// </param>
/// <returns>
/// -1 if the first PatternedPredicate has a lower outcome pattern index;
/// 1 if the second PatternedPredicate has a lower outcome pattern index;
/// 0 if they both have the same outcome pattern index.
/// </returns>
public virtual int Compare(PatternedPredicate firstPredicate, PatternedPredicate secondPredicate)
{
if (firstPredicate.OutcomePattern < secondPredicate.OutcomePattern)
{
return -1;
}
else if (firstPredicate.OutcomePattern > secondPredicate.OutcomePattern)
{
return 1;
}
return 0;
}
}
}
}

View file

@ -0,0 +1,87 @@
//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 has no equivalent in the java MaxEnt library, because the link
//between GISModel and GISModelReader is implemented differently there. This
//interface is designed so that GIS model reader classes can hold some or all of
//their data in persistent storage rather than in memory.
using System;
using System.Collections.Generic;
namespace BotSharp.MachineLearning.IO
{
/// <summary>
/// Interface for readers of GIS models.
/// </summary>
public interface IGisModelReader
{
/// <summary>
/// Returns the value of the model's correction constant. This property should
/// usually only be accessed by GIS model writer classes via the GisModel class.
/// </summary>
int CorrectionConstant
{
get;
}
/// <summary>
/// Returns the value of the model's correction constant parameter. This property should
/// usually only be accessed by GIS model writer classes via the GisModel class.
/// </summary>
double CorrectionParameter
{
get;
}
/// <summary>
/// Returns the model's outcome labels as a string array. This method should
/// usually only be accessed by GIS model writer classes via the GisModel class.
/// </summary>
string[] GetOutcomeLabels();
/// <summary>
/// Returns the model's outcome patterns. This method should
/// usually only be accessed by GIS model writer classes via the GisModel class.
/// </summary>
int[][] GetOutcomePatterns();
/// <summary>
/// Returns the model's predicates. This method should
/// usually only be accessed by GIS model writer classes via the GisModel class.
/// </summary>
Dictionary<string, PatternedPredicate> GetPredicates();
/// <summary>
/// Returns model information for a predicate, given the predicate label.
/// </summary>
/// <param name="predicateLabel">
/// The predicate label to fetch information for.
/// </param>
/// <param name="featureCounts">
/// Array to be passed in to the method; it should have a length equal to the number of outcomes
/// in the model. The method increments the count of each outcome that is active in the specified
/// predicate.
/// </param>
/// <param name="outcomeSums">
/// Array to be passed in to the method; it should have a length equal to the number of outcomes
/// in the model. The method adds the parameter values for each of the active outcomes in the
/// predicate.
/// </param>
void GetPredicateData(string predicateLabel, int[] featureCounts, double[] outcomeSums);
}
}

View file

@ -0,0 +1,123 @@
//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 BinaryGISModelReader.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.IO;
namespace BotSharp.MachineLearning.IO
{
/// <summary>
/// A reader for GIS models stored in the binary format produced by the java version
/// of MaxEnt. This binary format stores data using big-endian values, which means
/// that the C# version must reverse the byte order of each value in turn, making it
/// less efficient. Use only for compatibility with the java MaxEnt library.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on BinaryGISModelReader.java, $Revision: 1.1.1.1 $, $Date: 2001/10/23 14:06:53 $
/// </version>
public class JavaBinaryGisModelReader : GisModelReader
{
private readonly Stream _input;
private readonly byte[] _buffer;
private int _stringLength = 0;
private readonly System.Text.Encoding _encoding = System.Text.Encoding.UTF8;
/// <summary>
/// Constructor which directly instantiates the Stream containing
/// the model contents.
/// </summary>
/// <param name="dataInputStream">The Stream containing the model information.
/// </param>
public JavaBinaryGisModelReader(Stream dataInputStream)
{
using (_input = dataInputStream)
{
_buffer = new byte[256];
base.ReadModel();
}
}
/// <summary>
/// Constructor which takes a filename and creates a reader for it.
/// </summary>
/// <param name="fileName">The full path and name of the file in which the model is stored.
/// </param>
public JavaBinaryGisModelReader(string fileName)
{
using (_input = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
_buffer = new byte[256];
base.ReadModel();
}
}
/// <summary>
/// Reads a 32-bit signed integer from the model file.
/// </summary>
protected override int ReadInt32()
{
_input.Read(_buffer, 0, 4);
Array.Reverse(_buffer, 0, 4);
return BitConverter.ToInt32(_buffer, 0);
}
/// <summary>
/// Reads a double-precision floating point number from the model file.
/// </summary>
protected override double ReadDouble()
{
_input.Read(_buffer, 0, 8);
Array.Reverse(_buffer, 0, 8);
return BitConverter.ToDouble(_buffer, 0);
}
/// <summary>
/// Reads a UTF-8 encoded string from the model file.
/// </summary>
protected override string ReadString()
{
//read string from binary file with UTF8 encoding
_stringLength = (_input.ReadByte() * 256) + _input.ReadByte();
_input.Read(_buffer, 0, _stringLength);
return _encoding.GetString(_buffer, 0, _stringLength);
}
}
}

View file

@ -0,0 +1,140 @@
//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 BinaryGISModelWriter.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.IO;
namespace BotSharp.MachineLearning.IO
{
/// <summary>
/// A writer for GIS models that saves models in the binary format used by the java
/// version of MaxEnt. This binary format stores data using big-endian values, which means
/// that the C# version must reverse the byte order of each value in turn, making it
/// less efficient. Use only for compatibility with the java MaxEnt library.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on BinaryGISModelWriter.java $Revision: 1.1.1.1 $, $Date: 2001/10/23 14:06:53 $
/// </version>
public class JavaBinaryGisModelWriter : GisModelWriter
{
private Stream mOutput;
private byte[] mBuffer = new byte[7];
private System.Text.Encoding mEncoding = System.Text.Encoding.UTF8;
/// <summary>
/// Default constructor.
/// </summary>
public JavaBinaryGisModelWriter()
{
}
/// <summary> Takes a GisModel and a File and
/// writes the model to that file.
/// </summary>
/// <param name="model">The GisModel which is to be persisted.
/// </param>
/// <param name="fileName">The name of the file in which the model is to be persisted.
/// </param>
public void Persist(GisModel model, string fileName)
{
using (mOutput = new FileStream(fileName, FileMode.Create))
{
base.Persist(model);
}
}
/// <summary>
/// Takes a GisModel and a Stream and writes the model to that stream.
/// </summary>
/// <param name="model">
/// The GIS model which is to be persisted.
/// </param>
/// <param name="dataOutputStream">
/// The Stream which will be used to persist the model.
/// </param>
public void Persist(GisModel model, Stream dataOutputStream)
{
using (mOutput = dataOutputStream)
{
base.Persist(model);
}
}
/// <summary>
/// Writes a UTF-8 encoded string to the model file.
/// </summary>
/// /// <param name="data">
/// The string data to be persisted.
/// </param>
protected override void WriteString(string data)
{
mOutput.WriteByte((byte)(mEncoding.GetByteCount(data) / 256));
mOutput.WriteByte((byte)(mEncoding.GetByteCount(data) % 256));
mOutput.Write(mEncoding.GetBytes(data), 0, mEncoding.GetByteCount(data));
}
/// <summary>
/// Writes a 32-bit signed integer to the model file.
/// </summary>
/// /// <param name="data">
/// The integer data to be persisted.
/// </param>
protected override void WriteInt32(int data)
{
mBuffer = BitConverter.GetBytes(data);
Array.Reverse(mBuffer);
mOutput.Write(mBuffer, 0, 4);
}
/// <summary>
/// Writes a double-precision floating point number to the model file.
/// </summary>
/// /// <param name="data">
/// The floating point data to be persisted.
/// </param>
protected override void WriteDouble(double data)
{
mBuffer = BitConverter.GetBytes(data);
Array.Reverse(mBuffer);
mOutput.Write(mBuffer, 0, 8);
}
}
}

View file

@ -0,0 +1,111 @@
//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 PlainTextGISModelReader.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.IO;
namespace BotSharp.MachineLearning.IO
{
/// <summary>
/// A reader for GIS models stored in plain text format.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on PlainTextGISModelReader.java, $Revision: 1.1.1.1 $, $Date: 2001/10/23 14:06:53 $
/// </version>
public class PlainTextGisModelReader : GisModelReader
{
private StreamReader mInput;
/// <summary>
/// Constructor which directly instantiates the StreamReader containing
/// the model contents.
/// </summary>
/// <param name="reader">
/// The StreamReader containing the model information.
/// </param>
public PlainTextGisModelReader(StreamReader reader)
{
using (mInput = reader)
{
base.ReadModel();
}
}
/// <summary>
/// Constructor which takes a file and creates a reader for it.
/// </summary>
/// <param name="fileName">
/// The full path and file name in which the model is stored.
/// </param>
public PlainTextGisModelReader(string fileName)
{
using (mInput = new StreamReader(fileName, System.Text.Encoding.UTF7))
{
base.ReadModel();
}
}
/// <summary>
/// Reads a 32-bit signed integer from the model file.
/// </summary>
protected override int ReadInt32()
{
return int.Parse(mInput.ReadLine(), System.Globalization.CultureInfo.InvariantCulture);
}
/// <summary>
/// Reads a double-precision floating point number from the model file.
/// </summary>
protected override double ReadDouble()
{
return double.Parse(mInput.ReadLine(), System.Globalization.CultureInfo.InvariantCulture);
}
/// <summary>
/// Reads a string from the model file.
/// </summary>
protected override string ReadString()
{
return mInput.ReadLine();
}
}
}

View file

@ -0,0 +1,134 @@
// 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 PlainTextGISModelReader.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.IO;
namespace BotSharp.MachineLearning.IO
{
/// <summary>
/// Model writer that saves models in plain text format.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on PlainTextGISModelWriter.java, $Revision: 1.1.1.1 $, $Date: 2001/10/23 14:06:53 $
/// </version>
public class PlainTextGisModelWriter : GisModelWriter
{
private StreamWriter mOutput;
/// <summary>
/// Default constructor.
/// </summary>
public PlainTextGisModelWriter()
{
}
/// <summary>
/// Takes a GIS model and a file and writes the model to that file.
/// </summary>
/// <param name="model">
/// The GisModel which is to be persisted.
/// </param>
/// <param name="fileName">
/// The name of the file in which the model is to be persisted.
/// </param>
public void Persist(GisModel model, string fileName)
{
using (mOutput = new StreamWriter(fileName, false, System.Text.Encoding.UTF7))
{
base.Persist(model);
}
}
/// <summary>
/// Takes a GisModel and a stream and writes the model to that stream.
/// </summary>
/// <param name="model">
/// The GisModel which is to be persisted.
/// </param>
/// <param name="writer">
/// The StreamWriter which will be used to persist the model.
/// </param>
public void Persist(GisModel model, StreamWriter writer)
{
using (mOutput = writer)
{
base.Persist(model);
}
}
/// <summary>
/// Writes a string to the model file.
/// </summary>
/// /// <param name="data">
/// The string data to be persisted.
/// </param>
protected override void WriteString(string data)
{
mOutput.Write(data);
mOutput.WriteLine();
}
/// <summary>
/// Writes a 32-bit signed integer to the model file.
/// </summary>
/// <param name="data">
/// The integer data to be persisted.
/// </param>
protected override void WriteInt32(int data)
{
mOutput.Write(data.ToString(System.Globalization.CultureInfo.InvariantCulture));
mOutput.WriteLine();
}
/// <summary>
/// Writes a double-precision floating point number to the model file.
/// </summary>
/// <param name="data">
/// The floating point data to be persisted.
/// </param>
protected override void WriteDouble(double data)
{
mOutput.Write(data.ToString(System.Globalization.CultureInfo.InvariantCulture));
mOutput.WriteLine();
}
}
}

View file

@ -0,0 +1,86 @@
//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 DataIndexer.java source file found in the
//original java implementation of MaxEnt. That source file contains the following header:
//Copyright (C) 2003 Thomas Morton
//
//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;
namespace BotSharp.MachineLearning
{
/// <summary>
/// Object that compresses events in memory and performs feature selection.
/// </summary>
public interface ITrainingDataIndexer
{
/// <summary>
/// Gets an array of context data calculated from the training data.
/// </summary>
/// <returns>
/// Array of integer arrays, each containing the context data for an event.
/// </returns>
int[][] GetContexts();
/// <summary>
/// Gets an array indicating how many times each event is seen.
/// </summary>
/// <returns>
/// Integer array with event frequencies.
/// </returns>
int[] GetNumTimesEventsSeen();
/// <summary>
/// Gets an outcome list.
/// </summary>
/// <returns>
/// Integer array of outcomes.
/// </returns>
int[] GetOutcomeList();
/// <summary>
/// Gets an array of predicate labels.
/// </summary>
/// <returns>
/// Array of predicate labels.
/// </returns>
string[] GetPredicateLabels();
/// <summary>
/// Gets an array of outcome labels.
/// </summary>
/// <returns>
/// Array of outcome labels.
/// </returns>
string[] GetOutcomeLabels();
}
}

View file

@ -0,0 +1,74 @@
//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 DataStream.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;
namespace BotSharp.MachineLearning
{
/// <summary>
/// A interface for objects which can deliver a stream of training data to be
/// supplied to an ITrainingEventReader. It is not necessary to use a ITrainingDataReader in a
/// SharpEntropy application, but it can be used to support a wider variety of formats
/// in which your training data can be held.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on DataStream.java, $Revision: 1.1.1.1 $, $Date: 2001/10/23 14:06:53 $
/// </version>
public interface ITrainingDataReader<T>
{
/// <summary>
/// Returns the next slice of data held in this ITrainingDataReader.
/// </summary>
/// <returns>
/// the object representing the data which is next in this
/// ITrainingDataReader
/// </returns>
T NextToken();
/// <summary>
/// Test whether there are any training data items remaining in this ITrainingDataReader.
/// </summary>
/// <returns>
/// true if this ITrainingDataReader has more data tokens
/// </returns>
bool HasNext();
}
}

View file

@ -0,0 +1,66 @@
//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 EventStream.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;
namespace BotSharp.MachineLearning
{
/// <summary>
/// An object which can deliver a stream of training events for the GIS
/// procedure (or others such as IIS if and when they are implemented).
/// TrainingEventReaders don't need to use SharpEntropy.ITrainingDataReader, but doing so
/// would provide greater flexibility for producing events from data stored in
/// different formats.
/// </summary>
public interface ITrainingEventReader
{
/// <summary>
/// Returns the next TrainingEvent object held in this TrainingEventReader.
/// </summary>
/// <returns>
/// the TrainingEvent object which is next in this TrainingEventReader
/// </returns>
TrainingEvent ReadNextEvent();
/// <summary>
/// Test whether there are any TrainingEvents remaining in this TrainingEventReader.
/// </summary>
/// <returns>
/// true if this TrainingEventReader has more TrainingEvents
/// </returns>
bool HasNext();
}
}

View file

@ -0,0 +1,212 @@
//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.MachineLearning
{
/// <summary>
/// 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.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on OnePassDataIndexer.java, $Revision: 1.1 $, $Date: 2003/12/13 16:41:29 $
/// </version>
public class OnePassDataIndexer : AbstractDataIndexer
{
/// <summary>
/// One argument constructor for OnePassDataIndexer which calls the two argument
/// constructor assuming no cutoff.
/// </summary>
/// <param name="eventReader">
/// An ITrainingEventReader which contains the a list of all the Events
/// seen in the training data.
/// </param>
public OnePassDataIndexer(ITrainingEventReader eventReader) : this(eventReader, 0)
{
}
/// <summary>
/// Two argument constructor for OnePassDataIndexer.
/// </summary>
/// <param name="eventReader">
/// An ITrainingEventReader which contains the a list of all the Events
/// seen in the training data.
/// </param>
/// <param name="cutoff">
/// The minimum number of times a predicate must have been
/// observed in order to be included in the model.
/// </param>
public OnePassDataIndexer(ITrainingEventReader eventReader, int cutoff)
{
Dictionary<string, int> predicateIndex;
List<TrainingEvent> events;
List<ComparableEvent> eventsToCompare;
predicateIndex = new Dictionary<string, int>();
//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.");
}
/// <summary>
/// Reads events from <tt>eventReader</tt> into a List&lt;TrainingEvent&gt;. The
/// predicates associated with each event are counted and any which
/// occur at least <tt>cutoff</tt> times are added to the
/// <tt>predicatesInOut</tt> dictionary along with a unique integer index.
/// </summary>
/// <param name="eventReader">
/// an <code>ITrainingEventReader</code> value
/// </param>
/// <param name="predicatesInOut">
/// a <code>Dictionary</code> value
/// </param>
/// <param name="cutoff">
/// an <code>int</code> value
/// </param>
/// <returns>
/// an <code>List of TrainingEvents</code> value
/// </returns>
private List<TrainingEvent> ComputeEventCounts(ITrainingEventReader eventReader, Dictionary<string, int> predicatesInOut, int cutoff)
{
var counter = new Dictionary<string, int>();
var events = new List<TrainingEvent>();
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<ComparableEvent> Index(List<TrainingEvent> events, Dictionary<string, int> predicateIndex)
{
var map = new Dictionary<string, int>();
int eventCount = events.Count;
int outcomeCount = 0;
var eventsToCompare = new List<ComparableEvent>(eventCount);
var indexedContext = new List<int>();
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;
}
}
}

View file

@ -0,0 +1,118 @@
//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.
using System;
namespace BotSharp.MachineLearning
{
/// <summary>
/// Object containing predicate data, where the parameters are matched to
/// the outcomes in an outcome pattern.
/// </summary>
/// <author>
/// Richard J. Northedge
/// </author>
public class PatternedPredicate
{
private int mOutcomePattern;
private double[] mParameters;
private string mName;
/// <summary>
/// Creates a PatternedPredicate object.
/// </summary>
/// <param name="outcomePattern">
/// Index into the outcome pattern array, specifying which outcome pattern relates to
/// this predicate.
/// </param>
/// <param name="parameters">
/// Array of parameters for this predicate.
/// </param>
protected internal PatternedPredicate(int outcomePattern, double[] parameters)
{
mOutcomePattern = outcomePattern;
mParameters = parameters;
}
/// <summary>
/// Creates a PatternedPredicate object.
/// </summary>
/// <param name="name">
/// The predicate name.
/// </param>
/// <param name="parameters">
/// Array of parameters for this predicate.
/// </param>
protected internal PatternedPredicate(string name, double[] parameters)
{
mName = name;
mParameters = parameters;
}
/// <summary>
/// Index into array of outcome patterns.
/// </summary>
public int OutcomePattern
{
get
{
return mOutcomePattern;
}
set // for trainer
{
mOutcomePattern = value;
}
}
/// <summary>
/// Gets the value of a parameter from this predicate.
/// </summary>
/// <param name="index">
/// index into the parameter array.
/// </param>
/// <returns></returns>
public double GetParameter(int index)
{
return mParameters[index];
}
/// <summary>
/// Number of parameters associated with this predicate.
/// </summary>
public int ParameterCount
{
get
{
return mParameters.Length;
}
}
/// <summary>
/// Name of the predicate.
/// </summary>
public string Name
{
get
{
return mName;
}
set
{
mName = value;
}
}
}
}

View file

@ -0,0 +1,86 @@
//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 PlainTextByLineDataStream.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.IO;
namespace BotSharp.MachineLearning
{
/// <summary>
/// This ITrainingDataReader implementation will take care of reading a plain text file
/// and returning the strings between each new line character, which is what
/// many SharpEntropy applications need in order to create ITrainingEventReaders.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on PlainTextByLineDataStream.java, $Revision: 1.1.1.1 $, $Date: 2001/10/23 14:06:53 $
/// </version>
public class PlainTextByLineDataReader : ITrainingDataReader<string>
{
private readonly StreamReader _dataReader;
private string _nextLine;
/// <summary>
/// Creates a training data reader for reading text lines from a file or other text stream
/// </summary>
/// <param name="dataSource">StreamReader containing the source of the training data</param>
public PlainTextByLineDataReader(StreamReader dataSource)
{
_dataReader = dataSource;
_nextLine = _dataReader.ReadLine();
}
/// <summary>Gets the next text line from the training data</summary>
/// <returns>Next text line from the training data</returns>
public virtual string NextToken()
{
string currentLine = _nextLine;
_nextLine = _dataReader.ReadLine();
return currentLine;
}
/// <summary>Checks if there is any more training data</summary>
/// <returns>true if there is more training data to be read</returns>
public virtual bool HasNext()
{
return (_nextLine != null);
}
}
}

View file

@ -0,0 +1,94 @@
//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 Event.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;
namespace BotSharp.MachineLearning
{
/// <summary>
/// The context of a decision point during training. This includes
/// contextual predicates and an outcome.
/// </summary>
/// <author>
/// Jason Baldridge
/// </author>
/// <author>
/// Richard J. Northedge
/// </author>
/// <version>
/// based on Event.java, $Revision: 1.3 $, $Date: 2003/12/09 23:13:08 $
/// </version>
public class TrainingEvent
{
/// <summary>
/// The outcome label for this training event.
/// </summary>
public string Outcome { get; private set; }
/// <summary>
/// The context for this training event.
/// </summary>
/// <returns>
/// A string array of context values for this training event.
/// </returns>
public string[] Context { get; private set; }
/// <summary>
/// Constructor for a training event.
/// </summary>
/// <param name="outcome">
/// the outcome label
/// </param>
/// <param name="context">
/// array containing context values
/// </param>
public TrainingEvent(string outcome, string[] context)
{
Outcome = outcome;
Context = context;
}
/// <summary>
/// Override providing text summary of the training event.
/// </summary>
/// <returns>
/// Summary of the training event.
/// </returns>
public override string ToString()
{
return Outcome + " " + string.Join(", ", Context);
}
}
}

View file

@ -0,0 +1,282 @@
//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 TwoPassDataIndexer.java source file found in the
//original java implementation of MaxEnt. That source file contains the following header:
//Copyright (C) 2003 Thomas Morton
//
//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.IO;
using System.Text;
namespace BotSharp.MachineLearning
{
/// <summary>
/// Collecting event and context counts by making two passes over the events.
/// The first pass determines which contexts will be used by the model, and the second
/// pass creates the events in memory containing only the contexts which will be used.
/// This greatly reduces the amount of memory required for storing the events.
/// During the first pass a temporary event file is created which is read during the second pass.
/// </summary>
/// /// <author>
/// Tom Morton
/// </author>
/// /// /// <author>
/// Richard J. Northedge
/// </author>
public class TwoPassDataIndexer : AbstractDataIndexer
{
/// <summary>
/// One argument constructor for DataIndexer which calls the two argument
/// constructor assuming no cutoff.
/// </summary>
/// <param name="eventReader">
/// An ITrainingEventReader which contains the list of all the events
/// seen in the training data.
/// </param>
public TwoPassDataIndexer(ITrainingEventReader eventReader): this(eventReader, 0){}
/// <summary>
/// Two argument constructor for TwoPassDataIndexer.
/// </summary>
/// <param name="eventReader">
/// An ITrainingEventReader which contains the a list of all the events
/// seen in the training data.
/// </param>
/// <param name="cutoff">
/// The minimum number of times a predicate must have been
/// observed in order to be included in the model.
/// </param>
public TwoPassDataIndexer(ITrainingEventReader eventReader, int cutoff)
{
List<ComparableEvent> eventsToCompare;
var predicateIndex = new Dictionary<string, int>();
//NotifyProgress("Indexing events using cutoff of " + cutoff + "\n");
//NotifyProgress("\tComputing event counts... ");
string tempFile = new FileInfo(Path.GetTempFileName()).FullName;
int eventCount = ComputeEventCounts(eventReader, tempFile, predicateIndex, cutoff);
//NotifyProgress("done. " + eventCount + " events");
//NotifyProgress("\tIndexing... ");
using (var fileEventReader = new FileEventReader(tempFile))
{
eventsToCompare = Index(eventCount, fileEventReader, predicateIndex);
}
if (File.Exists(tempFile))
{
File.Delete(tempFile);
}
//NotifyProgress("done.");
//NotifyProgress("Sorting and merging events... ");
SortAndMerge(eventsToCompare);
//NotifyProgress("Done indexing.");
}
/// <summary>
/// Reads events from <tt>eventStream</tt> into a dictionary. The
/// predicates associated with each event are counted and any which
/// occur at least <tt>cutoff</tt> times are added to the
/// <tt>predicatesInOut</tt> map along with a unique integer index.
/// </summary>
/// <param name="eventReader">
/// an <code>ITrainingEventReader</code> value
/// </param>
/// <param name="eventStoreFile">
/// a file name to which the events are written to for later processing.
/// </param>
/// <param name="predicatesInOut">
/// a <code>Dictionary</code> value
/// </param>
/// <param name="cutoff">
/// an <code>int</code> value
/// </param>
private int ComputeEventCounts(ITrainingEventReader eventReader, string eventStoreFile, Dictionary<string, int> predicatesInOut, int cutoff)
{
var counter = new Dictionary<string, int>();
int predicateIndex = 0;
int eventCount = 0;
using (var eventStoreWriter = new StreamWriter(eventStoreFile))
{
while (eventReader.HasNext())
{
TrainingEvent currentTrainingEvent = eventReader.ReadNextEvent();
eventCount++;
eventStoreWriter.Write(FileEventReader.ToLine(currentTrainingEvent));
string[] eventContext = currentTrainingEvent.Context;
for (int currentPredicate = 0; currentPredicate < eventContext.Length; currentPredicate++)
{
if (!predicatesInOut.ContainsKey(eventContext[currentPredicate]))
{
if (counter.ContainsKey(eventContext[currentPredicate]))
{
counter[eventContext[currentPredicate]]++;
}
else
{
counter.Add(eventContext[currentPredicate], 1);
}
if (counter[eventContext[currentPredicate]] >= cutoff)
{
predicatesInOut.Add(eventContext[currentPredicate], predicateIndex++);
counter.Remove(eventContext[currentPredicate]);
}
}
}
}
}
return eventCount;
}
private List<ComparableEvent> Index(int eventCount, ITrainingEventReader eventReader, Dictionary<string, int> predicateIndex)
{
var outcomeMap = new Dictionary<string, int>();
int outcomeCount = 0;
var eventsToCompare = new List<ComparableEvent>(eventCount);
var indexedContext = new List<int>();
while (eventReader.HasNext())
{
TrainingEvent currentTrainingEvent = eventReader.ReadNextEvent();
string[] eventContext = currentTrainingEvent.Context;
ComparableEvent comparableEvent;
int outcomeId;
string outcome = currentTrainingEvent.Outcome;
if (outcomeMap.ContainsKey(outcome))
{
outcomeId = outcomeMap[outcome];
}
else
{
outcomeId = outcomeCount++;
outcomeMap.Add(outcome, outcomeId);
}
for (int currentPredicate = 0; currentPredicate < eventContext.Length; currentPredicate++)
{
string predicate = eventContext[currentPredicate];
if (predicateIndex.ContainsKey(predicate))
{
indexedContext.Add(predicateIndex[predicate]);
}
}
// drop events with no active features
if (indexedContext.Count > 0)
{
comparableEvent = new ComparableEvent(outcomeId, indexedContext.ToArray());
eventsToCompare.Add(comparableEvent);
}
else
{
//"Dropped event " + currentTrainingEvent.Outcome + ":" + currentTrainingEvent.Context);
}
// recycle the list
indexedContext.Clear();
}
SetOutcomeLabels(ToIndexedStringArray(outcomeMap));
SetPredicateLabels(ToIndexedStringArray(predicateIndex));
return eventsToCompare;
}
}
class FileEventReader : ITrainingEventReader, IDisposable
{
private StreamReader mReader;
private string mCurrentLine;
private char[] mWhitespace;
public FileEventReader(string fileName)
{
mReader = new StreamReader(fileName, Encoding.UTF7);
mWhitespace = new char[] {'\t', '\n', '\r', ' '};
}
public virtual bool HasNext()
{
mCurrentLine = mReader.ReadLine();
return (mCurrentLine != null);
}
public virtual TrainingEvent ReadNextEvent()
{
string[] tokens = mCurrentLine.Split(mWhitespace);
string outcome = tokens[0];
var context = new string[tokens.Length - 1];
Array.Copy(tokens, 1, context, 0, tokens.Length - 1);
return (new TrainingEvent(outcome, context));
}
public static string ToLine(TrainingEvent eventToConvert)
{
var lineBuilder = new StringBuilder();
lineBuilder.Append(eventToConvert.Outcome);
string[] context = eventToConvert.Context;
for (int contextIndex = 0, contextLength = context.Length; contextIndex < contextLength; contextIndex++)
{
lineBuilder.Append(" " + context[contextIndex]);
}
lineBuilder.Append(System.Environment.NewLine);
return lineBuilder.ToString();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
mReader.Close();
}
}
~FileEventReader()
{
Dispose (false);
}
}
}

View file

@ -18,7 +18,7 @@ using System;
using System.IO;
using System.Collections.Generic;
namespace SharpWordNet
namespace BotSharp.MachineLearning
{
/// <summary>
/// Summary description for DataFileEngine.

View file

@ -17,7 +17,7 @@
using System;
using System.Linq;
namespace SharpWordNet
namespace BotSharp.MachineLearning
{
/// <summary>
/// Summary description for IndexWord.

View file

@ -21,7 +21,7 @@ using System;
using System.Collections.Generic;
using System.Text;
namespace SharpWordNet.Morph
namespace BotSharp.MachineLearning.Morph
{
public abstract class AbstractDelegatingOperation : IOperation
{

View file

@ -21,7 +21,7 @@ using System;
using System.Collections.Generic;
using System.Text;
namespace SharpWordNet.Morph
namespace BotSharp.MachineLearning.Morph
{
/// <summary>
/// Remove all applicable suffixes from the word(s) and do a look-up.

View file

@ -21,7 +21,7 @@ using System;
using System.Collections.Generic;
using System.Text;
namespace SharpWordNet.Morph
namespace BotSharp.MachineLearning.Morph
{
public interface IOperation
{

View file

@ -21,7 +21,7 @@ using System;
using System.Collections.Generic;
using System.Text;
namespace SharpWordNet.Morph
namespace BotSharp.MachineLearning.Morph
{
/// <summary>Lookup the word in the exceptions file of the given part-of-speech. </summary>
public class LookupExceptionsOperation : IOperation

View file

@ -21,7 +21,7 @@ using System;
using System.Collections.Generic;
using System.Text;
namespace SharpWordNet.Morph
namespace BotSharp.MachineLearning.Morph
{
public class LookupIndexWordOperation : IOperation
{

View file

@ -22,7 +22,7 @@ using System.Collections.Generic;
using System.Text;
using System.Collections;
namespace SharpWordNet.Morph
namespace BotSharp.MachineLearning.Morph
{
public class TokenizerOperation : AbstractDelegatingOperation
{

View file

@ -22,7 +22,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace SharpWordNet.Morph
namespace BotSharp.MachineLearning.Morph
{
public class Util
{

View file

@ -16,7 +16,7 @@
using System;
namespace SharpWordNet
namespace BotSharp.MachineLearning
{
/// <summary>
/// Summary description for Relation.

View file

@ -16,7 +16,7 @@
using System;
namespace SharpWordNet
namespace BotSharp.MachineLearning
{
/// <summary>
/// Summary description for RelationType.

View file

@ -16,7 +16,7 @@
using System;
namespace SharpWordNet
namespace BotSharp.MachineLearning
{
/// <summary>
/// Summary description for Synset.

View file

@ -16,7 +16,7 @@
using System;
namespace SharpWordNet
namespace BotSharp.MachineLearning
{
/// <summary>
/// Summary description for Tokenizer.

View file

@ -17,7 +17,7 @@
using System;
using System.Collections.Generic;
namespace SharpWordNet
namespace BotSharp.MachineLearning
{
/// <summary>
/// Summary description for WordNetEngine.