oslib/tst/PST/P2_MQL5SVM_7603/MQL5/Include/CSOM/CSOMNode.mqh

262 lines
6.7 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 16:15:18 +02:00
//|------------------------------------------------------------------+
//| 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;
}