OverviewFilesCommitsIssuesDocsReleasesPeers

basal-agent commits / b28156b

basal-agent: agent_learn.c — the slow loop closed (agent LEARNS its world model)
The agent babbles (random actions), records (action, observation) experience, and learns the controlled HMM (emission E, action-conditioned transitions T[a]) by controlled Baum-Welch, then controls with only the learned model. Result (both symmetric and asymmetric emissions): SYMMETRIC : TRUE 0.636 | LEARNED 0.636 | NO-MODEL 0.559 T[1][0]->to=1 = 0.89 (shift recovered) ASYMMETRIC: TRUE 0.709 | LEARNED 0.709 | NO-MODEL 0.635 T[1][0]->to=1 = 0.91 The learned model matches the handed-true-model control -> the world model is ACQUIRED, not given. Combined with belief_field_agent.c the loop is autonomous: babble -> LEARN (slow) -> infer by belief-mating (fast) -> decide toward setpoint -> act. Honest path (recorded in the header): two wrong turns first. (1) Wiring mom.c's spectral observable- operator read in directly FAILED (worse than random) — the uncontrolled OOM doesn't transfer to a controlled process; controlled spectral (PSR) is subtle and stays the tool for fractal-hard structure. (2) EM then learned nothing (chance, T uniform), which I MISDIAGNOSED as a symmetry valley — it was an off-by-one action-indexing bug (transition (t-1)->t is governed by Ab[t], not Ab[t-1]). Fixed -> EM recovers the operators in both envs. Lesson: characterize the bug, don't narrate a valley that isn't there. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
b28156b6d6e84fa28b805b0154af226e9887886c
by plankatron <fleeky@gmail.com> · 2026-07-22T02:40:57.000Z

Changed files (2) +128 -0

.gitignore +1 -0
……@@ -34,3 +34,4 @@ bridges
3434coemerge
3535integrated
3636belief_field_agent
37agent_learn
agent_learn.c +127 -0
……@@ -0,0 +1,127 @@
1/* agent_learn.c — the SLOW LOOP: the agent LEARNS its world model from experience, not handed it.
2 *
3 * belief_field_agent.c was handed the operators. Here the agent BABBLES (random actions), records
4 * (action, observation) experience, and learns the controlled HMM (emission E, action-conditioned
5 * transitions T[a]) by controlled Baum-Welch (EM), then controls using only the learned model. Result:
6 * the learned model recovers the shift dynamics (T[a=1] from state 0 peaks at ~0.9 on 'to=1') and controls
7 * AS WELL AS the agent handed the true model, far better than acting on raw observation. The world model is
8 * now ACQUIRED, not given -- the last autonomy piece. Tested on two emission structures (symmetric and
9 * asymmetric per-state) to show learning is robust; both close the loop.
10 *
11 * HONEST PATH (kept as a record). Two wrong turns preceded this: (1) a first version wired mom.c's spectral
12 * observable-operator read directly in -- it failed (worse than random) because the uncontrolled OOM does
13 * not transfer trivially to a controlled process (controlled spectral learning / PSR is genuinely subtle;
14 * that remains the right tool for FRACTAL-hard structure, per mom.c, but a proper task, not a quick wire-in).
15 * (2) EM then learned NOTHING (control = chance, T uniform), which I misdiagnosed as a symmetry "valley";
16 * it was actually an off-by-one ACTION-INDEXING bug -- the transition (t-1)->t is governed by Ab[t], not
17 * Ab[t-1]. Fixed, EM recovers the operators cleanly in BOTH environments. The lesson: characterize the bug,
18 * do not narrate a valley that is not there.
19 *
20 * build: cc -O2 -Wall -std=c11 -o agent_learn agent_learn.c -lm
21 */
22#include <math.h>
23#include <stdio.h>
24
25#define K 3
26#define TN 0.15
27#define GOAL 0
28#define TGT 0
29#define NB 100000
30#define ITERS 60
31#define CONTROL 300000
32
33static unsigned long long RNG;
34static unsigned long long xs(void){ RNG^=RNG<<13; RNG^=RNG>>7; RNG^=RNG<<17; return RNG; }
35static double urand(void){ return (double)(xs()>>11)*(1.0/9007199254740992.0); }
36static int rk(void){ return (int)(xs()%K); }
37
38static double Emat[K][K]; /* current true emission (set per environment) */
39static void set_symmetric(void){ for(int s=0;s<K;s++) for(int x=0;x<K;x++) Emat[s][x]=(s==x)?0.60:0.20; }
40static void set_asymmetric(void){ double A[K][K]={{0.70,0.20,0.10},{0.15,0.70,0.15},{0.10,0.25,0.65}}; for(int s=0;s<K;s++)for(int x=0;x<K;x++) Emat[s][x]=A[s][x]; }
41
42static double Ptrans(int j,int i,int a){ return (1.0-TN)*((j==(i+a)%K)?1.0:0.0) + TN/K; }
43static double Pemit (int x,int s){ return Emat[s][x]; }
44static int step_env(int s,int a){ return (urand()<1.0-TN)? (s+a)%K : rk(); }
45static int emit_env(int s){ double u=urand(),a=0; for(int x=0;x<K;x++){ a+=Emat[s][x]; if(u<a) return x; } return K-1; }
46
47static double run_true(void){
48 RNG=0x9e3779b97f4a7c15ULL; int s=rk(); long hit=0; double b[K]={1.0/K,1.0/K,1.0/K};
49 for(long t=0;t<CONTROL;t++){
50 int best=0; double bv=-1; for(int a=0;a<K;a++){ double m=0; for(int i=0;i<K;i++) m+=b[i]*Ptrans(GOAL,i,a); if(m>bv){bv=m;best=a;} }
51 s=step_env(s,best); int x=emit_env(s); if(s==GOAL) hit++;
52 double bp[K]={0,0,0}; for(int j=0;j<K;j++){ double v=0; for(int i=0;i<K;i++) v+=b[i]*Ptrans(j,i,best); bp[j]=v*Pemit(x,j); }
53 double z=0; for(int j=0;j<K;j++) z+=bp[j]; if(z<1e-300)z=1e-300; for(int j=0;j<K;j++) b[j]=bp[j]/z;
54 }
55 return (double)hit/CONTROL;
56}
57static double run_nomodel(void){
58 RNG=0x9e3779b97f4a7c15ULL; int s=rk(),lastx=0; long hit=0;
59 for(long t=0;t<CONTROL;t++){ int a=((GOAL-lastx)%K+K)%K; s=step_env(s,a); int x=emit_env(s); if(s==GOAL)hit++; lastx=x; }
60 return (double)hit/CONTROL;
61}
62
63static double E[K][K], Tr[K][K][K], pi[K];
64static int Xb[NB], Ab[NB];
65static double al[NB][K], be[NB][K], cs[NB];
66
67static void em(void){
68 RNG=0xd1b54a32d192ed03ULL; int s=rk();
69 for(long t=0;t<NB;t++){ int a=rk(); s=step_env(s,a); Ab[t]=a; Xb[t]=emit_env(s); }
70 for(int i=0;i<K;i++){ pi[i]=1.0/K; double z=0; for(int x=0;x<K;x++){ E[i][x]=(i==x)?0.5:0.25; z+=E[i][x]; } for(int x=0;x<K;x++) E[i][x]/=z;
71 for(int a=0;a<K;a++) for(int j=0;j<K;j++) Tr[a][i][j]=1.0/K; }
72 for(int it=0; it<ITERS; it++){
73 double s0=0; for(int i=0;i<K;i++){ al[0][i]=pi[i]*E[i][Xb[0]]; s0+=al[0][i]; }
74 if(s0<1e-300)s0=1e-300; cs[0]=s0; for(int i=0;i<K;i++) al[0][i]/=s0;
75 for(long t=1;t<NB;t++){ double st=0; int a=Ab[t]; /* transition (t-1)->t is governed by Ab[t] */
76 for(int j=0;j<K;j++){ double v=0; for(int i=0;i<K;i++) v+=al[t-1][i]*Tr[a][i][j]; al[t][j]=v*E[j][Xb[t]]; st+=al[t][j]; }
77 if(st<1e-300)st=1e-300; cs[t]=st; for(int j=0;j<K;j++) al[t][j]/=st; }
78 for(int i=0;i<K;i++) be[NB-1][i]=1.0;
79 for(long t=NB-2;t>=0;t--){ int a=Ab[t+1]; /* transition t->(t+1) is governed by Ab[t+1] */
80 for(int i=0;i<K;i++){ double v=0; for(int j=0;j<K;j++) v+=Tr[a][i][j]*E[j][Xb[t+1]]*be[t+1][j]; be[t][i]=v/cs[t+1]; } }
81 double Enum[K][K]={{0}},Eden[K]={0},Tnum[K][K][K]={{{0}}},Tden[K][K]={{0}},pin[K]={0};
82 for(long t=0;t<NB;t++){ for(int i=0;i<K;i++){ double g=al[t][i]*be[t][i]; Enum[i][Xb[t]]+=g; Eden[i]+=g; if(t==0) pin[i]=g; } }
83 for(long t=0;t<NB-1;t++){ int a=Ab[t+1]; /* transition t->(t+1) is governed by Ab[t+1] */
84 for(int i=0;i<K;i++){ double gi=0; for(int j=0;j<K;j++){ double xi=al[t][i]*Tr[a][i][j]*E[j][Xb[t+1]]*be[t+1][j]/cs[t+1]; Tnum[a][i][j]+=xi; gi+=xi; } Tden[a][i]+=gi; } }
85 for(int i=0;i<K;i++){ double z=Eden[i]<1e-12?1e-12:Eden[i]; for(int x=0;x<K;x++) E[i][x]=Enum[i][x]/z; }
86 for(int a=0;a<K;a++) for(int i=0;i<K;i++){ double z=Tden[a][i]<1e-12?1e-12:Tden[a][i]; for(int j=0;j<K;j++) Tr[a][i][j]=Tnum[a][i][j]/z; }
87 double zp=0; for(int i=0;i<K;i++) zp+=pin[i]; if(zp<1e-12)zp=1e-12; for(int i=0;i<K;i++) pi[i]=pin[i]/zp;
88 }
89}
90static double run_learned(int gstar){
91 RNG=0x9e3779b97f4a7c15ULL; int s=rk(); long hit=0; double b[K]; for(int i=0;i<K;i++) b[i]=pi[i];
92 for(long t=0;t<CONTROL;t++){
93 int best=0; double bv=-1; for(int a=0;a<K;a++){ double m=0; for(int i=0;i<K;i++) m+=b[i]*Tr[a][i][gstar]; if(m>bv){bv=m;best=a;} }
94 s=step_env(s,best); int x=emit_env(s); if(s==GOAL) hit++;
95 double bp[K]={0,0,0}; for(int j=0;j<K;j++){ double v=0; for(int i=0;i<K;i++) v+=b[i]*Tr[best][i][j]; bp[j]=v*E[j][x]; }
96 double z=0; for(int j=0;j<K;j++) z+=bp[j]; if(z<1e-300)z=1e-300; for(int j=0;j<K;j++) b[j]=bp[j]/z;
97 }
98 return (double)hit/CONTROL;
99}
100
101static void run_mode(const char*name){
102 em();
103 int gstar=0; for(int i=1;i<K;i++) if(E[i][TGT]>E[gstar][TGT]) gstar=i;
104 double occ_learn=run_learned(gstar), occ_true=run_true(), occ_nom=run_nomodel();
105 /* is the learned transition informative? peak-off-diagonal test on T[a=1] */
106 double diag1=Tr[1][0][1]; /* should be high (~shift) if learned */
107 printf(" --- %s ---\n",name);
108 printf(" TRUE model %.3f | LEARNED %.3f | NO-MODEL %.3f | chance %.3f\n", occ_true,occ_learn,occ_nom,1.0/K);
109 printf(" learned T[a=1] from-state-0 -> [%.2f %.2f %.2f] (peak at 'to=1' if the shift was learned)\n",Tr[1][0][0],Tr[1][0][1],Tr[1][0][2]);
110 if(occ_learn>occ_nom+0.03 && occ_learn>occ_true-0.06)
111 printf(" => slow loop CLOSES: learned model controls ~as well as the true model (shift T[1][0]->to=1 = %.2f).\n\n",diag1);
112 else
113 printf(" => learned model did not reach handed-model control here -- read the numbers before claiming success.\n\n");
114}
115
116int main(void){
117 printf("=== Agent LEARNS its world model from experience (slow loop closed) ===\n");
118 printf(" Babble %d, controlled EM %d iters, control %d. Goal=state %d via observation TGT=%d.\n\n",NB,ITERS,CONTROL,GOAL,TGT);
119 set_symmetric(); run_mode("SYMMETRIC per-state emissions");
120 set_asymmetric(); run_mode("ASYMMETRIC per-state emissions");
121 printf(" READ: in BOTH environments the agent learned E and T[a] from raw babbling and controls ~as well as\n");
122 printf(" the agent handed the true model -- the world model is ACQUIRED, not given. Combined with the seed\n");
123 printf(" (belief_field_agent.c), the loop is now autonomous: babble -> LEARN the model (slow) -> infer by\n");
124 printf(" belief-mating (fast) -> decide toward the setpoint -> act. mom.c stays the directed-read tool for\n");
125 printf(" fractal-hard structure where local EM would stall (Part A's mess3), which this benign env is not.\n");
126 return 0;
127}