using System;
using System.Collections;
using SharpUtils;
using System.Text;
using System.Xml.Serialization;
using System.Xml;
using System.Threading;
namespace Neural_Net_Library
{
/// <summary>
/// VALUES STRUCTURE represents all the values that are used for accessing arrays in the library
/// These were originally global variables in the original c++ ( yuk )
/// </summary>
public struct Values
{
/// <summary>
/// standard values for all networks
/// </summary>
public const int NodeValue = 0;
public const int LearningRate = 1;
public const int NodeError = 0;
public const int Weight = 0;
/// <summary>
/// BackPropagation Network Values
/// </summary>
public const int Delta = 1;
public const int Momentum = 2;
/// <summary>
/// Self Organizing Network Values
/// </summary>
public const int Composite = 0;
public const int Row = 1;
public const int Column = 2;
/// <summary>
/// Bidirectional Associative Memory
/// </summary>
public const int LastNodeValue = 1;
/// <summary>
/// return a random value
/// Note: The sleep( 100 ) is added as the Random function is called repeatedly in certain cases and
/// the output is useless on a fast computer so this slows it down enough to make the values acceptable
/// </summary>
/// <param name="dLowerLimit">The lowest acceptable value</param>
/// <param name="UpperLimit">The highest acceptable value</param>
/// <returns></returns>
public static double Random( double dLowerLimit, double dUpperLimit )
{
Thread.Sleep( 100 );
double dNumber = 0.0;
Random temp = new Random();
dNumber = temp.Next( ( int )dLowerLimit, ( int )dUpperLimit );
if( dNumber>0 )
{
dNumber -= temp.NextDouble();
if( dNumber < -1 )
dNumber = -1;
}
else
{
dNumber = temp.NextDouble();
if( dNumber > 1 )
dNumber = 1;
}
return dNumber;
}
}
/// <summary>
/// abstract basic class
/// </summary>
public abstract class Basic
{
private static int nID = -1;
public Basic()
{
nID++;
}
public int ID
{
get
{
return nID;
}
set
{
nID = value;
}
}
}
/// <summary>
/// Basic Link class that provides the links between all nodes in any network.
/// Note the links carry the weight values that are used during the learning calculations
/// </summary>
public abstract class BasicLink : Basic
{
protected ArrayList arrayLinkValues; /// values for the link ( weight value is arraylinkvalues 0 )
protected BasicNode bnInputNode; /// node instance link is coming from
protected BasicNode bnOutputNode; /// node instance link is going to
private DebugLevel debugLevel;
private Logger log;
/// <summary>
/// variables used for loading the links
/// </summary>
private int nInputNodeID;
private int nOutputNodeID;
private int nIdentifier;
/// <summary>
/// link id
/// </summary>
public int Identifier
{
get
{
return nIdentifier;
}
set
{
nIdentifier = value;
}
}
/// <summary>
/// Used only setting up the links on load
/// </summary>
public int InputNodeID
{
get
{
return nInputNodeID;
}
set
{
nInputNodeID = value;
}
}
/// <summary>
/// Used only for setting up the links on load
/// </summary>
public int OutputNodeID
{
get
{
return nOutputNodeID;
}
set
{
nOutputNodeID = value;
}
}
/// <summary>
/// most basic constructor taking only the log file
/// </summary>
/// <param name="log"></param>
public BasicLink( Logger log )
{
arrayLinkValues = new ArrayList();
arrayLinkValues.Add( 0.0 );
Identifier = ID;
debugLevel = new DebugLevel( DebugLevel.currentLevel );
this.log = log;
}
/// <summary>
/// Constructor taking the log file and the number of links to create
/// </summary>
/// <param name="log"></param>
/// <param name="nCount"></param>
public BasicLink( Logger log, int nCount )
{
arrayLinkValues = new ArrayList( nCount );
for( int i=0; i<nCount; i++ )
arrayLinkValues.Add( 0.0 );
Identifier = ID;
debugLevel = new DebugLevel( DebugLevel.currentLevel );
this.log = log;
}
/// <summary>
/// save the link details to a file
/// </summary>
public virtual void Save( XmlWriter xmlWriter )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Basic Link Save Called, link id no " + Identifier.ToString(), ClassName );
}
xmlWriter.WriteStartElement( "BasicLink" );
xmlWriter.WriteElementString( "Identifier", Identifier.ToString() );
for( int i=0; i<arrayLinkValues.Count; i++ )
{
xmlWriter.WriteElementString( "LinkValue", ( ( double )arrayLinkValues[ i ] ).ToString() );
}
xmlWriter.WriteElementString( "InputNodeID", bnInputNode.Identifier.ToString() );
xmlWriter.WriteElementString( "OutputNodeID", bnOutputNode.Identifier.ToString() );
xmlWriter.WriteEndElement();
}
/// <summary>
/// load the link details from a file
/// </summary>
public virtual void Load( XmlReader xmlReader )
{
arrayLinkValues.Clear();
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Basic Link Load Called, link id no " + Identifier.ToString(), ClassName );
}
while( xmlReader.Name != "Identifier" )
{
xmlReader.Read();
}
xmlReader.Read();
Identifier = Int32.Parse( xmlReader.Value );
while( xmlReader.Name != "LinkValue" )
{
xmlReader.Read();
}
xmlReader.Read();
arrayLinkValues.Add( Double.Parse( xmlReader.Value ) );
while( xmlReader.Name != "InputNodeID" )
{
xmlReader.Read();
}
xmlReader.Read();
InputNodeID = Int32.Parse( xmlReader.Value );
while( xmlReader.Name != "OutputNodeID" )
{
xmlReader.Read();
}
xmlReader.Read();
OutputNodeID = Int32.Parse( xmlReader.Value );
}
/// <summary>
/// Get the link value from the array list
/// </summary>
/// <param name="nID">number in the array</param>
/// <returns>the value at the given point in the array or 0</returns>
public virtual double GetLinkValue( int nID )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Getting the Link value for array number " + Identifier.ToString() + " link id no " + ID.ToString() + " value = " + ( ( double )arrayLinkValues[ nID ] ).ToString(), ClassName );
}
if( arrayLinkValues.Count == 0 || nID >= arrayLinkValues.Count )
return 0.0;
return ( double )arrayLinkValues[ nID ];
}
/// <summary>
/// Set the given position in the array list to passed value
/// </summary>
/// <param name="dNewValue">new value</param>
/// <param name="nID">number in the array</param>
public virtual void SetLinkValue( double dNewValue, int nID )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Setting the link value at " + Identifier.ToString() + " from " + ( ( double )arrayLinkValues[ nID ] ).ToString() + " to " + dNewValue.ToString() + " link id no " + ID.ToString(), ClassName );
}
if( arrayLinkValues.Count == 0 || nID >= arrayLinkValues.Count )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Errors ) == true )
{
log.Log( DebugLevelSet.Warning, "Error the id " + Identifier.ToString() + " is greater than the number of link values or the link values array is empty, link id no " + ID.ToString(), ClassName );
}
return;
}
arrayLinkValues[ nID ] = dNewValue;
}
/// <summary>
/// get and set the input node
/// </summary>
public BasicNode InputNode
{
get
{
return bnInputNode;
}
set
{
bnInputNode = value;
}
}
/// <summary>
/// get and set the output node
/// </summary>
public BasicNode OutputNode
{
get
{
return bnOutputNode;
}
set
{
bnOutputNode = value;
}
}
/// <summary>
/// Get the class name
/// </summary>
public string ClassName
{
get
{
return this.ToString();
}
}
/// <summary>
/// get the size of the array of link values
/// </summary>
public int Size
{
get
{
return arrayLinkValues.Count;
}
}
/// <summary>
/// get the value of the input node at the given id
/// </summary>
/// <param name="nID">location of the input value</param>
/// <returns>value stored at location ( nID )</returns>
public virtual double InputValue( int nID )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Getting the Input Value at " + Identifier.ToString() + " link id no " + ID.ToString() + " value = " + InputNode.GetValue( nID ).ToString(), ClassName );
}
return InputNode.GetValue( nID );
}
/// <summary>
/// get the value of the output node at the given id
/// </summary>
/// <param name="nID">location of the output value</param>
/// <returns>value stored at location ( nID )</returns>
public virtual double OutputValue( int nID )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Getting the Output Valuer at " + Identifier.ToString() + " link id no " + ID.ToString() + " value = " + OutputNode.GetValue( nID ).ToString(), ClassName );
}
return OutputNode.GetValue( nID );
}
/// <summary>
/// get the value of the input error at the given id
/// </summary>
/// <param name="nID">location of the error at the given id</param>
/// <returns>value stored at location ( nID )</returns>
public virtual double InputError( int nID )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Getting the Input Error at " + Identifier.ToString() + " link id no " + ID.ToString() + " value = " + ( ( double )InputNode.GetError( nID ) ).ToString(), ClassName );
}
return ( double )InputNode.GetError( nID );
}
/// <summary>
/// get the value of the output error at the given id
/// </summary>
/// <param name="nID">location of the output error</param>
/// <returns>value stored at the location ( nID )</returns>
public virtual double OutputError( int nID )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Getting the Output Error at " + Identifier.ToString() + " linki id no " + ID.ToString() + " value = " + OutputNode.GetError( nID ).ToString(), ClassName );
}
return OutputNode.GetError( nID );
}
/// <summary>
/// get the weighted input value at the given id
/// </summary>
/// <param name="nID">location of the input value</param>
/// <returns>value of the number at the location ( nID ) multiplied by the weight</returns>
public virtual double WeightedInputValue( int nID )
{
double dReturn = 0.0;
if( Values.Weight < arrayLinkValues.Count )
dReturn = bnInputNode.GetValue( nID ) * ( ( double )arrayLinkValues[ Values.Weight ] );
else
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Warning ) == true )
{
log.Log( DebugLevelSet.Warning, "Warning the Values weight value is greater than the link values count returning 0.0, link id no " + ID.ToString(), ClassName );
}
}
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Getting the Weighted Input Value at " + Identifier.ToString() + " link id no " + ID.ToString() + " unweighted value = " + bnInputNode.GetValue( nID ).ToString() + " weighted value = " + dReturn.ToString(), ClassName );
}
return dReturn;
}
/// <summary>
/// get the weighted output value at the given id
/// </summary>
/// <param name="nID">location of the output value</param>
/// <returns>value of the number at the location ( nID ) multiplied by the weight</returns>
public virtual double WeightedOutputValue( int nID )
{
double dReturn = 0.0;
if( Values.Weight < arrayLinkValues.Count )
dReturn = bnOutputNode.GetValue( nID ) * ( ( double )arrayLinkValues[ Values.Weight ] );
else
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Warning ) == true )
{
log.Log( DebugLevelSet.Warning, "Warning the Values Weight value is greater that the link values array count returning 0.0, link id no " + ID.ToString(), ClassName );
}
}
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Getting the Weighted Output value at " + Identifier.ToString() + " link id no " + ID.ToString() + " unweighted value = " + bnOutputNode.GetValue( nID ).ToString() + " weighted value = " + dReturn.ToString(), ClassName );
}
return dReturn;
}
/// <summary>
/// get the wieghted output error at the given id
/// </summary>
/// <param name="nID">location of the output error</param>
/// <returns>value of the number at the location ( nID ) multiplied by the weight</returns>
public virtual double WeightedOutputError( int nID )
{
double dReturn = 0.0;
if( Values.Weight < arrayLinkValues.Count )
dReturn = bnOutputNode.GetError( nID ) * ( ( double )arrayLinkValues[ Values.Weight ] );
else
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Warning ) == true )
{
log.Log( DebugLevelSet.Warning, "Warning the Values Weight value is greater that the link values array count returning 0.0, link id no " + Identifier.ToString(), ClassName );
}
}
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Getting the Weighted Output Error value at " + Identifier.ToString() + " link id no " + Identifier.ToString() + " unweighted value = " + bnOutputNode.GetError( nID ).ToString() + " weighted value = " + dReturn.ToString(), ClassName );
}
return dReturn;
}
/// <summary>
/// get the weighted input error at the given id
/// </summary>
/// <param name="nID">location of the input error</param>
/// <returns>value of the number at the location ( nID ) multiplied by the wieght</returns>
public virtual double WeightedInputError( int nID )
{
double dReturn = 0.0;
if( Values.Weight < arrayLinkValues.Count )
dReturn = bnInputNode.GetError( nID ) * ( ( double )arrayLinkValues[ Values.Weight ] );
else
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Warning ) == true )
{
log.Log( DebugLevelSet.Warning, "Warning the Values Weight value is greater than the link values array count returning 0.0, link id no " + Identifier.ToString(), ClassName );
}
}
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Getting the Weighted Input Error value at " + Identifier.ToString() + " link id no " + Identifier.ToString() + " unweighted value = " + bnInputNode.GetError( nID ).ToString() + " weighted value = " + dReturn.ToString(), ClassName );
}
return dReturn;
}
/// <summary>
/// Update the weight for this basic Link
/// </summary>
/// <param name="dNewValue">new weight value for the link</param>
public virtual void UpdateWeight( double dNewValue )
{
if( Values.Weight < arrayLinkValues.Count )
{
double dTemp = ( double )arrayLinkValues[ Values.Weight ];
dTemp += dNewValue;
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Updating the Weight for this basic link id no " + Identifier.ToString() + " from = " + ( ( double )arrayLinkValues[ Values.Weight ]).ToString() + " to = " + dTemp.ToString(), ClassName );
}
arrayLinkValues[ Values.Weight ] = dTemp;
}
}
}
/// <summary>
/// Generic definition for an bias node
/// </summary>
public class Bias
{
private DebugLevel debugLevel;
private Logger log;
private ArrayList arrayBiasValues;
/// <summary>
/// basic constructor taking only the logger
/// </summary>
/// <param name="log">xml log file that info is written too</param>
public Bias( Logger log )
{
this.log = log;
arrayBiasValues = new ArrayList();
debugLevel = new DebugLevel( DebugLevel.currentLevel );
arrayBiasValues.Add( 1.0 );
}
/// <summary>
/// constructor taking the logger and the bias value ( rarely used as bias is usually 1.0 )
/// </summary>
/// <param name="log">xml log file that info is written too</param>
/// <param name="dBias">bias to be applied</param>
public Bias( Logger log, double dBias )
{
arrayBiasValues = new ArrayList();
if( dBias == 0.0 )
dBias = 1.0;
arrayBiasValues.Add( dBias );
debugLevel = new DebugLevel( DebugLevel.currentLevel );
this.log = log;
}
/// <summary>
/// get the original bias
/// </summary>
/// <returns>bias value normally one</returns>
public double GetOriginalBias()
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Returning original bias of " + arrayBiasValues[ 0 ].ToString(), ClassName );
}
return ( double )arrayBiasValues[ 0 ];
}
/// <summary>
/// get the bias at a given id
/// </summary>
/// <param name="nID">location of the bias value</param>
/// <returns>value at the given location ( nID )</returns>
public double GetBiasAt( int nID )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Setting the Bias at " + nID.ToString() + " to " + ( ( double )arrayBiasValues[ 0 ] ).ToString(), ClassName );
}
if( nID < arrayBiasValues.Count )
{
return ( double )arrayBiasValues[ nID ];
}
else
{
if( debugLevel.TestDebugLevel( DebugLevelSet.WarningsAndErrors ) == true )
{
log.Log( DebugLevelSet.WarningsAndErrors, "Warning the id passed to the array for getting the bias " + nID.ToString() + " is greater than the number of elements " + arrayBiasValues.Count.ToString() );
}
}
return 0.0;
}
/// <summary>
/// set the bias value at the default location
/// </summary>
/// <param name="dBias">bias value to set</param>
public void SetBias( double dBias )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Setting the bias from " + ( ( double )arrayBiasValues[ 0 ] ).ToString() + " to " + dBias.ToString() );
}
arrayBiasValues[ 0 ] = dBias;
}
/// <summary>
/// set the bias value at the given location
/// </summary>
/// <param name="nID">location of the bias value to set</param>
/// <param name="dBias">new bias value</param>
public void SetBiasAt( int nID, double dBias )
{
if( nID < arrayBiasValues.Count )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Setting the bias at " + nID.ToString() + " from " + ( ( double )arrayBiasValues[ nID ] ).ToString() + " to " + dBias.ToString() );
}
arrayBiasValues[ nID ] = dBias;
}
else
{
if( debugLevel.TestDebugLevel( DebugLevelSet.WarningsAndErrors ) == true )
{
log.Log( DebugLevelSet.WarningsAndErrors, "Warning the id passed to the array for setting the bias " + nID.ToString() + " is greater than the number of elements " + arrayBiasValues.Count.ToString() );
}
}
}
/// <summary>
/// get the class name
/// </summary>
public string ClassName
{
get
{
return this.ToString();
}
}
/// <summary>
/// save the current bias node
/// </summary>
/// <param name="xmlWriter">xml writer to the save file</param>
public virtual void Save( XmlWriter xmlWriter )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Save called in bias node", ClassName );
}
xmlWriter.WriteStartElement( "Bias" );
for( int i=0; i<arrayBiasValues.Count; i++ )
{
xmlWriter.WriteElementString( "BiasValue", ( ( double )arrayBiasValues[ i ] ).ToString() );
}
xmlWriter.WriteEndElement();
}
/// <summary>
/// reload the saved bias node
/// </summary>
/// <param name="xmlReader">xml reader to the file load the data from</param>
public virtual void Load( XmlReader xmlReader )
{
while( xmlReader.Name != "Bias" )
{
xmlReader.Read();
}
bool bBreak = false;
for( ;; )
{
switch( xmlReader.NodeType )
{
case XmlNodeType.Element:
{
switch( xmlReader.Name )
{
case "BiasValue":
{
xmlReader.Read();
arrayBiasValues.Add( Double.Parse( xmlReader.Value ) ); break;
}
}
} break;
case XmlNodeType.EndElement:
{
switch( xmlReader.Name )
{
case "Bias": bBreak = true; break;
}
} break;
}
if( bBreak == true )
break;
xmlReader.Read();
}
}
}
/// <summary>
/// basic node class, form the base class for all nodes in all networks
/// </summary>
public class BasicNode : Basic
{
private ArrayList arrayNodeValues; /// double values
private ArrayList arrayNodeErrors; /// double values
private ArrayList arrayInputLinks; /// Basic links
private ArrayList arrayOutputLinks; /// Basic links
private DebugLevel debugLevel;
private Logger log;
/// <summary>
/// use the bias or not default not. The bias is static as it is applied to the
/// network as a whole and not to individual nodes
/// </summary>
private static bool bUseBias = false;
private Bias bias;
private int nIdentifier;
/// <summary>
/// node id
/// </summary>
public int Identifier
{
get
{
return nIdentifier;
}
set
{
nIdentifier = value;
}
}
/// <summary>
/// set the optional bias
/// </summary>
public bool UseBias
{
get
{
return bUseBias;
}
set
{
bUseBias = value;
}
}
/// <summary>
/// get the current bias
/// </summary>
public Bias GetBias
{
get
{
return bias;
}
}
/// <summary>
/// most basic constructor only takes the log file object
/// </summary>
/// <param name="slog">log file for storing info</param>
public BasicNode( Logger slog )
{
bias = new Bias( slog );
arrayNodeValues = new ArrayList();
arrayNodeValues.Add( 0.0 );
arrayNodeErrors = new ArrayList();
arrayNodeErrors.Add( 0.0 );
arrayInputLinks = new ArrayList();
arrayOutputLinks = new ArrayList();
Identifier = ID;
debugLevel = new DebugLevel( DebugLevel.currentLevel );
log = slog;
}
/// <summary>
/// constructor taking the log and the sizes for the values and errors
/// </summary>
/// <param name="slog">log file for writing info</param>
/// <param name="nodeValuesSize">initial size of the values array</param>
/// <param name="nodeErrorsSize">initial size of the errors array</param>
public BasicNode( Logger slog, int nodeValuesSize, int nodeErrorsSize )
{
bias = new Bias( slog );
arrayNodeValues = new ArrayList( nodeValuesSize );
for( int i=0; i<nodeValuesSize; i++ )
arrayNodeValues.Add( 0.0 );
arrayNodeErrors = new ArrayList( nodeErrorsSize );
for( int i=0; i<nodeErrorsSize; i++ )
arrayNodeErrors.Add( 0.0 );
arrayInputLinks = new ArrayList();
arrayOutputLinks = new ArrayList();
Identifier = ID;
debugLevel = new DebugLevel( DebugLevel.currentLevel );
log = slog;
}
/// <summary>
/// values stored for this node
/// </summary>
public ArrayList NodeValues
{
get
{
return arrayNodeValues;
}
}
/// <summary>
/// error values for this node
/// </summary>
public ArrayList NodeErrors
{
get
{
return arrayNodeErrors;
}
}
/// <summary>
/// input links for this node
/// </summary>
public ArrayList InputLinks
{
get
{
return arrayInputLinks;
}
}
/// <summary>
/// output links for this node
/// </summary>
public ArrayList OutputLinks
{
get
{
return arrayOutputLinks;
}
}
/// <summary>
/// run this node ( no implementation as it is meant to be overridden
/// </summary>
/// <param name="nMode"></param>
public virtual void Run( int nMode )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Run called in basic node", ClassName );
}
}
/// <summary>
/// run this node ( no implementation as it is meant to be overridden ) ( pretty much obsolete already )
/// </summary>
/// <param name="nMode"></param>
/// <param name="dBias"></param>
public virtual void Run( int nMode, double dBias )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, " Run with bias called in basic node", ClassName );
}
}
/// <summary>
/// run the learning algorithm for the node ( no implementation as it is meant to be overridden
/// </summary>
/// <param name="nMode"></param>
public virtual void Learn( int nMode )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Learn Called in basic node", ClassName );
}
}
/// <summary>
/// save the current node
/// </summary>
/// <param name="xmlWriter">xmlWriter to the file to write too</param>
public virtual void Save( XmlWriter xmlWriter )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Save called in basic node", ClassName );
}
xmlWriter.WriteStartElement( "BasicNode" );
xmlWriter.WriteElementString( "Identifier", Identifier.ToString() );
for( int i=0; i<arrayNodeValues.Count; i++ )
{
xmlWriter.WriteElementString( "NodeValue", ( ( double )arrayNodeValues[ i ] ).ToString() );
}
for( int i=0; i<arrayNodeErrors.Count; i++ )
{
xmlWriter.WriteElementString( "NodeError", ( ( double )arrayNodeErrors[ i ] ).ToString() );
}
bias.Save( xmlWriter );
xmlWriter.WriteEndElement();
}
/// <summary>
/// reload the node
/// </summary>
/// <param name="xmlReader">xml reader to the file to read from</param>
public virtual void Load( XmlReader xmlReader )
{
arrayNodeValues.Clear();
arrayNodeErrors.Clear();
arrayInputLinks.Clear();
arrayOutputLinks.Clear();
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Load called in basic node", ClassName );
}
while( xmlReader.Name != "Identifier" )
{
xmlReader.Read();
}
xmlReader.Read();
Identifier = Int32.Parse( xmlReader.Value );
bool bBreak = false;
/// can be any number of node values not just one
for( ;; )
{
xmlReader.Read();
switch( xmlReader.NodeType )
{
case XmlNodeType.Element:
{
switch( xmlReader.Name )
{
case "NodeValue":
{
xmlReader.Read();
arrayNodeValues.Add( Double.Parse( xmlReader.Value ) ); break;
}
case "NodeError": bBreak = true; break;
}
} break;
}
if( bBreak == true )
break;
}
/// should now be on Node error
bBreak = false;
for( ;; )
{
switch( xmlReader.NodeType )
{
case XmlNodeType.Element:
{
switch( xmlReader.Name )
{
case "NodeError":
{
xmlReader.Read();
if( xmlReader.Value == "0" )
arrayNodeErrors.Add( 0.0 );
else if( xmlReader.Value == "1" )
arrayNodeErrors.Add( 1.0 );
else
arrayNodeErrors.Add( Double.Parse( xmlReader.Value ) ); break;
}
}
} break;
case XmlNodeType.EndElement:
{
switch( xmlReader.Name )
{
case "NodeError": bBreak = true; break;
}
} break;
}
if( bBreak == true )
break;
xmlReader.Read();
}
bias.Load( xmlReader );
/// links data is not loaded here as the link contains all the needed information
}
/// <summary>
/// get the value from the array node values at the given id
/// </summary>
/// <param name="nID">location of the value ( nID )</param>
/// <returns>value at the given location ( nID )</returns>
public virtual double GetValue( int nID )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Get value called in basic node", ClassName );
}
if( arrayNodeValues.Count == 0 || nID >= arrayNodeValues.Count )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Warning ) == true )
{
log.Log( DebugLevelSet.Warning, "The id passed to basic node " + Identifier.ToString() + " is greater than the array node values count, returning 0.0", ClassName );
}
return 0.0;
}
return ( double )arrayNodeValues[ nID ];
}
/// <summary>
/// set the value at the given id
/// </summary>
/// <param name="nID">location of the value to set</param>
/// <param name="dNewValue">value to be set too</param>
public virtual void SetValue( int nID, double dNewValue )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Setting the value for id " + Identifier.ToString() + " to " + dNewValue.ToString(), ClassName );
}
if( arrayNodeValues.Count == 0 || nID >= arrayNodeValues.Count )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Warning ) == true )
{
log.Log( DebugLevelSet.Warning, "The id passed to basic node setvalue is greater than the array count ", ClassName );
}
return;
}
arrayNodeValues[ nID ] = dNewValue;
}
/// <summary>
/// get the error value at the passed in id
/// </summary>
/// <param name="nID">location of the error to get</param>
/// <returns>value of the error at the given location ( nID )</returns>
public virtual double GetError( int nID )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Getting the error value at " + Identifier.ToString() + " for basic node", ClassName );
}
if( arrayNodeErrors.Count == 0 || nID >= arrayNodeErrors.Count )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Warning ) == true )
{
log.Log( DebugLevelSet.Warning, "The id passed to basic node get error is greater than the array count returning 0.0", ClassName );
}
return 0.0;
}
return ( double )arrayNodeErrors[ nID ];
}
/// <summary>
/// set the error at the given id
/// </summary>
/// <param name="nID">location of the error to set</param>
/// <param name="dNewValue">value of the new error</param>
public virtual void SetError( int nID, double dNewValue )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Setting the error value for basic node at " + Identifier.ToString() + " to " + dNewValue.ToString(), ClassName );
}
if( arrayNodeErrors.Count == 0 || nID >= arrayNodeErrors.Count )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Warning ) == true )
{
log.Log( DebugLevelSet.Warning, "The id passed to basic node set error is greater than the array count", ClassName );
}
return;
}
arrayNodeErrors[ nID ] = dNewValue;
}
/// <summary>
/// get the class name
/// </summary>
public string ClassName
{
get
{
return this.ToString();
}
}
/// <summary>
/// create a link to a node
/// </summary>
/// <param name="bnToNode">node to create a link to</param>
/// <param name="blLink">Basic link object to create the link</param>
public void CreateLink( BasicNode bnToNode, BasicLink blLink )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Creating a link between node " + bnToNode.Identifier.ToString() + " and link " + blLink.Identifier.ToString(), ClassName );
}
arrayOutputLinks.Add( blLink );
bnToNode.InputLinks.Add( blLink );
blLink.InputNode = this;
blLink.OutputNode = bnToNode;
}
/// <summary>
/// disconnect a connection from the arrays
/// </summary>
/// <param name="bnFromNode">node to disconnect from</param>
/// <param name="bnToNode">node connected to</param>
/// <returns>true on success</returns>
public bool Disconnect( BasicNode bnFromNode, BasicNode bnToNode )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Disconnecting the connection between " + bnFromNode.ID.ToString() + " to " + bnToNode.ID.ToString(), ClassName );
}
ArrayList tempList = bnFromNode.OutputLinks;
bool bFound = false;
/// see if it is possible to find the connection to the to node
int n=0;
for( ; n<tempList.Count; n++ )
{
if( ( ( BasicLink )tempList[ n ] ).OutputNode.Equals( bnToNode ) == true )
{
bFound = true;
break;
}
}
if( bFound == true )
{
/// from the current node remove the input then remove the node
( ( BasicLink )tempList[ n ] ).OutputNode.arrayInputLinks.Remove( tempList[ n ] );
tempList.RemoveAt( n );
return true;
}
else
return false;
}
/// <summary>
/// print out info
/// </summary>
public virtual void Print()
{
}
}
/// <summary>
/// the basic network class
/// Base class for most networks
/// </summary>
public abstract class BasicNetwork
{
private ArrayList arrayNodes; /// array of basicnodes
private ArrayList arrayLinks;
private DebugLevel debugLevel;
private Logger log;
private double dLearningRate;
/// <summary>
/// current learning rate
/// </summary>
public double LearningRate
{
get
{
return dLearningRate;
}
set
{
dLearningRate = value;
}
}
/// <summary>
/// allow the code to set if the bias should be used
/// </summary>
public bool UseBias
{
set
{
if( arrayNodes.Count > 0 )
{
( ( BasicNode )arrayNodes[ 0 ] ).UseBias = value;
}
}
}
/// <summary>
/// most basic constructor taking only the logger
/// </summary>
/// <param name="log">log file object</param>
public BasicNetwork( Logger log )
{
arrayNodes = new ArrayList();
arrayLinks = new ArrayList();
debugLevel = new DebugLevel( DebugLevel.currentLevel );
this.log = log;
}
/// <summary>
/// constructor taking the logger object the number of nodes and the number of links
/// </summary>
/// <param name="log">logger</param>
/// <param name="nNodesCount">number of nodes to create</param>
/// <param name="nLinksCount">number of links to create</param>
public BasicNetwork( Logger log, int nNodesCount, int nLinksCount )
{
arrayNodes = new ArrayList( nNodesCount );
arrayLinks = new ArrayList( nLinksCount );
debugLevel = new DebugLevel( DebugLevel.currentLevel );
this.log = log;
}
/// <summary>
/// add a new node to the network
/// </summary>
/// <param name="node">node to be added</param>
public virtual void AddNode( BasicNode node )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Adding a new neuron to basic network" );
}
arrayNodes.Add( node );
}
/// <summary>
/// add a new link to the network
/// </summary>
/// <param name="link">link to be added</param>
public virtual void AddLink( BasicLink link )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Adding a new link to the basic network" );
}
arrayLinks.Add( link );
}
/// <summary>
/// remove the node at the specified location
/// </summary>
/// <param name="nID">location of the node to be removed</param>
public virtual void RemoveNodeAt( int nID )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Removing a node from basic network at " + nID.ToString() );
}
if( nID <= arrayNodes.Count )
{
arrayNodes.RemoveAt( nID );
}
else
{
if( debugLevel.TestDebugLevel( DebugLevelSet.WarningsAndErrors ) == true )
{
log.Log( DebugLevelSet.WarningsAndErrors, "Warning attempt to remove a node from basic network " + nID.ToString() + " when there are only " + arrayNodes.Count.ToString() + " in the array " );
}
}
}
/// <summary>
/// remove the link at the specified location
/// </summary>
/// <param name="nID">location of the link to be removed</param>
public virtual void RemoveLinkAt( int nID )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Removing a link from the basic network at " + nID.ToString() );
}
if( nID <= arrayNodes.Count )
{
arrayNodes.RemoveAt( nID );
}
else
{
if( debugLevel.TestDebugLevel( DebugLevelSet.WarningsAndErrors ) == true )
{
log.Log( DebugLevelSet.WarningsAndErrors, "Warning attemot to remove a node from basic network " + nID.ToString() + " when there are only " + arrayLinks.Count.ToString() + " in the array " );
}
}
}
/// <summary>
/// get the node at the given location
/// </summary>
/// <param name="nID">location of the node to retreive</param>
/// <returns>node at location ( nID )</returns>
public BasicNode GetNodeAt( int nID )
{
if( arrayNodes.Count >= nID )
return ( BasicNode )arrayNodes[ nID ];
else
{
if( debugLevel.TestDebugLevel( DebugLevelSet.WarningsAndErrors ) == true )
{
log.Log( DebugLevelSet.WarningsAndErrors, "Warning attempt to get a node from basic network " + nID.ToString() + " when there are only " + arrayNodes.Count.ToString() + " in the array " );
}
}
return null;
}
/// <summary>
/// ge the link at the given location
/// </summary>
/// <param name="nID">location of the link to retreive</param>
/// <returns>link at location ( nID )</returns>
public BasicLink GetLinkAt( int nID )
{
if( arrayLinks.Count >= nID )
return ( BasicLink )arrayLinks[ nID ];
else
{
if( debugLevel.TestDebugLevel( DebugLevelSet.WarningsAndErrors ) == true )
{
log.Log( DebugLevelSet.WarningsAndErrors, "Warning attempt to get a link from basic network " + nID.ToString() + " when there are only " + arrayLinks.Count.ToString() + " in the array " );
}
}
return null;
}
/// <summary>
/// allow access to the Nodes
/// </summary>
public ArrayList Nodes
{
get
{
return arrayNodes;
}
}
/// <summary>
/// allow access to the links
/// </summary>
public ArrayList Links
{
get
{
return arrayLinks;
}
}
protected abstract void CreateNetwork();
/// <summary>
/// save the current network
/// </summary>
/// <param name="xmlWriter">sml writer for the file to save to</param>
public virtual void Save( XmlWriter xmlWriter )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Save Node Links called for basic network ", ClassName );
}
xmlWriter.WriteStartElement( "BasicNetwork" );
for( int i=0; i<arrayNodes.Count; i++ )
{
( ( BasicNode )arrayNodes[ i ] ).Save( xmlWriter );
}
for( int i=0; i<arrayLinks.Count; i++ )
{
( ( BasicLink )arrayLinks[ i ] ).Save( xmlWriter );
}
xmlWriter.WriteEndElement();
}
/// <summary>
/// example of the load function. Can't implement load here as the basic Link class is abstract
/// </summary>
/// <param name="xmlReader"></param>
public virtual void Load( XmlReader xmlReader )
{
/*
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Load Node links called for basic network", ClassName );
}
arrayNodes.Clear();
arrayLinks.Clear();
/// can be any number of basic nodes not just one
for( ;; )
{
xmlReader.Read();
switch( xmlReader.NodeType )
{
case XmlNodeType.Element:
{
switch( xmlReader.Name )
{
case "BasicNode":
{
BasicNode temp = new BasicNode( log );
temp.Load( xmlReader );
arrayNodes.Add( temp );
}
case "BasicLink": bBreak = true; break;
}
} break;
}
if( bBreak == true )
break;
}
/// should now be on Basic Link
bBreak = false;
for( ;; )
{
switch( xmlReader.NodeType )
{
case XmlNodeType.Element:
{
switch( xmlReader.Name )
{
case "BasicLink":
{
BasicLink temp = new BasicLink();
temp.Load( xmlReader );
arrayLinks.Add( temp );
}
}
} break;
case XmlNodeType.EndElement:
{
switch( xmlReader.Name )
{
case "BasicNetwork": bBreak = true; break;
}
} break;
}
if( bBreak == true )
break;
xmlReader.Read();
}
*/
}
public string ClassName
{
get
{
return this.ToString();
}
}
/// <summary>
/// perform a series of operations on the nodes ( usually all of them )
/// </summary>
/// <param name="nMode"></param>
public virtual void Epoch()
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "Epoch called for basic network ", ClassName );
}
}
/// <summary>
/// set the value for the node at the given index
/// </summary>
/// <param name="nID"></param>
/// <param name="dNewVal"></param>
public virtual void SetValue( int nID, double dNewVal )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "set value called for basic network ", ClassName );
}
if( nID >= this.Nodes.Count )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.WarningsAndErrors ) == true )
{
log.Log( DebugLevelSet.WarningsAndErrors, "Warning the id passed to set value in Basic network is higher than the node count, returning without setting the value", ClassName );
}
return;
}
this.GetNodeAt( nID ).SetValue( Values.NodeValue, dNewVal );
}
/// <summary>
/// set the values for the nodes to the values in the pattern
/// </summary>
/// <param name="pattern">a Pattern derived class containing the input values for the nodes</param>
public virtual void SetValue( Pattern pattern )
{
if( debugLevel.TestDebugLevel( DebugLevelSet.Progress ) == true )
{
log.Log( DebugLevelSet.Progress, "set value called for basic network ", ClassName );
}
for( int i=0; i<pattern.InSet.Count; i++ )
{
this.GetNodeAt( i ).SetValue( Values.NodeValue, pattern.InputValue( i ) );
}
}
}
/// <summary>
/// The basic neuron class models the minimum needed for a neuron and is abstract to force inheritance
/// so that each network can add what is required.
/// </summary>
public abstract class BasicNeuron
{
private BasicNode basicNodeInputNodeOne;
private BasicNode basicNodeInputNodeTwo;
private DebugLevel debugLevel;
private Logger log;
public BasicNode InputNodeOne
{
get
{
return basicNodeInputNodeOne;
}
set
{
basicNodeInputNodeOne = value;
}
}
public BasicNode InputNodeTwo
{
get
{
return basicNodeInputNodeTwo;
}
set
{
basicNodeInputNodeTwo = value;
}
}
/// <summary>
/// constructor
/// </summary>
/// <param name="log"></param>
/// <param name="basicInputNodeOne"></param>
/// <param name="basicInputNodeTwo"></param>
/// <param name="biasBiasNode"></param>
public BasicNeuron( Logger log, BasicNode basicInputNodeOne, BasicNode basicInputNodeTwo )
{
InputNodeOne = basicInputNodeOne;
InputNodeTwo = basicInputNodeTwo;
debugLevel = new DebugLevel( DebugLevel.currentLevel );
this.log = log;
}
/// <summary>
/// each neuron will need to define how to build it's own links
/// </summary>
public abstract void BuildLinks();
public string ClassName
{
get
{
return this.ToString();
}
}
public string Data
{
get
{
StringBuilder strString = new StringBuilder();
strString.Append( "Basic Neuron Values : Input Node One Values = " );
for( int i=0; i<InputNodeOne.NodeValues.Count; i++ )
{
strString.Append( " value " + i.ToString() + " = " + InputNodeOne.NodeValues[ i ].ToString() );
}
strString.Append( " : Node Errors = " );
for( int i=0; i<InputNodeOne.NodeErrors.Count; i++ )
{
strString.Append( " value " + i.ToString() + " = " + InputNodeOne.NodeErrors[ i ].ToString() );
}
strString.Append( " : Node Input Links = " );
for( int i=0; i<InputNodeOne.InputLinks.Count; i++ )
{
strString.Append( " value " + i.ToString() + " = " + InputNodeOne.InputLinks[ i ].ToString() );
}
strString.Append( " : Node Output Links = " );
for( int i=0; i<InputNodeOne.OutputLinks.Count; i++ )
{
strString.Append( " value " + i.ToString() + " = " + InputNodeOne.OutputLinks[ i ].ToString() );
}
return strString.ToString();
}
}
/// <summary>
/// save the current data
/// </summary>
/// <param name="xmlWriter"></param>
public virtual void Save( XmlWriter xmlWriter )
{
xmlWriter.WriteStartElement( "BasicNeuron" );
basicNodeInputNodeOne.Save( xmlWriter );
basicNodeInputNodeTwo.Save( xmlWriter );
xmlWriter.WriteEndElement();
}
/// <summary>
/// reload saved data
/// </summary>
/// <param name="xmlReader"></param>
public virtual void Load( XmlReader xmlReader )
{
while( xmlReader.Name != "BasicNode" )
{
xmlReader.Read();
}
basicNodeInputNodeOne.Load( xmlReader );
while( xmlReader.Name != "BasicNode" )
{
xmlReader.Read();
}
basicNodeInputNodeTwo.Load( xmlReader );
}
}
}