486 lines
37 KiB
MQL5
486 lines
37 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| BufferDouble.mqh |
|
|
//| Copyright 2021, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2021, MetaQuotes Ltd."
|
|
#property link "https://www.mql5.com"
|
|
//+------------------------------------------------------------------+
|
|
//| Connect libraries |
|
|
//+------------------------------------------------------------------+
|
|
#include <Arrays\Array.mqh>
|
|
#include "opencl.mqh"
|
|
//+------------------------------------------------------------------+
|
|
//| Class CBufferType |
|
|
//| Purpose: Dynamic data buffer class |
|
|
//+------------------------------------------------------------------+
|
|
class CBufferType: public CObject
|
|
{
|
|
protected:
|
|
CMyOpenCL* m_cOpenCL; // OpenCL context object
|
|
int m_myIndex; // data buffer index in context
|
|
public:
|
|
CBufferType(void);
|
|
~CBufferType(void);
|
|
//---
|
|
MATRIX m_mMatrix;
|
|
//--- method for initializing the buffer with initial values
|
|
virtual bool BufferInit(const ulong rows, const ulong columns, const TYPE value = 0);
|
|
//--- create a new buffer in the OpenCL context
|
|
virtual bool BufferCreate(CMyOpenCL *opencl);
|
|
//--- delete a buffer in the OpenCL context
|
|
virtual bool BufferFree(void);
|
|
//--- read data of the buffer from the OpenCL context
|
|
virtual bool BufferRead(void);
|
|
//--- write buffer data to the OpenCL context
|
|
virtual bool BufferWrite(void);
|
|
//--- get buffer index
|
|
virtual int GetIndex(void);
|
|
//--- change buffer index
|
|
virtual bool SetIndex(int index)
|
|
{
|
|
if(!m_cOpenCL.BufferFree(m_myIndex))
|
|
return false;
|
|
m_myIndex = index;
|
|
return true;
|
|
}
|
|
//--- copy buffer data to the array
|
|
virtual int GetData(TYPE &values[], bool load = true);
|
|
virtual int GetData(MATRIX &values, bool load = true);
|
|
virtual int GetData(CBufferType *values, bool load = true);
|
|
//--- calculate the average value of the data buffer
|
|
virtual TYPE MathMean(void);
|
|
//--- vector operations
|
|
virtual bool SumArray(CBufferType *src);
|
|
virtual int Scaling(TYPE value);
|
|
virtual bool Split(CBufferType* target1, CBufferType* target2, const int position);
|
|
virtual bool Concatenate(CBufferType* target1, CBufferType* target2, const ulong positions1, const ulong positions2);
|
|
//--- file handling methods
|
|
virtual bool Save(const int file_handle);
|
|
virtual bool Load(const int file_handle);
|
|
//--- class identifier
|
|
virtual int Type(void) const { return defBuffer; }
|
|
|
|
ulong Rows(void) const { return m_mMatrix.Rows(); }
|
|
ulong Cols(void) const { return m_mMatrix.Cols(); }
|
|
ulong Total(void) const { return (m_mMatrix.Rows() * m_mMatrix.Cols()); }
|
|
TYPE At(uint index) const { return m_mMatrix.Flat(index); }
|
|
TYPE operator[](ulong index) const { return m_mMatrix.Flat(index); }
|
|
VECTOR Row(ulong row) { return m_mMatrix.Row(row); }
|
|
VECTOR Col(ulong col) { return m_mMatrix.Col(col); }
|
|
bool Row(VECTOR& vec, ulong row) { return m_mMatrix.Row(vec, row); }
|
|
bool Col(VECTOR& vec, ulong col) { return m_mMatrix.Col(vec, col); }
|
|
bool Activation(MATRIX& mat_out, ENUM_ACTIVATION_FUNCTION func) { return m_mMatrix.Activation(mat_out, func);}
|
|
bool Derivative(MATRIX& mat_out, ENUM_ACTIVATION_FUNCTION func) { return m_mMatrix.Derivative(mat_out, func);}
|
|
bool Reshape(ulong rows, ulong cols){ return m_mMatrix.Reshape(rows, cols); }
|
|
|
|
bool Update(uint index, TYPE value)
|
|
{
|
|
if(index >= Total())
|
|
return false;
|
|
m_mMatrix.Flat(index, value);
|
|
return true;
|
|
}
|
|
|
|
bool Update(uint row, uint col, TYPE value)
|
|
{
|
|
if(row >= Rows() || col >= Cols())
|
|
return false;
|
|
m_mMatrix[row, col] = value;
|
|
return true;
|
|
}
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| Class constructor |
|
|
//+------------------------------------------------------------------+
|
|
CBufferType::CBufferType(void) : m_myIndex(-1)
|
|
{
|
|
m_cOpenCL = NULL;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Class destructor |
|
|
//+------------------------------------------------------------------+
|
|
CBufferType::~CBufferType(void)
|
|
{
|
|
if(m_cOpenCL && m_myIndex >= 0)
|
|
{
|
|
if(m_cOpenCL.BufferFree(m_myIndex))
|
|
{
|
|
m_myIndex = -1;
|
|
m_cOpenCL = NULL;
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Creating a new buffer in the OpenCL context |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferType::BufferCreate(CMyOpenCL *opencl)
|
|
{
|
|
//--- source data checking bock
|
|
if(!opencl)
|
|
{
|
|
BufferFree();
|
|
return false;
|
|
}
|
|
//--- if the received pointer matches the previously saved one, copy the buffer contents to the context memory
|
|
if(opencl == m_cOpenCL && m_myIndex >= 0)
|
|
return BufferWrite();
|
|
|
|
//--- check the presence of a previously saved pointer to OpenCL context
|
|
//--- if present, delete the buffer from the unused context
|
|
if(m_cOpenCL && m_myIndex >= 0)
|
|
{
|
|
if(m_cOpenCL.BufferFree(m_myIndex))
|
|
{
|
|
m_myIndex = -1;
|
|
m_cOpenCL = NULL;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
//--- create a new buffer in the specified OpenCL context
|
|
if((m_myIndex = opencl.AddBufferFromArray(m_mMatrix, 0, CL_MEM_READ_WRITE)) < 0)
|
|
return false;
|
|
m_cOpenCL = opencl;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Method for removing the buffer from the OpenCL context |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferType::BufferFree(void)
|
|
{
|
|
//--- check the presence of a previously saved pointer to OpenCL context
|
|
//--- if present, delete the buffer from the unused context
|
|
if(m_cOpenCL && m_myIndex >= 0)
|
|
if(m_cOpenCL.BufferFree(m_myIndex))
|
|
{
|
|
m_myIndex = -1;
|
|
m_cOpenCL = NULL;
|
|
return true;
|
|
}
|
|
if(m_myIndex >= 0)
|
|
m_myIndex = -1;
|
|
//---
|
|
return false;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Method for reading data from the buffer in the OpenCL context |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferType::BufferRead(void)
|
|
{
|
|
if(!m_cOpenCL || m_myIndex < 0)
|
|
return false;
|
|
//---
|
|
return m_cOpenCL.BufferRead(m_myIndex, m_mMatrix, 0);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Method for writing data to the buffer in the OpenCL context |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferType::BufferWrite(void)
|
|
{
|
|
if(!m_cOpenCL || m_myIndex < 0)
|
|
return false;
|
|
//---
|
|
return m_cOpenCL.BufferWrite(m_myIndex, m_mMatrix, 0);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Method for initializing the buffer with initial values |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferType::BufferInit(ulong rows, ulong columns, TYPE value)
|
|
{
|
|
if(rows <= 0 || columns <= 0)
|
|
return false;
|
|
//---
|
|
m_mMatrix = MATRIX::Full(rows, columns, value);
|
|
if(m_cOpenCL)
|
|
{
|
|
CMyOpenCL *opencl=m_cOpenCL;
|
|
BufferFree();
|
|
return BufferCreate(opencl);
|
|
}
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Method for getting buffer values |
|
|
//+------------------------------------------------------------------+
|
|
int CBufferType::GetData(TYPE &values[], bool load = true)
|
|
{
|
|
if(load && !BufferRead())
|
|
return -1;
|
|
if(ArraySize(values) != Total() &&
|
|
ArrayResize(values, (uint)Total()) <= 0)
|
|
return false;
|
|
//---
|
|
for(uint i = 0; i < Total(); i++)
|
|
values[i] = m_mMatrix.Flat(i);
|
|
return (int)Total();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Method for getting buffer values |
|
|
//+------------------------------------------------------------------+
|
|
int CBufferType::GetData(MATRIX &values, bool load = true)
|
|
{
|
|
if(load && !BufferRead())
|
|
return -1;
|
|
//---
|
|
values = m_mMatrix;
|
|
return (int)Total();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Method for getting buffer values |
|
|
//+------------------------------------------------------------------+
|
|
int CBufferType::GetData(CBufferType *values, bool load = true)
|
|
{
|
|
if(!values)
|
|
return -1;
|
|
if(load && !BufferRead())
|
|
return -1;
|
|
values.m_mMatrix.Copy(m_mMatrix);
|
|
return (int)values.Total();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Method for summing up elements of two data buffers |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferType::SumArray(CBufferType *src)
|
|
{
|
|
//--- check source data array
|
|
if(!src || src.Total() != Total())
|
|
return(false);
|
|
//---
|
|
if(!m_cOpenCL)
|
|
{
|
|
//--- resizing the matrix
|
|
MATRIX temp = src.m_mMatrix;
|
|
if(!temp.Reshape(Rows(), Cols()))
|
|
return(false);
|
|
//--- adding matrices
|
|
m_mMatrix += temp;
|
|
}
|
|
else
|
|
{
|
|
if(src.GetIndex() < 0 && !BufferCreate(m_cOpenCL))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_Sum, def_sum_inputs1, m_myIndex))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_Sum, def_sum_inputs2, src.GetIndex()))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_Sum, def_sum_outputs, m_myIndex))
|
|
return false;
|
|
uint off_set[] = {0};
|
|
uint NDRange[] = {(uint)Total()};
|
|
if(!m_cOpenCL.Execute(def_k_Sum, 1, off_set, NDRange))
|
|
return false;
|
|
}
|
|
//---
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Method for computing the average value of the array |
|
|
//+------------------------------------------------------------------+
|
|
TYPE CBufferType::MathMean(void)
|
|
{
|
|
return m_mMatrix.Mean();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Get the index of the buffer in the OpenCL context |
|
|
//+------------------------------------------------------------------+
|
|
int CBufferType::GetIndex(void)
|
|
{
|
|
if(!m_cOpenCL || m_myIndex < 0)
|
|
{
|
|
m_myIndex = -1;
|
|
m_cOpenCL = NULL;
|
|
return m_myIndex;
|
|
}
|
|
//---
|
|
if(!m_cOpenCL.CheckBuffer(m_myIndex))
|
|
m_myIndex = BufferCreate(m_cOpenCL);
|
|
//---
|
|
return m_myIndex;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Data scaling method (multiplying by a constant) |
|
|
//+------------------------------------------------------------------+
|
|
int CBufferType::Scaling(TYPE value)
|
|
{
|
|
if(!m_cOpenCL)
|
|
m_mMatrix *= value;
|
|
else
|
|
{
|
|
if(m_myIndex <= 0)
|
|
return false;
|
|
//--- pass parameters to the kernel
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_LineActivation, def_activ_inputs, m_myIndex))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_LineActivation, def_activ_outputs, m_myIndex))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgument(def_k_LineActivation, def_activ_param_a, value))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgument(def_k_LineActivation, def_activ_param_b, 0))
|
|
return false;
|
|
//--- place kernel to the execution queue
|
|
int off_set[] = {0};
|
|
int NDRange[] = { (int)Total() };
|
|
if(!m_cOpenCL.Execute(def_k_LineActivation, 1, off_set, NDRange))
|
|
return false;
|
|
}
|
|
//---
|
|
return (int)Total();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferType::Save(const int file_handle)
|
|
{
|
|
if(file_handle == INVALID_HANDLE)
|
|
return false;
|
|
if(m_myIndex >= 0)
|
|
if(!BufferRead())
|
|
return false;
|
|
//---
|
|
if(FileWriteInteger(file_handle, Type()) < INT_VALUE)
|
|
return false;
|
|
if(FileWriteLong(file_handle, Rows()) < sizeof(long))
|
|
return false;
|
|
if(FileWriteLong(file_handle, Cols()) < sizeof(long))
|
|
return false;
|
|
//---
|
|
for(ulong r = 0; r < Rows(); r++)
|
|
for(ulong c = 0; c < Cols(); c++)
|
|
if(FileWriteDouble(file_handle, m_mMatrix[r, c]) < sizeof(double))
|
|
return false;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferType::Load(const int file_handle)
|
|
{
|
|
if(file_handle == INVALID_HANDLE)
|
|
return false;
|
|
if(FileReadInteger(file_handle) != Type())
|
|
return false;
|
|
//---
|
|
ulong rows = FileReadLong(file_handle);
|
|
ulong cols = FileReadLong(file_handle);
|
|
if(!m_mMatrix.Init(rows, cols))
|
|
return false;
|
|
for(ulong r = 0; r < rows; r++)
|
|
for(ulong c = 0; c < cols; c++)
|
|
m_mMatrix[r, c] = (TYPE)FileReadDouble(file_handle);
|
|
//---
|
|
if(m_myIndex >= 0)
|
|
{
|
|
if(!BufferFree())
|
|
return false;
|
|
if(!BufferCreate(m_cOpenCL))
|
|
return false;
|
|
}
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferType::Split(CBufferType *target1, CBufferType *target2, const int position)
|
|
{
|
|
if(!target1 || !target2)
|
|
return false;
|
|
//---
|
|
if(!m_cOpenCL)
|
|
{
|
|
ulong split[] = {position};
|
|
MATRIX m[];
|
|
if(!m_mMatrix.Vsplit(split, m))
|
|
return false;
|
|
if(target1!=GetPointer(this))
|
|
target1.m_mMatrix = m[0];
|
|
target2.m_mMatrix = m[1];
|
|
}
|
|
else
|
|
{
|
|
if((int)target1.Total() < position)
|
|
return false;
|
|
if(target1.GetIndex() < 0 && !target1.BufferCreate(m_cOpenCL))
|
|
return false;
|
|
if(target2.GetIndex() < 0 && !target2.BufferCreate(m_cOpenCL))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_Split, def_split_source, m_myIndex))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_Split, def_split_target1, target1.GetIndex()))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_Split, def_split_target2, target2.GetIndex()))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgument(def_k_Split, def_split_total_source, (int)Total()))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgument(def_k_Split, def_split_total_target1, position))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgument(def_k_Split, def_split_total_target2, (int)target2.Total()))
|
|
return false;
|
|
//--- place kernel to the execution queue
|
|
int off_set[] = {0};
|
|
int NDRange[] = {(int)Total()};
|
|
ResetLastError();
|
|
if(!m_cOpenCL.Execute(def_k_Split, 1, off_set, NDRange))
|
|
return false;
|
|
}
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CBufferType::Concatenate(CBufferType *source1, CBufferType *source2, const ulong positions1, const ulong positions2)
|
|
{
|
|
if(!source1 || source1.Total() < positions1)
|
|
return false;
|
|
if(!source2 || source2.Total() < positions2)
|
|
return false;
|
|
//---
|
|
if(!m_cOpenCL)
|
|
{
|
|
m_mMatrix = source1.m_mMatrix;
|
|
if(!m_mMatrix.Resize(m_mMatrix.Rows(), positions1 + positions2))
|
|
return false;
|
|
for(ulong c = 0; c < positions2; c++)
|
|
if(!m_mMatrix.Col(source2.m_mMatrix.Col(c), positions1 + c))
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if(source1.Total() < positions1)
|
|
return false;
|
|
if(source2.Total() < positions2)
|
|
return false;
|
|
if(Total() < positions1 + positions2)
|
|
return false;
|
|
if(source1.GetIndex() < 0 && !source1.BufferCreate(m_cOpenCL))
|
|
return false;
|
|
if(source2.GetIndex() < 0 && !source2.BufferCreate(m_cOpenCL))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_Concatenate, def_concat_source1, source1.GetIndex()))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_Concatenate, def_concat_source2, source2.GetIndex()))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgumentBuffer(def_k_Concatenate, def_concat_target, m_myIndex))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgument(def_k_Concatenate, def_concat_total_target, (int)Total()))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgument(def_k_Concatenate, def_concat_total_source1, (int)positions1))
|
|
return false;
|
|
if(!m_cOpenCL.SetArgument(def_k_Concatenate, def_concat_total_sourse2, (int)positions2))
|
|
return false;
|
|
//--- place kernel to the execution queue
|
|
int off_set[] = {0};
|
|
int NDRange[] = {(int)Total()};
|
|
ResetLastError();
|
|
if(!m_cOpenCL.Execute(def_k_Concatenate, 1, off_set, NDRange))
|
|
return false;
|
|
}
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|