kronos-mql5/Scripts/Kronos/KronosVerifyEncoder.mq5

132 lines
5.7 KiB
MQL5
Raw Permalink Normal View History

2026-07-05 05:06:39 +00:00
//+------------------------------------------------------------------+
//| 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("=============================================================");
}
//+------------------------------------------------------------------+