ScalerByLeo/Src/Scaler/RScaler/RCL.mqh
2026-09-16 18:51:57 -05:00

372 lines
11 KiB
MQL5

//+------------------------------------------------------------------+
//| RCL.mqh |
//| Copyright 2026, Leo. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Leo."
#property link "https://www.mql5.com/en/users/nique_372"
#property strict
#ifndef SCALERBYLEO_SRC_SCALER_RSCALER_RCL_MQH
#define SCALERBYLEO_SRC_SCALER_RSCALER_RCL_MQH
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "RBase.mqh"
#include "..\\..\\CL\\Main.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
namespace TSN
{
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//--- kernel transform / inverse (mismo layout de args en ambos kernels)
#define SCALERBYLEO_RCL_TRANSFORM_IDX_MEDIAN (0)
#define SCALERBYLEO_RCL_TRANSFORM_IDX_IQRINV (1)
#define SCALERBYLEO_RCL_TRANSFORM_IDX_IQR (1)
#define SCALERBYLEO_RCL_TRANSFORM_IDX_MATRIX (2)
#define SCALERBYLEO_RCL_TRANSFORM_IDX_COLS (3)
#define SCALERBYLEO_RCL_TRANSFORM_IDX_ISTART (4)
//---
#define SCALERBYLEO_RCL_KNAME_TRANSFORM ("robust_scaler_tranform_matrix")
#define SCALERBYLEO_RCL_KNAME_INV_TRANSFORM ("robust_scaler_inverse_tranform_matrix")
//+------------------------------------------------------------------+
//| Robust Scaler (OpenCL) |
//+------------------------------------------------------------------+
template<typename TFlt>
class RobustScalerCL : public RobustScalerBase<TFlt>
{
private:
bool OnLoad() override final;
//---
int m_buffer_h_medians;
int m_buffer_h_iqrs;
int m_buffer_h_iqrs_inv;
//---
int m_kernel_transform;
int m_kernel_inv_transform;
//---
bool m_is_init;
public:
RobustScalerCL(void);
~RobustScalerCL(void) {}
//---
__forceinline bool FitTransform(matrix<TFlt> &X, matrix<TFlt> &out);
bool Transform(matrix<TFlt> &X, matrix<TFlt> &out);
bool InverseTransform(matrix<TFlt> &X_scaled, matrix<TFlt> &out);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template<typename TFlt> RobustScalerCL::RobustScalerCL()
: m_buffer_h_medians(INVALID_HANDLE), m_buffer_h_iqrs(INVALID_HANDLE), m_buffer_h_iqrs_inv(INVALID_HANDLE),
m_kernel_transform(INVALID_HANDLE), m_kernel_inv_transform(INVALID_HANDLE), m_is_init(false)
{
m_type = SCALERBYLEO_SCALER_TYPE_ROBUST_CL;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template<typename TFlt>
bool RobustScalerCL::OnLoad()
{
//---
if(!m_is_init)
{
//---
MQLART_TRY_INI
//---
if(sizeof(TFlt) == sizeof(float))
{
MQLART_TRY(COpenCLCtxManager<TFlt>::ProgramInit(g_cl_scaler_program_flt), true)
}
else
{
MQLART_TRY(COpenCLCtxManager<TFlt>::ProgramInit(g_cl_scaler_program_dbl), true)
}
//---
MQLART_TRY(COpenCLCtxManager<TFlt>::KernelGet(SCALERBYLEO_RCL_KNAME_TRANSFORM, m_kernel_transform), true)
MQLART_TRY(COpenCLCtxManager<TFlt>::KernelGet(SCALERBYLEO_RCL_KNAME_INV_TRANSFORM, m_kernel_inv_transform), true)
//---
m_is_init = true;
//---
MQLART_TRY_END
//---
if(MQLART_TRY_IS_ERR)
{
m_last_err = SCALERBYLEO_ERR_IN_CTX_MANAGER_CL;
return false;
}
}
//--- actulizamos los 3 buffers
OPENCLMANAGER_MAKE_VECTOR(m_buffer_h_medians, m_medians, CL_MEM_READ_ONLY)
OPENCLMANAGER_MAKE_VECTOR(m_buffer_h_iqrs, m_iqrs, CL_MEM_READ_ONLY)
OPENCLMANAGER_MAKE_VECTOR(m_buffer_h_iqrs_inv, m_iqrs_inv, CL_MEM_READ_ONLY)
return true; // exito
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
template<typename TFlt>
__forceinline bool RobustScalerCL::FitTransform(matrix<TFlt> &X, matrix<TFlt> &out)
{
//---
if(!Fit(X))
return false;
if(!Transform(X, out))
return false;
//---
return true;
}
//+------------------------------------------------------------------+
//| Transform |
//+------------------------------------------------------------------+
template<typename TFlt>
bool RobustScalerCL::Transform(matrix<TFlt> &X, matrix<TFlt> &out)
{
//---
if(!m_loaded_scaler)
{
m_last_err = SCALERBYLEO_ERR_NOT_TRAINED;
return false;
}
//--- chekeo de rows
const ulong rows = X.Rows();
if(rows == 0)
{
m_last_err = SCALERBYLEO_ERR_EMPTY_INPUT;
return false;
}
//--- chekeo de cols
const ulong total_cols = X.Cols();
const ulong fs = m_medians.Size();
if(m_i_start + fs > total_cols)
{
m_last_err = SCALERBYLEO_ERR_SIZE_MISMATCH;
return false;
}
//--- init
int matrix_h = INVALID_HANDLE;
::ResetLastError();
//---
MQLART_TRY_INI
//--- Decidimos que subimos a la GPU segun el caso (patron validado en Bench/CLPattern.mq5)
ulong istart, cl_cols;
if(m_reconstruir && fs != total_cols)
{
//--- Caso ambiguo: subimos TODO + offset (Estrategia A, gano el benchmark)
out.Resize(rows, total_cols);
istart = m_i_start;
cl_cols = total_cols;
const uint write = uint(sizeof(TFlt) * total_cols * rows);
matrix_h = CLBufferCreate(CCLCtxShared::s_context, write, CL_MEM_READ_WRITE);
MQLART_TRY_NOT(matrix_h, INVALID_HANDLE)
MQLART_TRY(CLBufferWrite(matrix_h, 0, X), true)
}
else
{
istart = 0;
if(fs == total_cols)
{
//--- Caso trivial: se escala todo, no hay nada que reconstruir
out.Resize(rows, total_cols);
cl_cols = total_cols;
const uint write = uint(sizeof(TFlt) * total_cols * rows);
matrix_h = CLBufferCreate(CCLCtxShared::s_context, write, CL_MEM_READ_WRITE);
MQLART_TRY_NOT(matrix_h, INVALID_HANDLE)
MQLART_TRY(CLBufferWrite(matrix_h, 0, X), true)
}
else
{
//--- Caso !reconstruir: solo interesa el rango, subimos angosto
out.Resize(rows, fs);
cl_cols = fs;
matrix<TFlt> in(rows, fs);
for(ulong c = 0; c < fs; c++)
for(ulong r = 0; r < rows; r++)
in[r][c] = X[r][m_i_start + c];
const uint write = uint(sizeof(TFlt) * fs * rows);
matrix_h = CLBufferCreate(CCLCtxShared::s_context, write, CL_MEM_READ_WRITE);
MQLART_TRY_NOT(matrix_h, INVALID_HANDLE)
MQLART_TRY(CLBufferWrite(matrix_h, 0, in), true)
}
}
//---
MQLART_TRY(CLSetKernelArgMem(m_kernel_transform, SCALERBYLEO_RCL_TRANSFORM_IDX_MEDIAN, m_buffer_h_medians), true)
MQLART_TRY(CLSetKernelArgMem(m_kernel_transform, SCALERBYLEO_RCL_TRANSFORM_IDX_IQRINV, m_buffer_h_iqrs_inv), true)
MQLART_TRY(CLSetKernelArgMem(m_kernel_transform, SCALERBYLEO_RCL_TRANSFORM_IDX_MATRIX, matrix_h), true)
MQLART_TRY(CLSetKernelArg(m_kernel_transform, SCALERBYLEO_RCL_TRANSFORM_IDX_COLS, uint(cl_cols)), true)
MQLART_TRY(CLSetKernelArg(m_kernel_transform, SCALERBYLEO_RCL_TRANSFORM_IDX_ISTART, uint(istart)), true)
//---
const uint work_off_set[2] = {0, 0};
uint work_size_tranfors[2] = { (uint)rows, (uint)fs };
MQLART_TRY(CLExecute(m_kernel_transform, 2, work_off_set, work_size_tranfors), true)
CLBufferRead(matrix_h, 0, out);
//---
MQLART_TRY_END
//---
if(matrix_h != INVALID_HANDLE)
CLBufferFree(matrix_h);
//---
if(MQLART_TRY_IS_ERR)
{
m_last_err = SCALERBYLEO_ERR_IN_OPENCL;
return false;
}
//---
return true;
}
//+------------------------------------------------------------------+
//| InverseTransform |
//+------------------------------------------------------------------+
template<typename TFlt>
bool RobustScalerCL::InverseTransform(matrix<TFlt> &X_scaled, matrix<TFlt> &out)
{
//---
if(!m_loaded_scaler)
{
m_last_err = SCALERBYLEO_ERR_NOT_TRAINED;
return false;
}
//--- chekeo de rows
const ulong rows = X_scaled.Rows();
if(rows == 0)
{
m_last_err = SCALERBYLEO_ERR_EMPTY_INPUT;
return false;
}
//--- chekeo de cols
const ulong total_cols = X_scaled.Cols();
const ulong fs = m_medians.Size();
if(m_i_start + fs > total_cols)
{
m_last_err = SCALERBYLEO_ERR_SIZE_MISMATCH;
return false;
}
//--- init
int matrix_h = INVALID_HANDLE;
::ResetLastError();
//---
MQLART_TRY_INI
//---
ulong istart, cl_cols;
if(m_reconstruir && fs != total_cols)
{
out.Resize(rows, total_cols);
istart = m_i_start;
cl_cols = total_cols;
const uint write = uint(sizeof(TFlt) * total_cols * rows);
matrix_h = CLBufferCreate(CCLCtxShared::s_context, write, CL_MEM_READ_WRITE);
MQLART_TRY_NOT(matrix_h, INVALID_HANDLE)
MQLART_TRY(CLBufferWrite(matrix_h, 0, X_scaled), true)
}
else
{
istart = 0;
if(fs == total_cols)
{
out.Resize(rows, total_cols);
cl_cols = total_cols;
const uint write = uint(sizeof(TFlt) * total_cols * rows);
matrix_h = CLBufferCreate(CCLCtxShared::s_context, write, CL_MEM_READ_WRITE);
MQLART_TRY_NOT(matrix_h, INVALID_HANDLE)
MQLART_TRY(CLBufferWrite(matrix_h, 0, X_scaled), true)
}
else
{
out.Resize(rows, fs);
cl_cols = fs;
matrix<TFlt> in(rows, fs);
for(ulong c = 0; c < fs; c++)
for(ulong r = 0; r < rows; r++)
in[r][c] = X_scaled[r][m_i_start + c];
const uint write = uint(sizeof(TFlt) * fs * rows);
matrix_h = CLBufferCreate(CCLCtxShared::s_context, write, CL_MEM_READ_WRITE);
MQLART_TRY_NOT(matrix_h, INVALID_HANDLE)
MQLART_TRY(CLBufferWrite(matrix_h, 0, in), true)
}
}
//---
MQLART_TRY(CLSetKernelArgMem(m_kernel_inv_transform, SCALERBYLEO_RCL_TRANSFORM_IDX_MEDIAN, m_buffer_h_medians), true)
MQLART_TRY(CLSetKernelArgMem(m_kernel_inv_transform, SCALERBYLEO_RCL_TRANSFORM_IDX_IQR, m_buffer_h_iqrs), true)
MQLART_TRY(CLSetKernelArgMem(m_kernel_inv_transform, SCALERBYLEO_RCL_TRANSFORM_IDX_MATRIX, matrix_h), true)
MQLART_TRY(CLSetKernelArg(m_kernel_inv_transform, SCALERBYLEO_RCL_TRANSFORM_IDX_COLS, uint(cl_cols)), true)
MQLART_TRY(CLSetKernelArg(m_kernel_inv_transform, SCALERBYLEO_RCL_TRANSFORM_IDX_ISTART, uint(istart)), true)
//---
const uint work_off_set[2] = {0, 0};
uint work_size_tranfors[2] = { (uint)rows, (uint)fs };
MQLART_TRY(CLExecute(m_kernel_inv_transform, 2, work_off_set, work_size_tranfors), true)
CLBufferRead(matrix_h, 0, out);
//---
MQLART_TRY_END
//---
if(matrix_h != INVALID_HANDLE)
CLBufferFree(matrix_h);
//---
if(MQLART_TRY_IS_ERR)
{
m_last_err = SCALERBYLEO_ERR_IN_OPENCL;
return false;
}
//---
return true;
}
}
#endif // SCALERBYLEO_SRC_SCALER_RSCALER_RCL_MQH