262 lines
6.7 KiB
MQL5
262 lines
6.7 KiB
MQL5
|
//|------------------------------------------------------------------+
|
||
|
//| CSOMNode.mqh |
|
||
|
//| Copyright (c) 2018, Marketeer |
|
||
|
//| https://www.mql5.com/en/users/marketeer |
|
||
|
//| https://www.mql5.com/ru/articles/5472/ |
|
||
|
//| https://www.mql5.com/ru/articles/5473/ |
|
||
|
//|------------------------------------------------------------------+
|
||
|
|
||
|
class CSOMNode
|
||
|
{
|
||
|
protected:
|
||
|
int x, y; // coordinates in hosting map
|
||
|
|
||
|
double m_weights[];
|
||
|
int m_dimension;
|
||
|
double m_distance;
|
||
|
|
||
|
int m_hitCount;
|
||
|
double m_sum[];
|
||
|
double m_sumP2[];
|
||
|
double m_mse;
|
||
|
long m_updateCount;
|
||
|
int m_cluster;
|
||
|
bool m_selected;
|
||
|
double m_output;
|
||
|
|
||
|
static uint defaultDimension;
|
||
|
static int dimensionMax;
|
||
|
static ulong dimensionBitMask;
|
||
|
|
||
|
public:
|
||
|
CSOMNode(const uint dim = 0);
|
||
|
~CSOMNode();
|
||
|
void InitNode(const int x0, const int y0);
|
||
|
int GetX() const { return x; }
|
||
|
int GetY() const { return y; }
|
||
|
double GetWeight(const int index) const;
|
||
|
void GetCodeVector(double &vector[]) const;
|
||
|
double GetDistance() const;
|
||
|
double CalculateDistance(const double &vector[]) const;
|
||
|
double CalculateDistance(const CSOMNode *other) const;
|
||
|
double CalculateOutput(const double &vector[]);
|
||
|
static void SetFeatureMask(const int dim = 0, const ulong bitmask = 0);
|
||
|
void AdjustWeights(const double &vector[], const double learning_rate, const double influence);
|
||
|
void SetDimension(const int dimension);
|
||
|
void SetDistance(const double d);
|
||
|
void Save(const int handle) const;
|
||
|
void Load(const int handle);
|
||
|
|
||
|
void RegisterPatternHit(const double &vector[]);
|
||
|
int GetHitsCount() const;
|
||
|
void SetHitsCount(const int n) { m_hitCount = n; }
|
||
|
double GetHitsMean(const int plane) const;
|
||
|
double GetHitsDeviation(const int plane) const;
|
||
|
double GetMSE() const;
|
||
|
long GetUpdateCount() const;
|
||
|
void SetCluster(int index);
|
||
|
int GetCluster() const;
|
||
|
void Select() { m_selected = !m_selected; }
|
||
|
bool IsSelected() const { return m_selected; }
|
||
|
double GetOutput() const { return m_output; }
|
||
|
|
||
|
static void FactoryInit(const uint dim);
|
||
|
};
|
||
|
|
||
|
static uint CSOMNode::defaultDimension = 0;
|
||
|
static int CSOMNode::dimensionMax = 0;
|
||
|
static ulong CSOMNode::dimensionBitMask = 0;
|
||
|
|
||
|
static void CSOMNode::FactoryInit(const uint dim)
|
||
|
{
|
||
|
defaultDimension = dim;
|
||
|
}
|
||
|
|
||
|
void CSOMNode::CSOMNode(const uint dim = 0)
|
||
|
{
|
||
|
x = y = 0;
|
||
|
m_distance = 0.0;
|
||
|
m_hitCount = 0;
|
||
|
m_updateCount = 0;
|
||
|
m_mse = 0;
|
||
|
m_cluster = 0;
|
||
|
m_selected = false;
|
||
|
m_output = 0;
|
||
|
SetDimension(dim ? dim : defaultDimension);
|
||
|
}
|
||
|
|
||
|
void CSOMNode::InitNode(const int x0, const int y0)
|
||
|
{
|
||
|
x = x0;
|
||
|
y = y0;
|
||
|
ArrayResize(m_weights, m_dimension);
|
||
|
ArrayResize(m_sum, m_dimension);
|
||
|
ArrayResize(m_sumP2, m_dimension);
|
||
|
ArrayInitialize(m_sum, 0);
|
||
|
ArrayInitialize(m_sumP2, 0);
|
||
|
|
||
|
for(int i = 0; i < m_dimension; i++)
|
||
|
{
|
||
|
m_weights[i] = 2.0 * rand() / 32768 - 1.0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CSOMNode::~CSOMNode()
|
||
|
{
|
||
|
ArrayResize(m_weights, 0);
|
||
|
ArrayResize(m_sum, 0);
|
||
|
ArrayResize(m_sumP2, 0);
|
||
|
}
|
||
|
|
||
|
double CSOMNode::GetWeight(const int weight_index) const
|
||
|
{
|
||
|
if(weight_index >= 0 && weight_index < m_dimension)
|
||
|
return m_weights[weight_index];
|
||
|
else
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void CSOMNode::GetCodeVector(double &vector[]) const
|
||
|
{
|
||
|
ArrayCopy(vector, m_weights);
|
||
|
}
|
||
|
|
||
|
static void CSOMNode::SetFeatureMask(const int dim = 0, const ulong bitmask = 0)
|
||
|
{
|
||
|
dimensionMax = dim;
|
||
|
dimensionBitMask = bitmask;
|
||
|
}
|
||
|
|
||
|
double CSOMNode::CalculateDistance(const double &vector[]) const
|
||
|
{
|
||
|
double distSqr = 0;
|
||
|
if(dimensionMax <= 0 || dimensionMax > m_dimension) dimensionMax = m_dimension;
|
||
|
for(int i = 0; i < dimensionMax; i++)
|
||
|
{
|
||
|
if(dimensionBitMask == 0 || ((dimensionBitMask & (1 << i)) != 0))
|
||
|
{
|
||
|
distSqr += (vector[i] - m_weights[i]) * (vector[i] - m_weights[i]);
|
||
|
}
|
||
|
}
|
||
|
return distSqr;
|
||
|
}
|
||
|
|
||
|
double CSOMNode::CalculateDistance(const CSOMNode *other) const
|
||
|
{
|
||
|
double vector[];
|
||
|
other.GetCodeVector(vector);
|
||
|
return CalculateDistance(vector);
|
||
|
}
|
||
|
|
||
|
double CSOMNode::CalculateOutput(const double &vector[])
|
||
|
{
|
||
|
m_output = CalculateDistance(vector);
|
||
|
return m_output;
|
||
|
}
|
||
|
|
||
|
void CSOMNode::AdjustWeights(const double &vector[], const double learning_rate, const double influence)
|
||
|
{
|
||
|
m_updateCount++;
|
||
|
for(int i = 0; i < m_dimension; i++)
|
||
|
{
|
||
|
m_weights[i] += learning_rate * influence * (vector[i] - m_weights[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CSOMNode::SetDimension(const int dimension)
|
||
|
{
|
||
|
m_dimension = dimension;
|
||
|
ArrayResize(m_weights, m_dimension);
|
||
|
}
|
||
|
|
||
|
void CSOMNode::SetDistance(const double d)
|
||
|
{
|
||
|
m_distance = d;
|
||
|
}
|
||
|
|
||
|
double CSOMNode::GetDistance() const
|
||
|
{
|
||
|
return m_distance;
|
||
|
}
|
||
|
|
||
|
void CSOMNode::Save(const int handle) const
|
||
|
{
|
||
|
FileWriteInteger(handle, x);
|
||
|
FileWriteInteger(handle, y);
|
||
|
FileWriteArray(handle, m_weights);
|
||
|
|
||
|
FileWriteDouble(handle, m_distance);
|
||
|
FileWriteInteger(handle, m_hitCount);
|
||
|
FileWriteArray(handle, m_sum);
|
||
|
FileWriteArray(handle, m_sumP2);
|
||
|
FileWriteDouble(handle, m_mse);
|
||
|
FileWriteInteger(handle, m_cluster);
|
||
|
}
|
||
|
|
||
|
void CSOMNode::Load(const int handle)
|
||
|
{
|
||
|
x = FileReadInteger(handle);
|
||
|
y = FileReadInteger(handle);
|
||
|
FileReadArray(handle, m_weights, 0, m_dimension);
|
||
|
|
||
|
m_distance = FileReadDouble(handle);
|
||
|
m_hitCount = FileReadInteger(handle);
|
||
|
FileReadArray(handle, m_sum, 0, m_dimension);
|
||
|
FileReadArray(handle, m_sumP2, 0, m_dimension);
|
||
|
m_mse = FileReadDouble(handle);
|
||
|
m_cluster = FileReadInteger(handle);
|
||
|
}
|
||
|
|
||
|
void CSOMNode::RegisterPatternHit(const double &vector[])
|
||
|
{
|
||
|
m_hitCount++;
|
||
|
double e = 0;
|
||
|
for(int i = 0; i < m_dimension; i++) // dimensionMax
|
||
|
{
|
||
|
m_sum[i] += vector[i];
|
||
|
m_sumP2[i] += vector[i] * vector[i];
|
||
|
e += (m_weights[i] - vector[i]) * (m_weights[i] - vector[i]);
|
||
|
}
|
||
|
m_mse += e / m_dimension;
|
||
|
}
|
||
|
|
||
|
int CSOMNode::GetHitsCount() const
|
||
|
{
|
||
|
return m_hitCount;
|
||
|
}
|
||
|
|
||
|
double CSOMNode::GetHitsMean(const int plane) const
|
||
|
{
|
||
|
if(m_hitCount == 0) return 0;
|
||
|
return m_sum[plane] / m_hitCount;
|
||
|
}
|
||
|
|
||
|
double CSOMNode::GetHitsDeviation(const int plane) const
|
||
|
{
|
||
|
if(m_hitCount == 0) return 0;
|
||
|
double z = m_sumP2[plane] / m_hitCount - m_sum[plane] / m_hitCount * m_sum[plane] / m_hitCount;
|
||
|
if(z < 0) return 0;
|
||
|
return MathSqrt(z);
|
||
|
}
|
||
|
|
||
|
double CSOMNode::GetMSE() const
|
||
|
{
|
||
|
if(m_hitCount == 0) return 0;
|
||
|
return m_mse / m_hitCount;
|
||
|
}
|
||
|
|
||
|
long CSOMNode::GetUpdateCount() const
|
||
|
{
|
||
|
return m_updateCount;
|
||
|
}
|
||
|
|
||
|
void CSOMNode::SetCluster(int index)
|
||
|
{
|
||
|
m_cluster = index;
|
||
|
}
|
||
|
|
||
|
int CSOMNode::GetCluster() const
|
||
|
{
|
||
|
return m_cluster;
|
||
|
}
|