forked from animatedread/Warrior_EA
The //| box blocks were excluded from0b06f8eand5efdb48and were what remained: 160 of them ran to 10+ lines, the longest to 88. Compressed to their leading topic sentences - 5 lines for a function header, 8 for a file header - keeping the box format and the standard MQL5 name/author lines verbatim. Verified at the BYTE level this time, across every in-scope file: the list of non-comment lines is byte-identical to HEAD and braces balance. The first check compared a locale-decoded 'git show' against a UTF-8 read and flagged 25 files that had not changed at all - every BOM and every non-ASCII line mismatched. 47,696 -> 40,665 lines in scope; comment share 38% -> 26%. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
236 lines
10 KiB
MQL5
236 lines
10 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| BufferDouble.mqh |
|
|
//| AnimateDread |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
//| CBufferDouble - the OpenCL/DirectML-backed buffer wrapper every |
|
|
//| *OCL neuron class (AI\Network.mqh) uses for its weights/output/ |
|
|
//| gradient storage. Needs COpenCLMy (AI\Network.mqh) and |
|
|
//| CDirectMLMy (AI\NeuronDirectML.mqh) already declared. Extracted |
|
|
//| verbatim out of AI\Network.mqh (SOLID cleanup) - no logic changes.|
|
|
//+------------------------------------------------------------------+
|
|
#include "NeuronDirectML.mqh"
|
|
class CBufferDouble : public CArrayDouble
|
|
{
|
|
protected:
|
|
COpenCLMy *OpenCL;
|
|
CDirectMLMy *DirectML;
|
|
int m_myIndex;
|
|
//--- OpenCL device buffers are float32 (see AI\Network.cl's fp32 conversion) while this class's
|
|
//--- public CArrayDouble interface - and the DirectML backend's DLL boundary (DML_BufferRead/
|
|
//--- DML_BufferWrite, hardcoded to double[]) - stay double. This scratch array is the narrow/widen
|
|
//--- point: populated from m_data before an OpenCL write, copied back into m_data after an OpenCL
|
|
//--- read. Never touched on the DirectML or CPU-fallback paths.
|
|
float m_data_f[];
|
|
public:
|
|
CBufferDouble(void);
|
|
~CBufferDouble(void);
|
|
//---
|
|
virtual bool BufferInit(uint count, double value);
|
|
virtual bool BufferCreate(COpenCLMy *opencl);
|
|
virtual bool BufferCreate(CDirectMLMy *directml);
|
|
virtual bool BufferFree(void);
|
|
virtual bool BufferRead(void);
|
|
virtual bool BufferWrite(void);
|
|
virtual int GetData(double &values[]);
|
|
virtual int GetData(CArrayDouble *values);
|
|
virtual int GetIndex(void) { return m_myIndex; }
|
|
//---
|
|
virtual int Type(void) const { return defBufferDouble; }
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CBufferDouble::CBufferDouble(void) : m_myIndex(-1)
|
|
{
|
|
OpenCL = NULL;
|
|
DirectML = NULL;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CBufferDouble::~CBufferDouble(void)
|
|
{
|
|
BufferFree();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferDouble::BufferCreate(COpenCLMy *opencl)
|
|
{
|
|
BufferFree();
|
|
//---
|
|
if(CheckPointer(opencl) == POINTER_INVALID)
|
|
return false;
|
|
if(ArrayResize(m_data_f, m_data_total) < 0)
|
|
{
|
|
Print(__FUNCTION__ + ": ArrayResize(m_data_f, " + IntegerToString(m_data_total) + ") failed - allocation failure?");
|
|
return false;
|
|
}
|
|
for(int i = 0; i < m_data_total; i++)
|
|
m_data_f[i] = (float)m_data[i];
|
|
if((m_myIndex = opencl.AddBufferFromArray(m_data_f, 0, m_data_total, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR)) < 0)
|
|
{
|
|
Print(__FUNCTION__ + ": OpenCL AddBufferFromArray failed for " + IntegerToString(m_data_total) + " elements, error " + IntegerToString(GetLastError()) + " (VRAM exhaustion / device lost?)");
|
|
return false;
|
|
}
|
|
OpenCL = opencl;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferDouble::BufferCreate(CDirectMLMy *directml)
|
|
{
|
|
BufferFree();
|
|
//---
|
|
if(CheckPointer(directml) == POINTER_INVALID)
|
|
return false;
|
|
if((m_myIndex = directml.BufferCreate(m_data_total)) < 0)
|
|
{
|
|
Print(__FUNCTION__ + ": " + directml.BackendName() + " BufferCreate failed for " + IntegerToString(m_data_total) + " elements (error " + IntegerToString(directml.LastError()) + ")");
|
|
return false;
|
|
}
|
|
DirectML = directml;
|
|
bool ok = DirectML.BufferWrite(m_myIndex, m_data, m_data_total);
|
|
if(!ok)
|
|
Print(__FUNCTION__ + ": " + directml.BackendName() + " BufferWrite failed for buffer " + IntegerToString(m_myIndex) +
|
|
" on create (" + IntegerToString(m_data_total) + " elements, error " + IntegerToString(directml.LastError()) + ")");
|
|
return ok;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferDouble::BufferFree(void)
|
|
{
|
|
if(CheckPointer(OpenCL) != POINTER_INVALID && m_myIndex >= 0)
|
|
{
|
|
if(!OpenCL.BufferFree(m_myIndex))
|
|
return false;
|
|
m_myIndex = -1;
|
|
OpenCL = NULL;
|
|
return true;
|
|
}
|
|
if(CheckPointer(DirectML) != POINTER_INVALID && m_myIndex >= 0)
|
|
{
|
|
DirectML.BufferFree(m_myIndex);
|
|
m_myIndex = -1;
|
|
DirectML = NULL;
|
|
return true;
|
|
}
|
|
//---
|
|
return false;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferDouble::BufferRead(void)
|
|
{
|
|
if(CheckPointer(OpenCL) != POINTER_INVALID && m_myIndex >= 0)
|
|
{
|
|
if(ArrayResize(m_data_f, m_data_total) < 0)
|
|
{
|
|
Print(__FUNCTION__ + ": ArrayResize(m_data_f, " + IntegerToString(m_data_total) + ") failed - allocation failure?");
|
|
return false;
|
|
}
|
|
if(!OpenCL.BufferRead(m_myIndex, m_data_f, 0, 0, m_data_total))
|
|
{
|
|
Print(__FUNCTION__ + ": OpenCL BufferRead failed for buffer " + IntegerToString(m_myIndex) + ", error " + IntegerToString(GetLastError()));
|
|
return false;
|
|
}
|
|
for(int i = 0; i < m_data_total; i++)
|
|
m_data[i] = (double)m_data_f[i];
|
|
return true;
|
|
}
|
|
if(CheckPointer(DirectML) != POINTER_INVALID && m_myIndex >= 0)
|
|
{
|
|
bool ok = DirectML.BufferRead(m_myIndex, m_data, m_data_total);
|
|
if(!ok)
|
|
Print(__FUNCTION__ + ": " + DirectML.BackendName() + " BufferRead failed for buffer " + IntegerToString(m_myIndex) +
|
|
" (" + IntegerToString(m_data_total) + " elements, error " + IntegerToString(DirectML.LastError()) + ")");
|
|
return ok;
|
|
}
|
|
//---
|
|
return false;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferDouble::BufferWrite(void)
|
|
{
|
|
if(CheckPointer(OpenCL) != POINTER_INVALID && m_myIndex >= 0)
|
|
{
|
|
if(ArrayResize(m_data_f, m_data_total) < 0)
|
|
{
|
|
Print(__FUNCTION__ + ": ArrayResize(m_data_f, " + IntegerToString(m_data_total) + ") failed - allocation failure?");
|
|
return false;
|
|
}
|
|
for(int i = 0; i < m_data_total; i++)
|
|
m_data_f[i] = (float)m_data[i];
|
|
bool ok = OpenCL.BufferWrite(m_myIndex, m_data_f, 0, 0, m_data_total);
|
|
if(!ok)
|
|
Print(__FUNCTION__ + ": OpenCL BufferWrite failed for buffer " + IntegerToString(m_myIndex) + ", error " + IntegerToString(GetLastError()));
|
|
return ok;
|
|
}
|
|
if(CheckPointer(DirectML) != POINTER_INVALID && m_myIndex >= 0)
|
|
{
|
|
bool ok = DirectML.BufferWrite(m_myIndex, m_data, m_data_total);
|
|
if(!ok)
|
|
Print(__FUNCTION__ + ": " + DirectML.BackendName() + " BufferWrite failed for buffer " + IntegerToString(m_myIndex) +
|
|
" (" + IntegerToString(m_data_total) + " elements, error " + IntegerToString(DirectML.LastError()) + ")");
|
|
return ok;
|
|
}
|
|
//---
|
|
return false;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferDouble::BufferInit(uint count, double value)
|
|
{
|
|
if(!Reserve(count))
|
|
return false;
|
|
m_data_total = (int)fmin(ArrayInitialize(m_data, value), count);
|
|
//---
|
|
return m_data_total == count;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int CBufferDouble::GetData(double &values[])
|
|
{
|
|
if(!BufferRead())
|
|
return false;
|
|
return ArrayCopy(values, m_data, 0, 0, m_data_total);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int CBufferDouble::GetData(CArrayDouble *values)
|
|
{
|
|
if(!BufferRead())
|
|
return -1;
|
|
values.Clear();
|
|
if(!values.AddArray(GetPointer(this)))
|
|
return -1;
|
|
return m_data_total;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Zero an optimizer-state buffer (Adam moments / SGD momentum) in |
|
|
//| place, host AND device copies. |
|
|
//+------------------------------------------------------------------+
|
|
bool ZeroOptimizerBuffer(CBufferDouble *buf)
|
|
{
|
|
if(CheckPointer(buf) == POINTER_INVALID || buf.Total() <= 0)
|
|
return true;
|
|
int total = buf.Total();
|
|
for(int i = 0; i < total; i++)
|
|
if(!buf.Update(i, 0.0))
|
|
return false;
|
|
//--- push to the device-side copy only when one exists; a host-only buffer (pure-MQL5 inference
|
|
//--- mode, which never trains) has no index and BufferWrite would report a spurious failure.
|
|
if(buf.GetIndex() >= 0)
|
|
return buf.BufferWrite();
|
|
return true;
|
|
}
|