BotSharp/BotSharp.MachineLearning/Entropy/IO/GisModelReader.cs
2018-07-28 13:01:22 -05:00

348 lines
12 KiB
C#

//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);
}
}
}
}