// Zorro64 C++ Strategy DLL - Alpha12 (FULL OOP Refactor)
// Compile as x64 DLL, include zorro.h
// ======================================================================
//
// Refactor goals achieved:
// - ALL prior “globals” moved into Alpha12Strategy (and its components).
// - Components: NodePool, DTree, MarkovChain, NetState, Logger, RuntimeManager.
// - No more static state inside functions (seedBar/haveSeed/seedVal moved into members).
// - run() remains a thin C bridge.
//
// Notes:
// - Logic is preserved: this is primarily an encapsulation/refactor.
// - Memory management remains malloc/free like your original (safe incremental step).
// ======================================================================
#define _CRT_SECURE_NO_WARNINGS
#include <zorro.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <windows.h>
#include <stddef.h> // for size_t (or use #include <cstddef>)
// ======================================================================
// ================= USER CONFIG =================
#define ASSET_SYMBOL "EUR/USD"
#define BAR_PERIOD 5
#define TF_H1 12
#define MC_ACT 0.30 // initial threshold on |CDL| in [-1..1] to accept a pattern
#define PBULL_LONG_TH 0.60 // Markov gate for long
#define PBULL_SHORT_TH 0.40 // Markov gate for short
// Debug toggles
#define ENABLE_PLOTS 0
#define ENABLE_WATCH 0
// ================= ENGINE PARAMETERS =================
#define MAX_BRANCHES 3
#define MAX_DEPTH 4
#define NWIN 256
#define NET_EQNS 100
#define DEGREE 4
#define KPROJ 16
#define REWIRE_EVERY 127
#define CAND_NEIGH 8
// ===== LOGGING CONTROLS =====
#define LOG_EQ_TO_ONE_FILE 1
#define LOG_EXPR_TEXT 0
#define META_EVERY 4
#define LOG_EQ_SAMPLE NET_EQNS
#define EXPR_MAXLEN 512
#define LOG_EVERY 16
#define MC_EVERY 1
// ---- DTREE feature sizes ----
#define ADV_EQ_NF 19
#define ADV_PAIR_NF 12
// ================= Candles ? 122-state Markov =================
#define MC_NPAT 61
#define MC_STATES 123
#define MC_NONE 0
// ================= Runtime Memory / Accuracy Manager =================
#define MEM_BUDGET_MB 50
#define MEM_HEADROOM_MB 5
#define DEPTH_STEP_BARS 16
#define KEEP_CHILDREN_HI 2
#define KEEP_CHILDREN_LO 1
#define RUNTIME_MIN_DEPTH 2
// ===== Chunked rewire settings =====
#define REWIRE_BATCH_EQ_5M 24
#define REWIRE_BATCH_EQ_H1 64
#define REWIRE_MIN_BATCH 8
#define REWIRE_NORM_EVERY 1
#define REWIRE_MEM_SOFT (MEM_BUDGET_MB - 4)
#define REWIRE_MEM_HARD (MEM_BUDGET_MB - 1)
// ===== Chunked update settings =====
#define UPDATE_BATCH_EQ_5M 32
#define UPDATE_BATCH_EQ_H1 96
#define UPDATE_MIN_BATCH 8
#define UPDATE_MEM_SOFT (MEM_BUDGET_MB - 4)
#define UPDATE_MEM_HARD (MEM_BUDGET_MB - 1)
// ======================= Tight-memory switches =======================
#define TIGHT_MEM 1
#ifdef TIGHT_MEM
typedef float fvar;
typedef short i16;
typedef char i8;
#else
typedef var fvar;
typedef int i16;
typedef int i8;
#endif
// ---------- Candle wrapper name mapping ----------
// Map Alpha12 "canonical" names -> whatever YOUR zorro.h actually provides.
#ifndef A12_CDL_HIGH_WAVE
#define A12_CDL_HIGH_WAVE() CDLHignWave()
#endif
#ifndef A12_CDL_STICKSANDWICH
#define A12_CDL_STICKSANDWICH() CDLStickSandwhich()
#endif
#ifndef A12_CDL_SEPARATING_LINES
#define A12_CDL_SEPARATING_LINES() CDLSeperatingLines()
#endif
#ifndef A12_CDL_CONCEALING_BABY_SWALLOW
#define A12_CDL_CONCEALING_BABY_SWALLOW() CDLConcealBabysWall()
#endif
// ======================================================================
// Forward declarations
class Alpha12Strategy;
static Alpha12Strategy* gAlpha12 = nullptr;
// ======================================================================
// ========================= NodePool (component) ========================
struct Node {
var v;
var r;
void* c;
int n;
int d;
};
struct NodeChunk {
NodeChunk* next;
int used;
int _pad;
Node nodes[256];
};
class NodePool {
NodeChunk* head = 0;
Node* freeList = 0;
public:
~NodePool() { freeAll(); }
Node* allocNode() {
if(freeList) {
Node* n = freeList;
freeList = (Node*)n->c;
n->c = 0; n->n = 0; n->d = 0; n->v = 0; n->r = 0;
return n;
}
if(!head || head->used >= 256) {
NodeChunk* ch = (NodeChunk*)malloc(sizeof(NodeChunk));
if(!ch) quit("Alpha12: OOM allocating NodeChunk");
memset(ch, 0, sizeof(NodeChunk));
ch->next = head;
head = ch;
}
if(head->used < 0 || head->used >= 256) quit("Alpha12: Corrupt node pool state");
return &head->nodes[head->used++];
}
void freeNode(Node* u) {
if(!u) return;
u->c = (void*)freeList;
freeList = u;
}
void freeAll() {
NodeChunk* ch = head;
while(ch) {
NodeChunk* nx = ch->next;
free(ch);
ch = nx;
}
head = 0;
freeList = 0;
}
};
// ======================================================================
// ========================= MarkovChain (component) =====================
class MarkovChain {
public:
int* Count = 0; // [MC_STATES*MC_STATES]
int* RowSum = 0; // [MC_STATES]
int Prev = -1;
int Cur = 0;
var PBullNext = 0.5;
var Entropy = 1.0;
var Alpha = 1.0; // Laplace smoothing
public:
void alloc() {
int NN = MC_STATES*MC_STATES;
int bytesMat = NN*sizeof(int);
int bytesRow = MC_STATES*sizeof(int);
Count = (int*)malloc(bytesMat);
RowSum = (int*)malloc(bytesRow);
if(!Count || !RowSum) quit("Alpha12: OOM in MarkovChain::alloc");
memset(Count,0,bytesMat);
memset(RowSum,0,bytesRow);
Prev = -1; Cur = 0; PBullNext = 0.5; Entropy = 1.0;
}
void freeMem() {
if(Count) free(Count);
if(RowSum) free(RowSum);
Count = RowSum = 0;
Prev = -1; Cur = 0; PBullNext = 0.5; Entropy = 1.0;
}
static int isBull(int s){
if(s<=0) return 0;
return ((s-1)%2)==1;
}
static int stateFromCDL(var* cdl /*len=61*/, var thr) {
int i, best=-1;
var besta=0;
for(i=0;i<MC_NPAT;i++){
var a = abs(cdl[i]);
if(a>besta){ besta=a; best=i; }
}
if(best<0) return MC_NONE;
if(besta < thr) return MC_NONE;
int bull = (cdl[best] > 0);
return 1 + 2*best + bull; // 1..122
}
int idx(int fr,int to) const { return fr*MC_STATES + to; }
void update(int sPrev,int sCur){
if(sPrev<0) return;
Count[idx(sPrev,sCur)]++;
RowSum[sPrev]++;
}
var prob(int s,int t) const {
var num = (var)Count[idx(s,t)] + Alpha;
var den = (var)RowSum[s] + Alpha*MC_STATES;
if(den<=0) return 1.0/MC_STATES;
return num/den;
}
// robust row stats
void rowStats(int s, var* outPBull, var* outEntropy) {
if(outPBull) *outPBull=0.5;
if(outEntropy) *outEntropy=1.0;
if(!Count || !RowSum) return;
if(!(Alpha > 0)) Alpha = 1.0;
if(s <= 0 || s >= MC_STATES) return;
if(RowSum[s] <= 0) return;
var den = (var)RowSum[s] + Alpha*(var)MC_STATES;
if(!(den > 0)) return;
var Z=0, pBull=0;
int t;
for(t=1;t<MC_STATES;t++){
var p = ((var)Count[idx(s,t)] + Alpha) / den;
Z += p;
if(isBull(t)) pBull += p;
}
if(!(Z>0)) return;
var H=0;
var Hmax = log((var)(MC_STATES-1));
if(!(Hmax > 0)) Hmax = 1.0;
for(t=1;t<MC_STATES;t++){
var p = (((var)Count[idx(s,t)] + Alpha) / den) / Z;
if(p>0) H += -p*log(p);
}
if(outPBull) *outPBull = pBull / Z;
if(outEntropy) *outEntropy = H / Hmax;
}
};
// ======================================================================
// =========================== Logger (component) ========================
class Alpha12Logger {
int wroteHeader = 0;
public:
void writeEqHeaderOnce(){
if(wroteHeader) return;
wroteHeader = 1;
file_append("Log\\Alpha12_eq_all.csv",
"Bar,Epoch,Ctx,EqCount,i,n1,n2,TreeId,Depth,Rate,Pred,Adv,Prop,Mode,WAdv,WTree,PBull,Entropy,MCState,ExprLen,ExprHash,tanhN,sinN,cosN\n");
}
static void strlcat_safe(string dst, string src, int cap) {
if(!dst || !src || cap <= 0) return;
int dl = (int)strlen(dst);
int sl = (int)strlen(src);
int room = cap - 1 - dl;
if(room <= 0){ if(cap > 0) dst[cap-1] = 0; return; }
int i;
for(i = 0; i < room && i < sl; i++) dst[dl + i] = src[i];
dst[dl + i] = 0;
}
static int countSubStr(string s, string sub){
if(!s || !sub) return 0;
int n=0; string p=s; int sublen = (int)strlen(sub); if(sublen<=0) return 0;
while((p=strstr(p,sub))){ n++; p += sublen; }
return n;
}
static int djb2_hash(string s){
int h = 5381, c, i = 0;
if(!s) return h;
while((c = s[i++])) h = ((h<<5)+h) ^ c;
return h & 0x7fffffff;
}
void appendEqMetaLine(
int bar, int epoch, int ctx,
int i, int n1, int n2, int tid, int depth, var rate, var pred, var adv, var prop, int mode,
var wadv, var wtree, var pbull, var ent, int mcstate, string expr)
{
if(i >= LOG_EQ_SAMPLE) return;
int eLen = 0, eHash = 0, cT = 0, cS = 0, cC = 0;
if(expr){
eLen = (int)strlen(expr);
eHash = (int)djb2_hash(expr);
cT = countSubStr(expr,"tanh(");
cS = countSubStr(expr,"sin(");
cC = countSubStr(expr,"cos(");
} else {
eHash = (int)djb2_hash("");
}
file_append("Log\\Alpha12_eq_all.csv",
strf("%i,%i,%i,%i,%i,%i,%i,%i,%i,%.4f,%.4f,%.4f,%.4f,%i,%.3f,%.3f,%.4f,%.4f,%i,%i,%i,%i,%i,%i\n",
bar, epoch, ctx, NET_EQNS, i, n1, n2, tid, depth,
rate, pred, adv, prop, mode, wadv, wtree, pbull, ent,
mcstate, eLen, eHash, cT, cS, cC));
}
};
// ======================================================================
// =========================== NetState (component) ======================
class NetState {
public:
int N = NET_EQNS;
int D = DEGREE;
int K = KPROJ;
// core
var* State = 0;
var* Prev = 0;
var* StateSq = 0;
// adjacency & projection
i16* Adj = 0;
fvar* RP = 0;
fvar* Z = 0;
i8* Mode= 0;
// weights & params
fvar* WSelf=0; fvar* WN1=0; fvar* WN2=0; fvar* WGlob1=0; fvar* WGlob2=0; fvar* WMom=0; fvar* WTree=0; fvar* WAdv=0;
fvar *A1x=0,*A1lam=0,*A1mean=0,*A1E=0,*A1P=0,*A1i=0,*A1c=0;
fvar *A2x=0,*A2lam=0,*A2mean=0,*A2E=0,*A2P=0,*A2i=0,*A2c=0;
fvar *G1mean=0,*G1E=0,*G2P=0,*G2lam=0;
fvar* TreeTerm = 0;
i16* TopEq = 0;
fvar* TopW = 0;
i16* EqTreeId = 0;
fvar* TAlpha=0;
fvar* TBeta =0;
fvar* PropRaw=0;
fvar* Prop =0;
// expression buffers (optional)
string* Sym = 0;
int SymFreed = 0;
// Hit-rate
fvar* HitEW = 0;
int* HitN = 0;
fvar* AdvPrev = 0;
var Ret1 = 0;
// Projection cache guards
int ProjBar = -1;
int ProjK = -1;
// effective projection dim
int Keff = KPROJ;
public:
void allocate() {
int n=N, d=D, k=K;
State = (var*)malloc(n*sizeof(var));
Prev = (var*)malloc(n*sizeof(var));
StateSq = (var*)malloc(n*sizeof(var));
Adj = (i16*)malloc(n*d*sizeof(i16));
RP = (fvar*)malloc(k*n*sizeof(fvar));
Z = (fvar*)malloc(k*sizeof(fvar));
Mode = (i8*)malloc(n*sizeof(i8));
WSelf=(fvar*)malloc(n*sizeof(fvar));
WN1=(fvar*)malloc(n*sizeof(fvar));
WN2=(fvar*)malloc(n*sizeof(fvar));
WGlob1=(fvar*)malloc(n*sizeof(fvar));
WGlob2=(fvar*)malloc(n*sizeof(fvar));
WMom=(fvar*)malloc(n*sizeof(fvar));
WTree=(fvar*)malloc(n*sizeof(fvar));
WAdv=(fvar*)malloc(n*sizeof(fvar));
A1x=(fvar*)malloc(n*sizeof(fvar)); A1lam=(fvar*)malloc(n*sizeof(fvar)); A1mean=(fvar*)malloc(n*sizeof(fvar));
A1E=(fvar*)malloc(n*sizeof(fvar)); A1P=(fvar*)malloc(n*sizeof(fvar)); A1i=(fvar*)malloc(n*sizeof(fvar)); A1c=(fvar*)malloc(n*sizeof(fvar));
A2x=(fvar*)malloc(n*sizeof(fvar)); A2lam=(fvar*)malloc(n*sizeof(fvar)); A2mean=(fvar*)malloc(n*sizeof(fvar));
A2E=(fvar*)malloc(n*sizeof(fvar)); A2P=(fvar*)malloc(n*sizeof(fvar)); A2i=(fvar*)malloc(n*sizeof(fvar)); A2c=(fvar*)malloc(n*sizeof(fvar));
G1mean=(fvar*)malloc(n*sizeof(fvar)); G1E=(fvar*)malloc(n*sizeof(fvar));
G2P=(fvar*)malloc(n*sizeof(fvar)); G2lam=(fvar*)malloc(n*sizeof(fvar));
TAlpha=(fvar*)malloc(n*sizeof(fvar));
TBeta =(fvar*)malloc(n*sizeof(fvar));
TreeTerm=(fvar*)malloc(n*sizeof(fvar));
TopEq=(i16*)malloc(n*sizeof(i16));
TopW =(fvar*)malloc(n*sizeof(fvar));
PropRaw=(fvar*)malloc(n*sizeof(fvar));
Prop =(fvar*)malloc(n*sizeof(fvar));
EqTreeId=(i16*)malloc(n*sizeof(i16));
if(LOG_EXPR_TEXT) Sym = (string*)malloc(n*sizeof(char*)); else Sym = 0;
// init adjacency
{ int t; for(t=0;t<n*d;t++) Adj[t] = -1; }
// init core arrays
{
int i;
for(i=0;i<n;i++){
State[i]=random(); Prev[i]=State[i]; StateSq[i]=State[i]*State[i];
Mode[i]=0;
WSelf[i]=0.5f; WN1[i]=0.2f; WN2[i]=0.2f;
WGlob1[i]=0.1f; WGlob2[i]=0.1f; WMom[i]=0.05f;
WTree[i]=0.15f; WAdv[i]=0.15f;
A1x[i]=1; A1lam[i]=0.1f; A1mean[i]=0; A1E[i]=0; A1P[i]=0; A1i[i]=0; A1c[i]=0;
A2x[i]=1; A2lam[i]=0.1f; A2mean[i]=0; A2E[i]=0; A2P[i]=0; A2i[i]=0; A2c[i]=0;
G1mean[i]=1.0f; G1E[i]=0.001f;
G2P[i]=0.6f; G2lam[i]=0.3f;
TAlpha[i]=0.8f; TBeta[i]=25.0f;
TreeTerm[i]=0;
TopEq[i]=-1; TopW[i]=0;
PropRaw[i]=1; Prop[i]=(fvar)(1.0/n);
if(LOG_EXPR_TEXT){
Sym[i] = (char*)malloc(EXPR_MAXLEN);
if(Sym[i]) strcpy(Sym[i],"");
}
}
}
// hit-rate arrays
HitEW = (fvar*)malloc(n*sizeof(fvar));
HitN = (int*)malloc(n*sizeof(int));
AdvPrev = (fvar*)malloc(n*sizeof(fvar));
{ int i; for(i=0;i<n;i++){ HitEW[i]=0.5f; HitN[i]=0; AdvPrev[i]=0; } }
// projection guards
ProjBar = -1; ProjK = -1;
}
void freeAll() {
int i;
if(State)free(State);
if(Prev)free(Prev);
if(StateSq)free(StateSq);
if(Adj)free(Adj);
if(RP)free(RP);
if(Z)free(Z);
if(Mode)free(Mode);
if(WSelf)free(WSelf);
if(WN1)free(WN1);
if(WN2)free(WN2);
if(WGlob1)free(WGlob1);
if(WGlob2)free(WGlob2);
if(WMom)free(WMom);
if(WTree)free(WTree);
if(WAdv)free(WAdv);
if(A1x)free(A1x); if(A1lam)free(A1lam); if(A1mean)free(A1mean);
if(A1E)free(A1E); if(A1P)free(A1P); if(A1i)free(A1i); if(A1c)free(A1c);
if(A2x)free(A2x); if(A2lam)free(A2lam); if(A2mean)free(A2mean);
if(A2E)free(A2E); if(A2P)free(A2P); if(A2i)free(A2i); if(A2c)free(A2c);
if(G1mean)free(G1mean); if(G1E)free(G1E);
if(G2P)free(G2P); if(G2lam)free(G2lam);
if(TAlpha)free(TAlpha); if(TBeta)free(TBeta);
if(TreeTerm)free(TreeTerm);
if(TopEq)free(TopEq);
if(TopW)free(TopW);
if(EqTreeId)free(EqTreeId);
if(PropRaw)free(PropRaw);
if(Prop)free(Prop);
if(Sym){
for(i=0;i<N;i++) if(Sym[i]) free(Sym[i]);
free(Sym);
}
Sym = 0;
if(HitEW) free(HitEW);
if(HitN) free(HitN);
if(AdvPrev) free(AdvPrev);
// null everything
State=Prev=StateSq=0; Adj=0; RP=0; Z=0; Mode=0;
WSelf=WN1=WN2=WGlob1=WGlob2=WMom=WTree=WAdv=0;
A1x=A1lam=A1mean=A1E=A1P=A1i=A1c=0;
A2x=A2lam=A2mean=A2E=A2P=A2i=A2c=0;
G1mean=G1E=G2P=G2lam=0;
TAlpha=TBeta=0;
TreeTerm=0; TopEq=0; TopW=0; EqTreeId=0;
PropRaw=0; Prop=0;
HitEW=0; HitN=0; AdvPrev=0;
}
void randomizeRP(){
int k=K, n=N;
int kk,j;
for(kk=0;kk<k;kk++)
for(j=0;j<n;j++)
RP[kk*n+j] = ifelse(random(1) < 0.5, -1.0, 1.0);
}
int keffClamped() const {
int kk = Keff;
if(kk < 0) kk = 0;
if(kk > K) kk = K;
return kk;
}
void computeProjection(){
if(!RP || !Z || !StateSq) return;
int kk = keffClamped();
if(ProjBar == Bar && ProjK == kk) return;
int k, j;
for(k=0;k<kk;k++){
var acc=0;
for(j=0;j<N;j++) acc += (var)RP[k*N + j] * StateSq[j];
Z[k] = (fvar)acc;
}
ProjBar = Bar;
ProjK = kk;
}
void sanitizeAdjacency(){
if(!Adj) return;
int i,d;
for(i=0;i<N;i++){
for(d=0;d<D;d++){
i16* p = &Adj[i*D + d];
if(*p < 0 || *p >= N || *p == i){
int r = (int)random(N);
if(r==i) r = (r+1)%N;
*p = (i16)r;
}
}
if(D >= 2 && Adj[i*D+0] == Adj[i*D+1]){
int r2 = (Adj[i*D+1] + 1) % N;
if(r2 == i) r2 = (r2+1)%N;
Adj[i*D+1] = (i16)r2;
}
}
}
int adjSafe(int i, int d) const {
if(!Adj || N<=1 || D<=0) return 0;
if(d<0) d=0;
if(d>=D) d = d % D;
int v = Adj[i*D + d];
if(v<0 || v>=N || v==i) v = (i+1)%N;
return v;
}
void normalizeProportions(){
int i;
var s=0;
for(i=0;i<N;i++) s += PropRaw[i];
if(s<=0){
for(i=0;i<N;i++) Prop[i] = (fvar)(1.0/N);
return;
}
for(i=0;i<N;i++) Prop[i] = (fvar)(PropRaw[i]/s);
}
};
// ======================================================================
// ============================= DTree (component) =======================
class DTree {
public:
NodePool* pool = 0;
Node* Root = 0;
Node** TreeIdx = 0;
int TreeN = 0;
int TreeCap = 0;
var DTreeExp = 0;
var* DepthW = 0;
var DepthExpLast = -1.0;
Node DummyNode;
// Predictability cache
var* PredNode = 0;
int PredLen = 0;
int PredCap = 0;
int PredCacheBar = -1;
// equation-cycle angles
var* EqTheta = 0;
int LeadEq = -1;
var LeadTh = 0;
var CycPh = 0;
var CycSpd = 0;
public:
DTree() { memset(&DummyNode,0,sizeof(DummyNode)); }
void bindPool(NodePool* p){ pool = p; }
void allocDepthLUT(){
int sz = MAX_DEPTH + 1;
if(!DepthW) DepthW = (var*)malloc(sz*sizeof(var));
if(!DepthW) quit("Alpha12: OOM DepthW");
}
void freeAll(){
if(Root) freeTree(Root);
Root = 0;
if(TreeIdx) free(TreeIdx);
TreeIdx = 0; TreeN=0; TreeCap=0;
if(DepthW) free(DepthW);
DepthW=0;
if(PredNode) free(PredNode);
PredNode=0; PredLen=0; PredCap=0;
if(EqTheta) free(EqTheta);
EqTheta=0;
}
// Tree byte size
int tree_bytes(Node* u){
if(!u) return 0;
int SZV = sizeof(var), SZI = sizeof(int), SZP = sizeof(void*);
int sz_node = 2*SZV + SZP + 2*SZI;
int total = sz_node;
if(u->n > 0 && u->c) total += u->n * SZP;
int i;
for(i=0;i<u->n;i++) total += tree_bytes(((Node**)u->c)[i]);
return total;
}
void refreshDepthW(){
if(!DepthW) return;
int d;
for(d=0; d<=MAX_DEPTH; d++) DepthW[d] = 1.0 / pow(d+1, DTreeExp);
DepthExpLast = DTreeExp;
}
Node* createNode(int depth){
if(!pool) quit("Alpha12: DTree pool not bound");
Node* u = pool->allocNode();
if(!u) return 0;
u->v = random();
u->r = 0.01 + 0.02*depth + random(0.005);
u->d = depth;
if(depth > 0){
u->n = 1 + (int)random(MAX_BRANCHES);
u->c = (void**)malloc(u->n*sizeof(void*));
if(!u->c){ u->n=0; u->c=0; return u; }
int i;
for(i=0;i<u->n;i++){
((Node**)u->c)[i] = createNode(depth-1);
}
} else {
u->n=0; u->c=0;
}
return u;
}
var evaluateNode(Node* u){
if(!u) return 0;
var sum=0; int i;
for(i=0;i<u->n;i++) sum += evaluateNode(((Node**)u->c)[i]);
if(DepthExpLast < 0 || abs(DTreeExp - DepthExpLast) > 1e-9) refreshDepthW();
var phase = sin(u->r * Bar + sum);
var weight = DepthW[u->d];
u->v = (1 - weight)*u->v + weight*phase;
return u->v;
}
void freeTree(Node* u){
if(!u) return;
int i;
for(i=0;i<u->n;i++) freeTree(((Node**)u->c)[i]);
if(u->c) free(u->c);
pool->freeNode(u);
}
void pushTreeNode(Node* u){
if(TreeN >= TreeCap){
int newCap = TreeCap*2;
if(newCap < 64) newCap = 64;
TreeIdx = (Node**)realloc(TreeIdx, newCap*sizeof(Node*));
TreeCap = newCap;
}
TreeIdx[TreeN++] = u;
}
void indexTreeDFS(Node* u){
if(!u) return;
pushTreeNode(u);
int i;
for(i=0;i<u->n;i++) indexTreeDFS(((Node**)u->c)[i]);
}
void ensurePredCache(){
if(PredCacheBar != Bar){
if(PredNode){
int i;
for(i=0;i<PredLen;i++) PredNode[i] = -2;
}
PredCacheBar = Bar;
}
}
var nodePredictability(Node* t){
if(!t) return 0.5;
var disp = 0; int n=t->n, i, cnt=0;
if(t->c){
for(i=0;i<n;i++){
Node* c = ((Node**)t->c)[i];
if(c){ disp += abs(c->v - t->v); cnt++; }
}
if(cnt>0) disp /= cnt;
}
var depthFac = 1.0/(1 + t->d);
var rateBase = 0.01 + 0.02*t->d;
var rateFac = exp(-25.0*abs(t->r - rateBase));
var p = 0.5*(depthFac + rateFac);
p = 0.5*p + 0.5*(1.0 + (-disp));
if(p<0) p=0; if(p>1) p=1;
return p;
}
var predByTid(int tid){
if(!TreeIdx || tid < 0 || tid >= TreeN || !TreeIdx[tid]) return 0.5;
ensurePredCache();
if(PredNode && tid < PredLen && PredNode[tid] > -1.5) return PredNode[tid];
Node* t = TreeIdx[tid];
var p = nodePredictability(t);
if(PredNode && tid < PredLen) PredNode[tid] = p;
return p;
}
Node* treeAt(int tid){
if(!TreeIdx || tid < 0 || tid >= TreeN || !TreeIdx[tid]) return &DummyNode;
return TreeIdx[tid];
}
int safeTreeIndexFromEq(int eqTreeId, int treeN){
int denom = ifelse(treeN>0, treeN, 1);
int tid = eqTreeId;
if(tid < 0) tid = 0;
if(denom > 0) tid = tid % denom;
if(tid < 0) tid = 0;
return tid;
}
void maybeShrinkTreeIdx(){
if(!TreeIdx) return;
if(TreeCap > 64 && TreeN < (TreeCap>>1)){
int newCap = (TreeCap>>1);
if(newCap < 64) newCap = 64;
TreeIdx = (Node**)realloc(TreeIdx, newCap*sizeof(Node*));
TreeCap = newCap;
}
}
void resizePredCacheToTree(){
PredLen = TreeN; if(PredLen <= 0) PredLen = 1;
if(PredLen > PredCap){
if(PredNode) free(PredNode);
PredNode = (var*)malloc(PredLen*sizeof(var));
PredCap = PredLen;
}
PredCacheBar = -1;
}
// equation ring angles (needs EqTreeId mapping provided externally)
void refreshEqAngles(const i16* eqTreeId, int eqN){
if(!EqTheta) EqTheta = (var*)malloc(eqN*sizeof(var));
if(!EqTheta) quit("Alpha12: OOM EqTheta");
var twoPi = 2.*3.141592653589793;
var denom = ifelse(TreeN>0,(var)TreeN,1.0);
int i;
for(i=0;i<eqN;i++){
int tid = safeTreeIndexFromEq((int)eqTreeId[i], TreeN);
var u = ((var)tid)/denom;
EqTheta[i] = twoPi*u;
}
}
static var pi(){ return 3.141592653589793; }
static var wrapPi(var a){
while(a <= -pi()) a += 2.*pi();
while(a > pi()) a -= 2.*pi();
return a;
}
static var angDiff(var a, var b){ return wrapPi(b - a); }
void updateEquationCycle(const fvar* prop, int N){
if(!EqTheta){ CycPh = wrapPi(CycPh); return; }
int i, bestI=0;
var bestP=-1;
for(i=0;i<N;i++){
var p = (var)prop[i];
if(p > bestP){ bestP=p; bestI=i; }
}
var th = EqTheta[bestI];
var d = angDiff(LeadTh, th);
CycSpd = 0.9*CycSpd + 0.1*d;
CycPh = wrapPi(CycPh + CycSpd);
LeadEq = bestI;
LeadTh = th;
}
// --- prune & grow helpers (direct lift) ---
var nodeImportance(Node* u){
if(!u) return 0;
var amp = abs(u->v); if(amp>1) amp=1;
var p = nodePredictability(u);
var depthW = 1.0/(1.0 + u->d);
var imp = (0.6*p + 0.4*amp) * depthW;
return imp;
}
Node* createLeafDepth(int d){
Node* u = pool->allocNode();
if(!u) return 0;
u->v = random();
u->r = 0.01 + 0.02*d + random(0.005);
u->n = 0;
u->c = 0;
u->d = d;
return u;
}
void growSelectiveAtDepth(Node* u, int frontierDepth, int addK){
if(!u) return;
if(u->d == frontierDepth){
int want = addK; if(want<=0) return;
int oldN=u->n, newN=oldN+want;
Node** Cnew = (Node**)malloc(newN*sizeof(void*));
if(!Cnew) return;
if(oldN>0 && u->c) memcpy(Cnew,u->c,oldN*sizeof(void*));
int i;
for(i=oldN;i<newN;i++) Cnew[i] = createLeafDepth(frontierDepth-1);
if(u->c) free(u->c);
u->c = Cnew;
u->n = newN;
return;
}
int j;
for(j=0;j<u->n;j++) growSelectiveAtDepth(((Node**)u->c)[j],frontierDepth,addK);
}
void freeChildAt(Node* parent, int idx){
if(!parent || !parent->c) return;
Node** C = (Node**)parent->c;
freeTree(C[idx]);
int i;
for(i=idx+1;i<parent->n;i++) C[i-1]=C[i];
parent->n--;
if(parent->n==0){ free(parent->c); parent->c=0; }
}
void pruneSelectiveAtDepth(Node* u, int targetDepth, int keepK){
if(!u) return;
if(u->d == targetDepth-1 && u->n > 0){
int n=u->n, i, kept=0;
int mark[16]; for(i=0;i<16;i++) mark[i]=0;
int iter;
for(iter=0; iter<keepK && iter<n; iter++){
int bestI=-1; var bestImp=-1;
for(i=0;i<n;i++){
if(i<16 && mark[i]==1) continue;
var imp = nodeImportance(((Node**)u->c)[i]);
if(imp > bestImp){ bestImp=imp; bestI=i; }
}
if(bestI>=0 && bestI<16){ mark[bestI]=1; kept++; }
}
for(i=n-1;i>=0;i--) if(i<16 && mark[i]==0) freeChildAt(u,i);
return;
}
int j; for(j=0;j<u->n;j++) pruneSelectiveAtDepth(((Node**)u->c)[j],targetDepth,keepK);
}
};
// ======================================================================
// ======================== RuntimeManager (component) ===================
class RuntimeManager {
public:
int MemFixedBytes = 0;
int TreeBytesCached = 0;
int ShedStage = 0;
int LastDepthActBar = -999999;
int ChartsOff = 0;
int LogsOff = 0;
int RT_TreeMaxDepth = MAX_DEPTH;
// Accuracy sentinel
var ACC_mx=0, ACC_my=0, ACC_mx2=0, ACC_my2=0, ACC_mxy=0;
var AccCorr=0;
var AccBase=0;
int HaveBase=0;
// Elastic depth tuner
var UtilBefore=0, UtilAfter=0;
int TunePending=0;
int TuneStartBar=0;
int TuneAction=0;
var DTreeExpStep = 0.05;
int DTreeExpDir = 1;
public:
int mem_bytes_est() const { return MemFixedBytes + TreeBytesCached; }
int mem_mb_est() const { return mem_bytes_est()/(1024*1024); }
void recalcTreeBytes(DTree& dt){ TreeBytesCached = dt.tree_bytes(dt.Root); }
void computeMemFixedBytes(const NetState& net, const DTree& dt, int includeExprBytes){
int N=net.N, D=net.D, K=net.K;
int SZV=sizeof(var), SZF=sizeof(fvar), SZI16=sizeof(i16), SZI8=sizeof(i8), SZP=sizeof(void*);
int b=0;
b += N*SZV*2; // State, Prev
b += N*SZV; // StateSq
b += N*D*SZI16; // Adj
b += N*SZI16; // EqTreeId
b += N*SZI8; // Mode
b += K*N*SZF; // RP
b += K*SZF; // Z
b += N*SZF*(8); // weights
b += N*SZF*(7+7); // A1*, A2*
b += N*SZF*(2+2); // G1mean,G1E,G2P,G2lam
b += N*SZF*(2); // TAlpha,TBeta
b += N*SZF*(1); // TreeTerm
b += N*(SZI16 + SZF); // TopEq,TopW
b += N*SZF*2; // PropRaw,Prop
b += N*SZF; // HitEW
b += N*SZF; // AdvPrev
b += N*sizeof(int); // HitN
// Markov: caller adds separately if desired (we do it in strategy since there are 3 chains)
b += dt.TreeCap*SZP; // Tree index capacity
if(includeExprBytes) b += N*EXPR_MAXLEN;
MemFixedBytes = b;
}
void shed_zero_cost_once(){
if(ShedStage > 0) return;
set(PLOTNOW|OFF);
ChartsOff = 1;
LogsOff = 1;
ShedStage = 1;
}
void acc_update(var x, var y){
var a=0.01;
ACC_mx=(1-a)*ACC_mx + a*x;
ACC_my=(1-a)*ACC_my + a*y;
ACC_mx2=(1-a)*ACC_mx2 + a*(x*x);
ACC_my2=(1-a)*ACC_my2 + a*(y*y);
ACC_mxy=(1-a)*ACC_mxy + a*(x*y);
var vx = ACC_mx2 - ACC_mx*ACC_mx;
var vy = ACC_my2 - ACC_my*ACC_my;
var cv = ACC_mxy - ACC_mx*ACC_my;
if(vx>0 && vy>0) AccCorr = cv / sqrt(vx*vy);
else AccCorr = 0;
if(!HaveBase){ AccBase=AccCorr; HaveBase=1; }
}
var util_now(){
int mb = mem_mb_est();
var mem_pen = 0;
if(mb > MEM_BUDGET_MB) mem_pen = (mb - MEM_BUDGET_MB)/(var)MEM_BUDGET_MB;
return AccCorr - 0.5*mem_pen;
}
void depth_manager_runtime(DTree& dt){
int trigger = MEM_BUDGET_MB - MEM_HEADROOM_MB;
int mb = mem_mb_est();
if(mb < trigger) return;
if(ShedStage == 0) shed_zero_cost_once();
if(ShedStage <= 1) ShedStage = 2;
int overBudget = (mb >= MEM_BUDGET_MB);
if(!overBudget && (Bar - LastDepthActBar < DEPTH_STEP_BARS)) return;
while(RT_TreeMaxDepth > RUNTIME_MIN_DEPTH) {
int keepK = ifelse(mem_mb_est() < MEM_BUDGET_MB + 2, KEEP_CHILDREN_HI, KEEP_CHILDREN_LO);
dt.pruneSelectiveAtDepth(dt.Root, RT_TreeMaxDepth, keepK);
RT_TreeMaxDepth--;
// reindex caller does (strategy)
mb = mem_mb_est();
printf("\n[DepthMgr] depth=%i keepK=%i est=%i MB", RT_TreeMaxDepth, keepK, mb);
if(mb < trigger) break;
}
LastDepthActBar = Bar;
}
};
// ===========================================================
// CUDA Advisor (Driver API + NVRTC)
// - Batch inference for ADV_EQ_NF features
// - Simple default model: tanh(dot(W,x)+b) in [-1..1]
// - Loads weights from Data\Alpha12_cuda_w.bin (float32)
// ===========================================================
class CudaAdvisor {
public:
// --- minimal CUDA driver types ---
typedef int CUresult;
typedef int CUdevice;
typedef struct CUctx_st* CUcontext;
typedef struct CUmod_st* CUmodule;
typedef struct CUfunc_st* CUfunction;
typedef unsigned long long CUdeviceptr;
static const int CUDA_SUCCESS = 0;
// --- minimal NVRTC types ---
typedef int nvrtcResult;
typedef struct _nvrtcProgram* nvrtcProgram;
static const int NVRTC_SUCCESS = 0;
// ---- function pointer types (nvcuda.dll) ----
typedef CUresult (__stdcall *PFN_cuInit)(unsigned int);
typedef CUresult (__stdcall *PFN_cuDeviceGetCount)(int*);
typedef CUresult (__stdcall *PFN_cuDeviceGet)(CUdevice*, int);
typedef CUresult (__stdcall *PFN_cuDeviceComputeCapability)(int*, int*, CUdevice);
typedef CUresult (__stdcall *PFN_cuCtxCreate_v2)(CUcontext*, unsigned int, CUdevice);
typedef CUresult (__stdcall *PFN_cuCtxDestroy_v2)(CUcontext);
typedef CUresult (__stdcall *PFN_cuModuleLoadDataEx)(CUmodule*, const void*, unsigned int, void*, void*);
typedef CUresult (__stdcall *PFN_cuModuleGetFunction)(CUfunction*, CUmodule, const char*);
typedef CUresult (__stdcall *PFN_cuModuleUnload)(CUmodule);
typedef CUresult (__stdcall *PFN_cuMemAlloc_v2)(CUdeviceptr*, size_t);
typedef CUresult (__stdcall *PFN_cuMemFree_v2)(CUdeviceptr);
typedef CUresult (__stdcall *PFN_cuMemcpyHtoD_v2)(CUdeviceptr, const void*, size_t);
typedef CUresult (__stdcall *PFN_cuMemcpyDtoH_v2)(void*, CUdeviceptr, size_t);
typedef CUresult (__stdcall *PFN_cuLaunchKernel)(
CUfunction,
unsigned int, unsigned int, unsigned int,
unsigned int, unsigned int, unsigned int,
unsigned int,
void*,
void**,
void**);
typedef CUresult (__stdcall *PFN_cuCtxSynchronize)(void);
// ---- NVRTC pointers ----
typedef nvrtcResult (__stdcall *PFN_nvrtcCreateProgram)(
nvrtcProgram*,
const char*,
const char*,
int,
const char* const*,
const char* const*);
typedef nvrtcResult (__stdcall *PFN_nvrtcCompileProgram)(nvrtcProgram, int, const char* const*);
typedef nvrtcResult (__stdcall *PFN_nvrtcGetProgramLogSize)(nvrtcProgram, size_t*);
typedef nvrtcResult (__stdcall *PFN_nvrtcGetProgramLog)(nvrtcProgram, char*);
typedef nvrtcResult (__stdcall *PFN_nvrtcGetPTXSize)(nvrtcProgram, size_t*);
typedef nvrtcResult (__stdcall *PFN_nvrtcGetPTX)(nvrtcProgram, char*);
typedef nvrtcResult (__stdcall *PFN_nvrtcDestroyProgram)(nvrtcProgram*);
private:
// DLLs
HMODULE hCU = 0;
HMODULE hNVRTC= 0;
// CUDA function pointers
PFN_cuInit p_cuInit = 0;
PFN_cuDeviceGetCount p_cuDeviceGetCount = 0;
PFN_cuDeviceGet p_cuDeviceGet = 0;
PFN_cuDeviceComputeCapability p_cuDeviceComputeCapability = 0;
PFN_cuCtxCreate_v2 p_cuCtxCreate = 0;
PFN_cuCtxDestroy_v2 p_cuCtxDestroy = 0;
PFN_cuModuleLoadDataEx p_cuModuleLoadDataEx = 0;
PFN_cuModuleGetFunction p_cuModuleGetFunction = 0;
PFN_cuModuleUnload p_cuModuleUnload = 0;
PFN_cuMemAlloc_v2 p_cuMemAlloc = 0;
PFN_cuMemFree_v2 p_cuMemFree = 0;
PFN_cuMemcpyHtoD_v2 p_cuMemcpyHtoD = 0;
PFN_cuMemcpyDtoH_v2 p_cuMemcpyDtoH = 0;
PFN_cuLaunchKernel p_cuLaunchKernel = 0;
PFN_cuCtxSynchronize p_cuCtxSynchronize = 0;
// NVRTC function pointers
PFN_nvrtcCreateProgram p_nvrtcCreateProgram = 0;
PFN_nvrtcCompileProgram p_nvrtcCompileProgram = 0;
PFN_nvrtcGetProgramLogSize p_nvrtcGetProgramLogSize = 0;
PFN_nvrtcGetProgramLog p_nvrtcGetProgramLog = 0;
PFN_nvrtcGetPTXSize p_nvrtcGetPTXSize = 0;
PFN_nvrtcGetPTX p_nvrtcGetPTX = 0;
PFN_nvrtcDestroyProgram p_nvrtcDestroyProgram = 0;
// CUDA state
int ready = 0;
CUdevice dev = 0;
CUcontext ctx = 0;
CUmodule mod = 0;
CUfunction func = 0;
// device buffers
CUdeviceptr dX = 0; // float[maxBatch * nf]
CUdeviceptr dOut = 0; // float[maxBatch]
CUdeviceptr dW = 0; // float[nf]
CUdeviceptr dB = 0; // float[1]
int maxBatch = 0;
int nf = 0;
// host staging (to avoid realloc)
float* hX = 0; // float[maxBatch*nf]
float* hOut = 0; // float[maxBatch]
// simple weights (host)
float* hW = 0; // float[nf]
float hB = 0;
// kernel source (NVRTC)
const char* kSrc =
"extern \"C\" __device__ __forceinline__ float tanh_approx(float x){\n"
" // rational approx, good enough for gating/advice in [-5..5]\n"
" if(x > 5.0f) return 1.0f;\n"
" if(x < -5.0f) return -1.0f;\n"
" float x2 = x*x;\n"
" return x*(27.0f + x2)/(27.0f + 9.0f*x2);\n"
"}\n"
"extern \"C\" __global__ void advise_kernel(const float* X, const float* W, const float* B, float* out, int nf, int batch)\n"
"{\n"
" int i = (int)(blockIdx.x * blockDim.x + threadIdx.x);\n"
" if(i >= batch) return;\n"
" const float* x = X + i*nf;\n"
" float acc = 0.0f;\n"
" for(int k=0;k<nf;k++) acc += x[k]*W[k];\n"
" acc += B[0];\n"
" out[i] = tanh_approx(acc);\n"
"}\n";
private:
static FARPROC sym(HMODULE h, const char* name) {
if(!h) return 0;
return GetProcAddress(h, name);
}
static HMODULE load_nvrtc_any() {
const char* names[] = {
"nvrtc64_123_0.dll","nvrtc64_122_0.dll","nvrtc64_121_0.dll","nvrtc64_120_0.dll",
"nvrtc64_118_0.dll","nvrtc64_117_0.dll","nvrtc64_116_0.dll","nvrtc64_115_0.dll",
"nvrtc64_114_0.dll","nvrtc64_113_0.dll","nvrtc64_112_0.dll","nvrtc64_111_0.dll",
"nvrtc64_110_0.dll","nvrtc64_102_0.dll","nvrtc64_101_0.dll","nvrtc64_100_0.dll",
"nvrtc64_92.dll"
};
for(int i=0;i<(int)(sizeof(names)/sizeof(names[0])); i++) {
HMODULE h = LoadLibraryA(names[i]);
if(h) return h;
}
return LoadLibraryA("nvrtc64.dll");
}
void release_all() {
if(dB && p_cuMemFree) { p_cuMemFree(dB); dB=0; }
if(dW && p_cuMemFree) { p_cuMemFree(dW); dW=0; }
if(dOut && p_cuMemFree) { p_cuMemFree(dOut); dOut=0; }
if(dX && p_cuMemFree) { p_cuMemFree(dX); dX=0; }
if(mod && p_cuModuleUnload) { p_cuModuleUnload(mod); mod=0; }
if(ctx && p_cuCtxDestroy) { p_cuCtxDestroy(ctx); ctx=0; }
if(hOut) { free(hOut); hOut=0; }
if(hX) { free(hX); hX=0; }
if(hW) { free(hW); hW=0; }
ready = 0;
if(hNVRTC) { FreeLibrary(hNVRTC); hNVRTC=0; }
if(hCU) { FreeLibrary(hCU); hCU=0; }
}
int load_symbols() {
hCU = LoadLibraryA("nvcuda.dll");
if(!hCU) return 0;
p_cuInit = (PFN_cuInit)sym(hCU, "cuInit");
p_cuDeviceGetCount = (PFN_cuDeviceGetCount)sym(hCU, "cuDeviceGetCount");
p_cuDeviceGet = (PFN_cuDeviceGet)sym(hCU, "cuDeviceGet");
p_cuDeviceComputeCapability = (PFN_cuDeviceComputeCapability)sym(hCU, "cuDeviceComputeCapability");
p_cuCtxCreate = (PFN_cuCtxCreate_v2)sym(hCU, "cuCtxCreate_v2");
p_cuCtxDestroy= (PFN_cuCtxDestroy_v2)sym(hCU, "cuCtxDestroy_v2");
p_cuModuleLoadDataEx = (PFN_cuModuleLoadDataEx)sym(hCU, "cuModuleLoadDataEx");
p_cuModuleGetFunction= (PFN_cuModuleGetFunction)sym(hCU, "cuModuleGetFunction");
p_cuModuleUnload = (PFN_cuModuleUnload)sym(hCU, "cuModuleUnload");
p_cuMemAlloc = (PFN_cuMemAlloc_v2) sym(hCU, "cuMemAlloc_v2");
p_cuMemFree = (PFN_cuMemFree_v2) sym(hCU, "cuMemFree_v2");
p_cuMemcpyHtoD = (PFN_cuMemcpyHtoD_v2) sym(hCU, "cuMemcpyHtoD_v2");
p_cuMemcpyDtoH = (PFN_cuMemcpyDtoH_v2) sym(hCU, "cuMemcpyDtoH_v2");
p_cuLaunchKernel = (PFN_cuLaunchKernel)sym(hCU, "cuLaunchKernel");
p_cuCtxSynchronize= (PFN_cuCtxSynchronize)sym(hCU, "cuCtxSynchronize");
if(!p_cuInit || !p_cuDeviceGetCount || !p_cuDeviceGet || !p_cuCtxCreate || !p_cuCtxDestroy ||
!p_cuModuleLoadDataEx || !p_cuModuleGetFunction || !p_cuModuleUnload ||
!p_cuMemAlloc || !p_cuMemFree || !p_cuMemcpyHtoD || !p_cuMemcpyDtoH ||
!p_cuLaunchKernel || !p_cuCtxSynchronize)
{
return 0;
}
hNVRTC = load_nvrtc_any();
if(!hNVRTC) return 0;
p_nvrtcCreateProgram = (PFN_nvrtcCreateProgram)sym(hNVRTC, "nvrtcCreateProgram");
p_nvrtcCompileProgram= (PFN_nvrtcCompileProgram)sym(hNVRTC, "nvrtcCompileProgram");
p_nvrtcGetProgramLogSize=(PFN_nvrtcGetProgramLogSize)sym(hNVRTC, "nvrtcGetProgramLogSize");
p_nvrtcGetProgramLog=(PFN_nvrtcGetProgramLog)sym(hNVRTC, "nvrtcGetProgramLog");
p_nvrtcGetPTXSize=(PFN_nvrtcGetPTXSize)sym(hNVRTC, "nvrtcGetPTXSize");
p_nvrtcGetPTX=(PFN_nvrtcGetPTX)sym(hNVRTC, "nvrtcGetPTX");
p_nvrtcDestroyProgram=(PFN_nvrtcDestroyProgram)sym(hNVRTC, "nvrtcDestroyProgram");
if(!p_nvrtcCreateProgram || !p_nvrtcCompileProgram || !p_nvrtcGetProgramLogSize ||
!p_nvrtcGetProgramLog || !p_nvrtcGetPTXSize || !p_nvrtcGetPTX || !p_nvrtcDestroyProgram)
{
return 0;
}
return 1;
}
int load_weights_from_file(const char* path) {
// expects nf floats + 1 bias float (all float32)
if(!hW) return 0;
FILE* f = fopen(path, "rb");
if(!f) {
// default zero weights
int i; for(i=0;i<nf;i++) hW[i] = 0.0f;
hB = 0.0f;
return 0;
}
size_t want = (size_t)(nf + 1);
float* tmp = (float*)malloc(want*sizeof(float));
if(!tmp) { fclose(f); return 0; }
size_t got = fread(tmp, sizeof(float), want, f);
fclose(f);
if(got >= (size_t)nf) {
int i; for(i=0;i<nf;i++) hW[i] = tmp[i];
if(got >= (size_t)(nf+1)) hB = tmp[nf];
else hB = 0.0f;
free(tmp);
return 1;
}
free(tmp);
return 0;
}
public:
int isReady() const { return ready; }
int init(int nfIn, int maxBatchIn) {
shutdown(); // idempotent
nf = nfIn;
maxBatch = maxBatchIn;
if(nf <= 0 || maxBatch <= 0) return 0;
if(!load_symbols()) { release_all(); return 0; }
CUresult e = p_cuInit(0);
if(e != CUDA_SUCCESS) { release_all(); return 0; }
int count = 0;
e = p_cuDeviceGetCount(&count);
if(e != CUDA_SUCCESS || count <= 0) { release_all(); return 0; }
e = p_cuDeviceGet(&dev, 0);
if(e != CUDA_SUCCESS) { release_all(); return 0; }
int maj=0,min=0;
if(p_cuDeviceComputeCapability) p_cuDeviceComputeCapability(&maj,&min,dev);
if(maj <= 0) { maj=5; min=2; }
e = p_cuCtxCreate(&ctx, 0, dev);
if(e != CUDA_SUCCESS || !ctx) { release_all(); return 0; }
// ---- NVRTC compile ----
nvrtcProgram prog = 0;
nvrtcResult r = p_nvrtcCreateProgram(&prog, kSrc, "advise_kernel.cu", 0, 0, 0);
if(r != NVRTC_SUCCESS || !prog) { release_all(); return 0; }
char archOpt[64];
sprintf(archOpt, "--gpu-architecture=compute_%d%d", maj, min);
const char* opts[] = { archOpt, "--use_fast_math" };
r = p_nvrtcCompileProgram(prog, (int)(sizeof(opts)/sizeof(opts[0])), opts);
// Print compile log to Zorro console (optional)
size_t logSize = 0;
p_nvrtcGetProgramLogSize(prog, &logSize);
if(logSize > 1) {
char* logbuf = (char*)malloc(logSize + 1);
if(logbuf) {
logbuf[0] = 0;
p_nvrtcGetProgramLog(prog, logbuf);
printf("\n[NVRTC-advise] %s", logbuf);
free(logbuf);
}
}
if(r != NVRTC_SUCCESS) {
p_nvrtcDestroyProgram(&prog);
release_all();
return 0;
}
size_t ptxSize = 0;
r = p_nvrtcGetPTXSize(prog, &ptxSize);
if(r != NVRTC_SUCCESS || ptxSize < 8) {
p_nvrtcDestroyProgram(&prog);
release_all();
return 0;
}
char* ptx = (char*)malloc(ptxSize + 1);
if(!ptx) {
p_nvrtcDestroyProgram(&prog);
release_all();
return 0;
}
ptx[0] = 0;
r = p_nvrtcGetPTX(prog, ptx);
p_nvrtcDestroyProgram(&prog);
if(r != NVRTC_SUCCESS) {
free(ptx);
release_all();
return 0;
}
e = p_cuModuleLoadDataEx(&mod, (const void*)ptx, 0, 0, 0);
free(ptx);
if(e != CUDA_SUCCESS || !mod) { release_all(); return 0; }
e = p_cuModuleGetFunction(&func, mod, "advise_kernel");
if(e != CUDA_SUCCESS || !func) { release_all(); return 0; }
// ---- allocate device buffers ----
e = p_cuMemAlloc(&dX, sizeof(float)* (size_t)maxBatch * (size_t)nf);
if(e != CUDA_SUCCESS || !dX) { release_all(); return 0; }
e = p_cuMemAlloc(&dOut, sizeof(float)* (size_t)maxBatch);
if(e != CUDA_SUCCESS || !dOut) { release_all(); return 0; }
e = p_cuMemAlloc(&dW, sizeof(float)*(size_t)nf);
if(e != CUDA_SUCCESS || !dW) { release_all(); return 0; }
e = p_cuMemAlloc(&dB, sizeof(float));
if(e != CUDA_SUCCESS || !dB) { release_all(); return 0; }
// ---- allocate host staging ----
hX = (float*)malloc(sizeof(float)*(size_t)maxBatch*(size_t)nf);
hOut = (float*)malloc(sizeof(float)*(size_t)maxBatch);
hW = (float*)malloc(sizeof(float)*(size_t)nf);
if(!hX || !hOut || !hW) { release_all(); return 0; }
// ---- load weights (optional) ----
load_weights_from_file("Data\\Alpha12_cuda_w.bin");
// copy weights to device
e = p_cuMemcpyHtoD(dW, hW, sizeof(float)*(size_t)nf);
if(e != CUDA_SUCCESS) { release_all(); return 0; }
e = p_cuMemcpyHtoD(dB, &hB, sizeof(float));
if(e != CUDA_SUCCESS) { release_all(); return 0; }
ready = 1;
printf("\n[CUDA-advise] init OK (nf=%d maxBatch=%d cc=%d.%d)", nf, maxBatch, maj, min);
return 1;
}
void shutdown() {
release_all();
}
// Batch inference:
// - X: float[batch*nf] on host (row-major)
// - out: float[batch] on host
// returns 1 on GPU success, 0 on failure.
int inferBatch(const float* X, int batch, float* out) {
if(!ready) return 0;
if(!X || !out) return 0;
if(batch <= 0) return 1;
if(batch > maxBatch) batch = maxBatch;
size_t bytesX = sizeof(float)*(size_t)batch*(size_t)nf;
size_t bytesO = sizeof(float)*(size_t)batch;
CUresult e = p_cuMemcpyHtoD(dX, X, bytesX);
if(e != CUDA_SUCCESS) { ready = 0; return 0; }
int nfLocal = nf;
int batchLocal = batch;
void* params[] = {
(void*)&dX,
(void*)&dW,
(void*)&dB,
(void*)&dOut,
(void*)&nfLocal,
(void*)&batchLocal
};
unsigned int block = 128;
unsigned int grid = (unsigned int)((batch + (int)block - 1) / (int)block);
e = p_cuLaunchKernel(func, grid,1,1, block,1,1, 0, 0, params, 0);
if(e != CUDA_SUCCESS) { ready = 0; return 0; }
e = p_cuCtxSynchronize();
if(e != CUDA_SUCCESS) { ready = 0; return 0; }
e = p_cuMemcpyDtoH(out, dOut, bytesO);
if(e != CUDA_SUCCESS) { ready = 0; return 0; }
return 1;
}
// helper: access staging buffers
float* hostX() { return hX; }
float* hostOut() { return hOut; }
int cap() const { return maxBatch; }
int featN() const { return nf; }
};
// ========================= Alpha12Strategy (owner) =====================
// Drop-in full class with CUDA-batched advisor + per-bar cache integrated.
// Assumes CudaAdvisor + other components (NodePool, DTree, NetState, Logger, RuntimeManager, MarkovChain)
// are already defined above.
class Alpha12Strategy {
public:
// Components
NodePool pool;
DTree dt;
NetState net;
Alpha12Logger log;
RuntimeManager rt;
// Markov: HTF, LTF, REL
MarkovChain MH;
MarkovChain ML;
MarkovChain MR;
// --- Candlestick buffers (NO static locals) ---
var CDL_L[MC_NPAT]; // 5M (LTF) pattern values
var CDL_H[MC_NPAT]; // 1H (HTF) pattern values
// Strategy runtime
int ready = 0;
int Epoch = 0;
int CtxID = 0;
// Markov adaptive knobs
var FB_W = 0.70;
var MC_ACT_dyn = MC_ACT;
var MC_Alpha = 1.0;
int CandNeigh = CAND_NEIGH;
// Rewire/update cursors
int RewirePos = 0;
int RewirePasses = 0;
int UpdatePos = 0;
int UpdatePasses = 0;
// Signal & trade
var LastSig = 0;
// Advisor budget/rotation
int AdviseMax = 16;
// Advisor seed cache (moved from static)
int seedBar = -1;
int haveSeed[NET_EQNS];
var seedVal[NET_EQNS];
// ---- CUDA advisor (batched DTREE replacement) ----
CudaAdvisor cuda;
int CudaReady = 0;
// Per-bar cached advice
int AdvCacheBar = -999999;
i8 AdvHave[NET_EQNS];
fvar AdvCache[NET_EQNS];
public:
Alpha12Strategy() {
dt.bindPool(&pool);
memset(haveSeed,0,sizeof(haveSeed));
memset(seedVal,0,sizeof(seedVal));
AdvCacheBar = -999999;
memset(AdvHave,0,sizeof(AdvHave));
memset(AdvCache,0,sizeof(AdvCache));
}
~Alpha12Strategy(){ cleanup(); }
// --------------------- utilities (direct lifts) ---------------------
static var randsign(){ return ifelse(random(1) < 0.5, -1.0, 1.0); }
static var mapUnit(var u,var lo,var hi){
if(u<-1) u=-1;
if(u>1) u=1;
var t=0.5*(u+1.0);
return lo + t*(hi-lo);
}
static var safeNum(var x){ if(invalid(x)) return 0; return clamp(x,-1e100,1e100); }
static void sanitize(var* A,int n){ int k; for(k=0;k<n;k++) A[k]=safeNum(A[k]); }
static var sat100(var x){ return clamp(x,-100.,100.); }
static var nrm_s(var x) { return sat100(100.*tanh(x)); }
static var nrm_scl(var x, var s) { return sat100(100.*tanh(s*x)); }
// --------------- Candlestick pattern builder (unchanged) ------------
int buildCDL_TA61(var* out, string* names)
{
int n = 0;
#define ADD(Name, Call) do{ var v = (Call); if(out) out[n] = v/100.; if(names) names[n] = Name; n++; }while(0)
ADD("CDL2Crows", CDL2Crows());
ADD("CDL3BlackCrows", CDL3BlackCrows());
ADD("CDL3Inside", CDL3Inside());
ADD("CDL3LineStrike", CDL3LineStrike());
ADD("CDL3Outside", CDL3Outside());
ADD("CDL3StarsInSouth", CDL3StarsInSouth());
ADD("CDL3WhiteSoldiers", CDL3WhiteSoldiers());
ADD("CDLAbandonedBaby", CDLAbandonedBaby(0.3));
ADD("CDLAdvanceBlock", CDLAdvanceBlock());
ADD("CDLBeltHold", CDLBeltHold());
ADD("CDLBreakaway", CDLBreakaway());
ADD("CDLClosingMarubozu", CDLClosingMarubozu());
// was: CDLConcealBabysWall() (very likely wrong)
ADD("CDLConcealingBabySwallow", A12_CDL_CONCEALING_BABY_SWALLOW());
ADD("CDLCounterAttack", CDLCounterAttack());
ADD("CDLDarkCloudCover", CDLDarkCloudCover(0.3));
ADD("CDLDoji", CDLDoji());
ADD("CDLDojiStar", CDLDojiStar());
ADD("CDLDragonflyDoji", CDLDragonflyDoji());
ADD("CDLEngulfing", CDLEngulfing());
ADD("CDLEveningDojiStar", CDLEveningDojiStar(0.3));
ADD("CDLEveningStar", CDLEveningStar(0.3));
ADD("CDLGapSideSideWhite", CDLGapSideSideWhite());
ADD("CDLGravestoneDoji", CDLGravestoneDoji());
ADD("CDLHammer", CDLHammer());
ADD("CDLHangingMan", CDLHangingMan());
ADD("CDLHarami", CDLHarami());
ADD("CDLHaramiCross", CDLHaramiCross());
// was: CDLHignWave()
ADD("CDLHighWave", A12_CDL_HIGH_WAVE());
ADD("CDLHikkake", CDLHikkake());
ADD("CDLHikkakeMod", CDLHikkakeMod());
ADD("CDLHomingPigeon", CDLHomingPigeon());
ADD("CDLIdentical3Crows", CDLIdentical3Crows());
ADD("CDLInNeck", CDLInNeck());
ADD("CDLInvertedHammer", CDLInvertedHammer());
ADD("CDLKicking", CDLKicking());
ADD("CDLKickingByLength", CDLKickingByLength());
ADD("CDLLadderBottom", CDLLadderBottom());
ADD("CDLLongLeggedDoji", CDLLongLeggedDoji());
ADD("CDLLongLine", CDLLongLine());
ADD("CDLMarubozu", CDLMarubozu());
ADD("CDLMatchingLow", CDLMatchingLow());
ADD("CDLMatHold", CDLMatHold(0.5));
ADD("CDLMorningDojiStar", CDLMorningDojiStar(0.3));
ADD("CDLMorningStar", CDLMorningStar(0.3));
ADD("CDLOnNeck", CDLOnNeck());
ADD("CDLPiercing", CDLPiercing());
// your existing underscore alias is fine
ADD("CDLRickshawMan", CDL_RickshawMan());
ADD("CDLRiseFall3Methods", CDL_RiseFall3Methods());
// was: CDL_SeperatingLines()
ADD("CDLSeparatingLines", A12_CDL_SEPARATING_LINES());
ADD("CDLShootingStar", CDL_ShootingStar());
ADD("CDLShortLine", CDL_ShortLine());
ADD("CDLSpinningTop", CDL_SpinningTop());
ADD("CDLStalledPattern", CDL_StalledPattern());
// was: CDL_StickSandwhich()
ADD("CDLStickSandwich", A12_CDL_STICKSANDWICH());
ADD("CDLTakuri", CDL_Takuri());
ADD("CDLTasukiGap", CDL_TasukiGap());
ADD("CDLThrusting", CDL_Thrusting());
ADD("CDLTristar", CDL_Tristar());
ADD("CDLUnique3River", CDL_Unique3River());
ADD("CDLUpsideGap2Crows", CDLUpsideGap2Crows());
ADD("CDLXSideGap3Methods", CDL_XSideGap3Methods());
#undef ADD
return n;
}
// --- quick aliases (underscore helpers used elsewhere in this file) ---
// Keep only wrappers that map underscore-names -> real Zorro functions.
var CDL_RickshawMan() { return CDLRickshawMan(); }
var CDL_RiseFall3Methods() { return CDLRiseFall3Methods(); }
var CDL_ShootingStar() { return CDLShootingStar(); }
var CDL_ShortLine() { return CDLShortLine(); }
var CDL_SpinningTop() { return CDLSpinningTop(); }
var CDL_StalledPattern() { return CDLStalledPattern(); }
var CDL_Takuri() { return CDLTakuri(); }
var CDL_TasukiGap() { return CDLTasukiGap(); }
var CDL_Thrusting() { return CDLThrusting(); }
var CDL_Tristar() { return CDLTristar(); }
var CDL_Unique3River() { return CDLUnique3River(); }
var CDL_XSideGap3Methods() { return CDLXSideGap3Methods(); }
// --------------- Markov relation mapping (unchanged) ----------------
int relFromHL(int sL, int sH){
if(sL <= 0 || sH <= 0) return MC_NONE;
int idxL = (sL - 1)/2; int bullL = ((sL - 1)%2)==1;
int idxH = (sH - 1)/2; int bullH = ((sH - 1)%2)==1;
if(idxL == idxH && bullL == bullH) return sL;
return MC_NONE;
}
int is_H1_close(){ return (Bar % TF_H1) == 0; }
// ------------------ memory estimator integration --------------------
int mem_mb_est() { return rt.mem_mb_est(); }
// =================== CUDA advice cache helpers ======================
void resetAdvCacheForBar() {
if(AdvCacheBar != Bar) {
AdvCacheBar = Bar;
for(int k=0;k<net.N;k++) { AdvHave[k]=0; AdvCache[k]=0; }
}
}
// EXACT same gating behavior as old adviseEq early exits.
int adviseGate(int i) {
if(!allowAdvise(i)) return 0;
if(is(INITRUN)) return 0;
int tight = (mem_mb_est() >= MEM_BUDGET_MB - MEM_HEADROOM_MB);
if(tight) return 0;
// Hit-rate gate (unchanged)
if(net.HitN[i] > 32) {
var h = (var)net.HitEW[i];
var gate = 0.40 + 0.15*(1.0 - MH.Entropy);
if(h < gate) {
if(random() >= 0.5) return 0;
}
}
return 1;
}
// Build a batch over [i0,i1), run GPU once, populate AdvCache for those i.
void computeAdviceBatchRange(int i0, int i1, var lambda, var mean, var energy, var power) {
resetAdvCacheForBar();
if(!CudaReady) return;
if(i0 < 0) i0 = 0;
if(i1 > net.N) i1 = net.N;
if(i0 >= i1) return;
float* X = cuda.hostX();
float* O = cuda.hostOut();
int nf = cuda.featN();
int idx[NET_EQNS];
int bsz = 0;
for(int i=i0;i<i1;i++) {
if(AdvHave[i]) continue;
if(!adviseGate(i)) {
AdvHave[i] = 1;
AdvCache[i] = (fvar)0;
continue;
}
// build features exactly like old DTREE path did
int tid = dt.safeTreeIndexFromEq((int)net.EqTreeId[i], dt.TreeN);
var pred = dt.predByTid(tid);
var S[ADV_EQ_NF];
buildEqFeatures(i, lambda, mean, energy, power, pred, S);
for(int k=0;k<ADV_EQ_NF;k++)
X[bsz*nf + k] = (float)S[k];
idx[bsz] = i;
bsz++;
if(bsz >= cuda.cap()) break;
}
if(bsz <= 0) return;
if(!cuda.inferBatch(X, bsz, O)) {
CudaReady = 0; // fail closed; avoid repeated driver errors
return;
}
for(int j=0;j<bsz;j++) {
int eq = idx[j];
var p = (var)O[j]; // expected in [-1..1]
p = clamp(p, -1.0, 1.0);
AdvCache[eq] = (fvar)p;
AdvHave[eq] = 1;
}
}
// ----------------------- strategy init/cleanup ----------------------
void init() {
if(ready) return;
BarPeriod = BAR_PERIOD;
LookBack = max(300, NWIN);
set(PLOTNOW);
asset(ASSET_SYMBOL);
// effective K
net.Keff = KPROJ;
if(net.Keff < 1) net.Keff = 1;
if(net.Keff > net.K) net.Keff = net.K;
// allocate components
net.allocate();
MH.alloc(); ML.alloc(); MR.alloc();
MH.Alpha = MC_Alpha; ML.Alpha = MC_Alpha; MR.Alpha = MC_Alpha;
dt.allocDepthLUT();
dt.DTreeExp = 0;
dt.Root = dt.createNode(MAX_DEPTH);
rt.RT_TreeMaxDepth = MAX_DEPTH;
dt.refreshDepthW();
// index tree and map EqTreeId
reindexTreeAndMap();
// projection matrix
net.randomizeRP();
net.computeProjection();
// initial full rewire
rewireEpoch(0,0,0,0);
log.writeEqHeaderOnce();
RewirePos=0; RewirePasses=0;
UpdatePos=0; UpdatePasses=0;
// seed cache reset
seedBar = -1;
memset(haveSeed,0,sizeof(haveSeed));
// ---- CUDA advisor init ----
CudaReady = 0;
if(cuda.init(ADV_EQ_NF, NET_EQNS)) {
CudaReady = 1;
}
AdvCacheBar = -999999;
memset(AdvHave,0,sizeof(AdvHave));
memset(AdvCache,0,sizeof(AdvCache));
ready = 1;
printf("\n[Alpha12] init done: N=%i D=%i K=%i (Keff=%i) Depth=%i est=%i MB CUDA=%i",
net.N, net.D, net.K, net.Keff, rt.RT_TreeMaxDepth, mem_mb_est(), CudaReady);
}
void cleanup() {
if(!ready) return;
// CUDA shutdown first
if(CudaReady) {
cuda.shutdown();
CudaReady = 0;
}
MH.freeMem(); ML.freeMem(); MR.freeMem();
dt.freeAll();
pool.freeAll();
net.freeAll();
ready = 0;
}
// --------------------- core tree reindex & mapping -------------------
void reindexTreeAndMap(){
dt.TreeN = 0;
dt.indexTreeDFS(dt.Root);
if(dt.TreeN <= 0){
dt.TreeN = 1;
if(dt.TreeIdx) dt.TreeIdx[0] = dt.Root;
}
{ int i; for(i=0;i<net.N;i++) net.EqTreeId[i] = (i16)(i % dt.TreeN); }
dt.resizePredCacheToTree();
dt.refreshEqAngles(net.EqTreeId, net.N);
dt.maybeShrinkTreeIdx();
rt.recalcTreeBytes(dt);
int includeExpr = (LOG_EXPR_TEXT && net.Sym && !net.SymFreed) ? 1 : 0;
rt.computeMemFixedBytes(net, dt, includeExpr);
rt.MemFixedBytes += 3*(MC_STATES*MC_STATES*(int)sizeof(int) + MC_STATES*(int)sizeof(int));
}
// --------------------- Markov updates (OOP) --------------------------
void updateMarkov_5M(){
// fill member buffer (no static locals)
buildCDL_TA61(CDL_L, 0);
int s = MarkovChain::stateFromCDL(CDL_L, MC_ACT_dyn);
if(Bar > LookBack) ML.update(ML.Prev, s);
ML.Prev = s;
if(s > 0 && s < MC_STATES){
if(ML.RowSum[s] > 0) ML.rowStats(s, &ML.PBullNext, &ML.Entropy);
ML.Cur = s;
}
}
void updateMarkov_1H(){
int saveTF = TimeFrame;
TimeFrame = TF_H1;
// fill member buffer (no static locals)
buildCDL_TA61(CDL_H, 0);
int sH = MarkovChain::stateFromCDL(CDL_H, MC_ACT_dyn);
if(Bar > LookBack) MH.update(MH.Prev, sH);
MH.Prev = sH;
if(sH > 0 && sH < MC_STATES){
if(MH.RowSum[sH] > 0) MH.rowStats(sH, &MH.PBullNext, &MH.Entropy);
MH.Cur = sH;
}
TimeFrame = saveTF;
}
void updateMarkov_REL(){
int r = relFromHL(ML.Cur, MH.Cur);
if(Bar > LookBack) MR.update(MR.Prev, r);
MR.Prev = r;
if(r > 0 && r < MC_STATES){
if(MR.RowSum[r] > 0) MR.rowStats(r, &MR.PBullNext, &MR.Entropy);
MR.Cur = r;
}
}
void updateAllMarkov(){
MH.Alpha = MC_Alpha;
ML.Alpha = MC_Alpha;
MR.Alpha = MC_Alpha;
updateMarkov_5M();
if(is_H1_close()){
updateMarkov_1H();
updateMarkov_REL();
}
}
// --------------------- Advisor rotation (unchanged) ------------------
int allowAdvise(int i){
int groups = net.N / AdviseMax;
if(groups < 1) groups = 1;
return ((i / AdviseMax) % groups) == (Bar % groups);
}
// --------------------- DTREE advisor wrappers ------------------------
// NOTE: CUDA-backed (batched + cached) with identical gating.
var adviseEq(int i, var lambda, var mean, var energy, var power) {
// keep the exact same gating behavior
if(!adviseGate(i)) return 0;
resetAdvCacheForBar();
if(AdvHave[i]) return (var)AdvCache[i];
// If we reach here, this equation wasn’t pre-batched by heavyUpdateChunk()
// (or adviseEq was called elsewhere). We do a tiny batch fallback.
if(CudaReady) {
computeAdviceBatchRange(i, i+1, lambda, mean, energy, power);
if(AdvHave[i]) return (var)AdvCache[i];
}
// CPU fallback: neutral
AdvHave[i] = 1;
AdvCache[i] = (fvar)0;
return 0;
}
var adviseSeed(int i, var lambda, var mean, var energy, var power) {
if(seedBar != Bar) {
for(int k=0;k<net.N;k++) haveSeed[k]=0;
seedBar = Bar;
}
if(i < 0) i = 0;
if(i >= net.N) i = i % net.N;
if(!allowAdvise(i)) return 0;
if(!haveSeed[i]) {
seedVal[i] = adviseEq(i, lambda, mean, energy, power);
haveSeed[i] = 1;
}
return seedVal[i];
}
static var mix01(var a, int salt){
var z = sin(123.456*a + 0.001*salt) + cos(98.765*a + 0.002*salt);
return tanh(0.75*z);
}
static var mapA(var a,var lo,var hi){ return mapUnit(a,lo,hi); }
// ------------------- Feature builders (unchanged logic) ---------------
void buildEqFeatures(int i, var lambda, var mean, var energy, var power, var pred, var* S /*ADV_EQ_NF*/) {
int tid = dt.safeTreeIndexFromEq((int)net.EqTreeId[i], dt.TreeN);
Node* t = dt.treeAt(tid);
var th_i = (dt.EqTheta ? dt.EqTheta[i] : 0);
var dphi = DTree::angDiff(dt.CycPh, th_i);
var alignC = cos(dphi);
var alignS = sin(dphi);
S[0] = nrm_s(net.State[i]);
S[1] = nrm_s(mean);
S[2] = nrm_scl(power,0.05);
S[3] = nrm_scl(energy,0.01);
S[4] = nrm_s(lambda);
S[5] = sat100(200.0*(pred-0.5));
S[6] = sat100(200.0*((var)t->d/MAX_DEPTH)-100.0);
S[7] = sat100(1000.0*t->r);
S[8] = nrm_s((var)net.TreeTerm[i]);
S[9] = sat100( (200.0/3.0) * (var)((int)net.Mode[i]) - 100.0 );
S[10] = sat100(200.0*(MH.PBullNext-0.5));
S[11] = sat100(200.0*(MH.Entropy-0.5));
S[12] = sat100(200.0*((var)net.HitEW[i] - 0.5));
S[13] = sat100(100.*alignC);
S[14] = sat100(100.*alignS);
S[15] = sat100(200.0*(ML.PBullNext - 0.5));
S[16] = sat100(200.0*(ML.Entropy - 0.5));
S[17] = sat100(200.0*(MR.PBullNext - 0.5));
S[18] = sat100(200.0*(MR.Entropy - 0.5));
sanitize(S,ADV_EQ_NF);
}
// ---------------- adjacency scoring (heuristic only) ------------------
var scorePairSafe(int i, int j, var lambda, var mean, var energy, var power){
int ti = dt.safeTreeIndexFromEq((int)net.EqTreeId[i], dt.TreeN);
int tj = dt.safeTreeIndexFromEq((int)net.EqTreeId[j], dt.TreeN);
Node* ni = dt.treeAt(ti);
Node* nj = dt.treeAt(tj);
var simD = 1.0 / (1.0 + abs((var)ni->d - (var)nj->d));
var dr = 50.0*abs(ni->r - nj->r);
var simR = 1.0 / (1.0 + dr);
var predi = dt.predByTid(ti);
var predj = dt.predByTid(tj);
var pred = 0.5*(predi + predj);
var score = 0.5*pred + 0.3*simD + 0.2*simR;
return 2.0*score - 1.0;
}
void rewireAdjacency_DTREE_range(int i0,int i1, var lambda, var mean, var energy, var power){
int i,d,c,best,cand;
if(i0<0) i0=0; if(i1>net.N) i1=net.N;
for(i=i0;i<i1;i++){
for(d=0; d<net.D; d++){
var bestScore = -2; best=-1;
for(c=0;c<CandNeigh;c++){
cand = (int)random(net.N);
if(cand==i) continue;
int clash=0,k;
for(k=0;k<d;k++){
int prev = net.Adj