From 6e0c9abff2ecdd777e284e24b3a9d6cdfcd89ded Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Sun, 31 May 2026 12:05:49 +0200 Subject: [PATCH] =?UTF-8?q?feat(rl):=20regime=5Fobserver=20trainer=20wirin?= =?UTF-8?q?g=20=E2=80=94=20loaders=20+=20struct=20+=20launchers=20(F1.4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds: - include_bytes! for rl_regime_flat_count + rl_regime_observer cubins - IntegratedTrainer struct fields: 2 modules + 2 functions + flat_count_d helper buffer - new() cubin loading + struct field assignment - launch_rl_regime_flat_count(): Grid=(1), Block=(256), smem=256*sizeof(int) - launch_rl_regime_observer(): Grid=(1), Block=(1), smem=0 Does NOT wire launchers into step_with_lobsim (that's F1.5). Co-Authored-By: Claude Sonnet 4.6 --- crates/ml-alpha/src/trainer/integrated.rs | 79 +++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/crates/ml-alpha/src/trainer/integrated.rs b/crates/ml-alpha/src/trainer/integrated.rs index fc8130c37..14a603671 100644 --- a/crates/ml-alpha/src/trainer/integrated.rs +++ b/crates/ml-alpha/src/trainer/integrated.rs @@ -216,6 +216,14 @@ const RL_KELLY_FRACTION_CONTROLLER_CUBIN: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/rl_kelly_fraction_controller.cubin")); const RL_EVAL_WARMUP_DECAY_CUBIN: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/rl_eval_warmup_decay.cubin")); +// Regime observer (F1.2 + F1.3) — flat-count block-reduce + state-machine +// signal emitter. Launched each env step: flat_count first (writes +// flat_count_d), then regime_observer (reads flat_count_d + ISV state, +// emits 6 surface signals + Welford state + ε_recovery_live). +const RL_REGIME_FLAT_COUNT_CUBIN: &[u8] = + include_bytes!(concat!(env!("OUT_DIR"), "/rl_regime_flat_count.cubin")); +const RL_REGIME_OBSERVER_CUBIN: &[u8] = + include_bytes!(concat!(env!("OUT_DIR"), "/rl_regime_observer.cubin")); const RL_WIN_RATE_EMA_UPDATE_CUBIN: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/rl_win_rate_ema_update.cubin")); const RL_AVG_WIN_LOSS_EMA_UPDATE_CUBIN: &[u8] = @@ -683,6 +691,15 @@ pub struct IntegratedTrainer { // v9 (2026-05-31): defensive eval-boundary calibration kernel. _rl_eval_warmup_decay_module: Arc, rl_eval_warmup_decay_fn: CudaFunction, + // Regime observer (F1.4) — emits unified state-machine signals consumed + // by Kelly (F2), v9 (F3), popart (F4), IQN τ (F5). + _rl_regime_flat_count_module: Arc, + rl_regime_flat_count_fn: CudaFunction, + _rl_regime_observer_module: Arc, + rl_regime_observer_fn: CudaFunction, + /// Per-step flat-count helper buffer: holds the block-reduce output + /// (number of accounts with lots==0) for one step. Length 1. + flat_count_d: CudaSlice, // EMA producers feeding the new controllers. _rl_win_rate_ema_update_module: Arc, rl_win_rate_ema_update_fn: CudaFunction, @@ -1607,6 +1624,22 @@ impl IntegratedTrainer { let rl_eval_warmup_decay_fn = rl_eval_warmup_decay_module .load_function("rl_eval_warmup_decay") .context("load rl_eval_warmup_decay")?; + // Regime observer (F1.4). + let rl_regime_flat_count_module = ctx + .load_cubin(RL_REGIME_FLAT_COUNT_CUBIN.to_vec()) + .context("load rl_regime_flat_count cubin")?; + let rl_regime_flat_count_fn = rl_regime_flat_count_module + .load_function("rl_regime_flat_count") + .context("load rl_regime_flat_count function")?; + let rl_regime_observer_module = ctx + .load_cubin(RL_REGIME_OBSERVER_CUBIN.to_vec()) + .context("load rl_regime_observer cubin")?; + let rl_regime_observer_fn = rl_regime_observer_module + .load_function("rl_regime_observer") + .context("load rl_regime_observer function")?; + let flat_count_d = stream + .alloc_zeros::(1) + .context("alloc flat_count_d")?; let rl_win_rate_ema_update_module = ctx .load_cubin(RL_WIN_RATE_EMA_UPDATE_CUBIN.to_vec()) .context("load rl_win_rate_ema_update cubin")?; @@ -2685,6 +2718,11 @@ impl IntegratedTrainer { rl_kelly_fraction_controller_fn, _rl_eval_warmup_decay_module: rl_eval_warmup_decay_module, rl_eval_warmup_decay_fn, + _rl_regime_flat_count_module: rl_regime_flat_count_module, + rl_regime_flat_count_fn, + _rl_regime_observer_module: rl_regime_observer_module, + rl_regime_observer_fn, + flat_count_d, _rl_win_rate_ema_update_module: rl_win_rate_ema_update_module, rl_win_rate_ema_update_fn, _rl_avg_win_loss_ema_update_module: rl_avg_win_loss_ema_update_module, @@ -3793,6 +3831,47 @@ impl IntegratedTrainer { Ok(()) } + /// Regime observer helper — block-reduce per-account flat count. + /// Output: `flat_count_d[0]` = number of accounts with lots==0. + /// Launch: Grid=(1,1,1), Block=(256,1,1), smem=256*sizeof(int). + pub fn launch_rl_regime_flat_count(&mut self, lots_d: &CudaSlice, b_size: usize) -> Result<()> { + let mut args = RawArgs::new(); + args.push_ptr(lots_d.raw_ptr()); + args.push_ptr(self.flat_count_d.raw_ptr()); + args.push_i32(b_size as i32); + let mut ptrs = args.build_arg_ptrs(); + let smem_bytes = (256 * std::mem::size_of::()) as u32; + unsafe { + raw_launch( + self.rl_regime_flat_count_fn.cu_function(), + (1, 1, 1), (256, 1, 1), smem_bytes, + self.raw_stream, + &mut ptrs[..args.len()], + ).map_err(|e| anyhow::anyhow!("rl_regime_flat_count: {:?}", e))?; + } + Ok(()) + } + + /// Regime observer — emits 6 surface signals + Welford state + ε_recovery_live. + /// Reads: kelly_f (prior step), cooldown, flat_count, worst_pnl, Welford state. + /// Launch: Grid=(1,1,1), Block=(1,1,1), smem=0. + pub fn launch_rl_regime_observer(&self, b_size: usize) -> Result<()> { + let mut args = RawArgs::new(); + args.push_ptr(self.isv_dev_ptr); + args.push_ptr(self.flat_count_d.raw_ptr()); + args.push_i32(b_size as i32); + let mut ptrs = args.build_arg_ptrs(); + unsafe { + raw_launch( + self.rl_regime_observer_fn.cu_function(), + (1, 1, 1), (1, 1, 1), 0, + self.raw_stream, + &mut ptrs[..args.len()], + ).map_err(|e| anyhow::anyhow!("rl_regime_observer: {:?}", e))?; + } + Ok(()) + } + /// Adaptive risk management — Layer 4 input EMA producer (win_rate). /// Reads `rewards_d`, `dones_d` [b_size] f32; outcome derived inline. /// Writes ISV[RL_WIN_RATE_EMA_INDEX = 677].