// hearsay_chain.cpp — Phase 2 de-risk: 5-hop retell chain on real 360M. // Measures (a) Jaccard drift hop0->hopK, (b) coherence (length/non-degenerate), (c) determinism. #include #include #include #include #include #include static void decode_str(llama_context*c,const llama_vocab*v,llama_batch&b,int32_t&p,const std::string&s,bool bos){ std::vector t(s.size()+16); int n=llama_tokenize(v,s.c_str(),s.length(),t.data(),t.size(),bos,true); if(n<0){t.resize(-n);n=llama_tokenize(v,s.c_str(),s.length(),t.data(),t.size(),bos,true);} t.resize(n); b.n_tokens=0; for(int i=0;i cd; cd.reserve(nv); for(llama_token t=0;t0)o.append(bf,nc); b.n_tokens=0;b.token[0]=nt;b.pos[0]=p++;b.n_seq_id[0]=1;b.seq_id[0][0]=0; b.logits[0]=true;b.n_tokens=1; if(llama_decode(c,b)!=0)break;} return o; } static std::set toks(std::string s){ for(auto&c:s)c=tolower(c); std::set r; std::stringstream ss(s); std::string w; while(ss>>w){ std::string x; for(char c:w) if(isalpha(c))x+=c; if(x.size()>2)r.insert(x);} return r; } static double jaccard(const std::set&a,const std::set&b){ if(a.empty()||b.empty())return 0; int inter=0; for(auto&x:a)if(b.count(x))inter++; return (double)inter/(a.size()+b.size()-inter); } static std::string retell(llama_model*m,const llama_vocab*v,const std::string& heard,uint64_t seed){ llama_context_params cp=llama_context_default_params(); cp.n_ctx=2048; cp.n_threads=1; cp.n_threads_batch=1; llama_context*ctx=llama_init_from_model(m,cp); std::string user="You overhear someone in the village saying: \""+heard+"\" In your own words, what do you make of it and pass along to others?"; llama_chat_message msg[1]; msg[0].role="user"; msg[0].content=user.c_str(); const char*tm=llama_model_chat_template(m,nullptr); std::vector tp(user.size()+1024); int r=llama_chat_apply_template(tm,msg,1,true,tp.data(),tp.size()); if(r>(int)tp.size()){tp.resize(r);r=llama_chat_apply_template(tm,msg,1,true,tp.data(),tp.size());} std::string prompt=r>0?std::string(tp.data()):user; llama_batch b=llama_batch_init(2048,0,1); int32_t pos=0; decode_str(ctx,v,b,pos,prompt,true); llama_sampler_chain_params sp=llama_sampler_chain_default_params(); llama_sampler*ch=llama_sampler_chain_init(sp); llama_sampler_chain_add(ch,llama_sampler_init_penalties(200,1.15f,0.0f,0.0f)); llama_sampler_chain_add(ch,llama_sampler_init_top_k(50)); llama_sampler_chain_add(ch,llama_sampler_init_top_p(0.9,1)); llama_sampler_chain_add(ch,llama_sampler_init_temp(0.8)); llama_sampler_chain_add(ch,llama_sampler_init_dist(seed)); std::string out=gen(ctx,v,b,pos,ch,90); llama_sampler_free(ch); llama_batch_free(b); llama_free(ctx); return out; } int main(){ llama_backend_init(); llama_model_params mp=llama_model_default_params(); llama_model*m=llama_model_load_from_file("models/smollm2-360m-instruct-q8_0.gguf",mp); if(!m){std::cerr<<"load fail\n";return 1;} const llama_vocab*v=llama_model_get_vocab(m); std::string seed_mem="The village of Brindlemark is magical, with glowing trees and sparkling lakes behind the houses."; std::cout<<"HOP0 (seed): "<140?cur.substr(0,140):cur; std::cout<<"HOP"<