132 lines
5.7 KiB
MQL5
132 lines
5.7 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| KronosVerifyEncoder.mq5 |
|
|
//| MMQ — Muhammad Minhas Qamar |
|
|
//| www.mql5.com/en/articles/23304 |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "MMQ — Muhammad Minhas Qamar"
|
|
#property link "https://www.mql5.com/en/articles/23304"
|
|
#property version "1.00"
|
|
#property script_show_inputs
|
|
#property strict
|
|
|
|
#include <Kronos\KronosEncoder.mqh> // pulls in TokenizerMath + TransformerCore
|
|
|
|
input string InpRefDir = "kronos_refs\\"; // refs folder under MQL5/Files/
|
|
input int InpLookback = 256; // L (rows in x_norm)
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Read a [rows,cols] float32 .bin into a matrix(double). |
|
|
//+------------------------------------------------------------------+
|
|
bool LoadF32Matrix(const string fname, ulong rows, ulong cols, matrix &out)
|
|
{
|
|
int h = FileOpen(fname, FILE_READ | FILE_BIN);
|
|
if(h == INVALID_HANDLE)
|
|
{ PrintFormat("LoadF32Matrix: cannot open %s (err %d)", fname, GetLastError()); return false; }
|
|
ulong n = rows * cols;
|
|
float buf[];
|
|
ArrayResize(buf, (int)n);
|
|
uint got = FileReadArray(h, buf, 0, (int)n);
|
|
FileClose(h);
|
|
if(got != n)
|
|
{ PrintFormat("LoadF32Matrix: short read %s (%u of %I64u)", fname, got, n); return false; }
|
|
out = matrix::Zeros(rows, cols);
|
|
for(ulong r = 0; r < rows; r++)
|
|
for(ulong c = 0; c < cols; c++)
|
|
out[r][c] = (double)buf[r * cols + c];
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Read N int32 values from a .bin into an int[]. |
|
|
//+------------------------------------------------------------------+
|
|
bool LoadI32Array(const string fname, int n, int &out[])
|
|
{
|
|
int h = FileOpen(fname, FILE_READ | FILE_BIN);
|
|
if(h == INVALID_HANDLE)
|
|
{ PrintFormat("LoadI32Array: cannot open %s (err %d)", fname, GetLastError()); return false; }
|
|
ArrayResize(out, n);
|
|
uint got = FileReadArray(h, out, 0, n); // int matches int32 width
|
|
FileClose(h);
|
|
if(got != (uint)n)
|
|
{ PrintFormat("LoadI32Array: short read %s (%u of %d)", fname, got, n); return false; }
|
|
return true;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Count mismatched elements and record the first mismatch index. |
|
|
//+------------------------------------------------------------------+
|
|
int CountMismatch(const int &a[], const int &b[], int n, int &first_idx)
|
|
{
|
|
int bad = 0;
|
|
first_idx = -1;
|
|
for(int i = 0; i < n; i++)
|
|
if(a[i] != b[i])
|
|
{ bad++; if(first_idx < 0) first_idx = i; }
|
|
return bad;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Script entry point. |
|
|
//+------------------------------------------------------------------+
|
|
void OnStart()
|
|
{
|
|
Print("================ Kronos encoder verification ================");
|
|
const int L = InpLookback;
|
|
|
|
//--- 1) load the frozen normalized input window
|
|
matrix x_norm;
|
|
if(!LoadF32Matrix(InpRefDir + "x_norm.bin", (ulong)L, KR_NFEAT, x_norm))
|
|
{ Print("ABORT: could not load x_norm.bin"); return; }
|
|
PrintFormat("Loaded x_norm: %I64u x %I64u", x_norm.Rows(), x_norm.Cols());
|
|
|
|
//--- 2) load the golden token ids
|
|
int ref_s1[], ref_s2[];
|
|
if(!LoadI32Array(InpRefDir + "s1_ids.bin", L, ref_s1)) { Print("ABORT: s1_ids.bin"); return; }
|
|
if(!LoadI32Array(InpRefDir + "s2_ids.bin", L, ref_s2)) { Print("ABORT: s2_ids.bin"); return; }
|
|
|
|
//--- 3) build + load the encoder, run it
|
|
CKronosEncoder enc;
|
|
if(!enc.Init(KR_TOK_WEIGHT_DIR, KR_TOK_N_ENC_LAYERS, KR_TOK_D_MODEL, KR_TOK_N_HEADS, KR_TOK_FF_DIM))
|
|
{ Print("ABORT: encoder Init failed (weights/paths)"); return; }
|
|
Print("Encoder weights loaded.");
|
|
|
|
int s1[], s2[];
|
|
if(!enc.Encode(x_norm, s1, s2))
|
|
{ Print("ABORT: Encode() failed"); return; }
|
|
PrintFormat("Encode produced %d s1 ids, %d s2 ids", ArraySize(s1), ArraySize(s2));
|
|
|
|
if(ArraySize(s1) != L || ArraySize(s2) != L)
|
|
{ PrintFormat("ABORT: length mismatch (got %d/%d, expected %d)", ArraySize(s1), ArraySize(s2), L); return; }
|
|
|
|
//--- 4) exact integer comparison
|
|
int first1, first2;
|
|
int bad1 = CountMismatch(s1, ref_s1, L, first1);
|
|
int bad2 = CountMismatch(s2, ref_s2, L, first2);
|
|
|
|
PrintFormat("s1: %d / %d match (mismatches: %d)", L - bad1, L, bad1);
|
|
PrintFormat("s2: %d / %d match (mismatches: %d)", L - bad2, L, bad2);
|
|
|
|
//--- 5) localize the first few mismatches if any
|
|
if(bad1 > 0)
|
|
{
|
|
PrintFormat("first s1 mismatch at t=%d : mql=%d ref=%d", first1, s1[first1], ref_s1[first1]);
|
|
int shown = 0;
|
|
for(int i = 0; i < L && shown < 8; i++)
|
|
if(s1[i] != ref_s1[i]) { PrintFormat(" s1[%d] mql=%d ref=%d", i, s1[i], ref_s1[i]); shown++; }
|
|
}
|
|
if(bad2 > 0)
|
|
{
|
|
PrintFormat("first s2 mismatch at t=%d : mql=%d ref=%d", first2, s2[first2], ref_s2[first2]);
|
|
int shown = 0;
|
|
for(int i = 0; i < L && shown < 8; i++)
|
|
if(s2[i] != ref_s2[i]) { PrintFormat(" s2[%d] mql=%d ref=%d", i, s2[i], ref_s2[i]); shown++; }
|
|
}
|
|
|
|
if(bad1 == 0 && bad2 == 0)
|
|
Print(">>> ENCODER VERIFIED: exact integer match on s1 and s2. <<<");
|
|
else
|
|
Print(">>> ENCODER MISMATCH: see dumps above. Likely culprits: "
|
|
"transpose convention, RoPE layout, or block count. <<<");
|
|
Print("=============================================================");
|
|
}
|
|
//+------------------------------------------------------------------+
|