UNPKG

gp-lite

Version:

Tiny, zero-dependency GA/GP engine for TypeScript/JS with first-class types, deterministic RNG, and budget-aware runs.

3 lines 28 kB
var Ue=Object.defineProperty,He=Object.defineProperties;var We=Object.getOwnPropertyDescriptors;var Oe=Object.getOwnPropertySymbols;var Be=Object.prototype.hasOwnProperty,Ve=Object.prototype.propertyIsEnumerable;var ze=(t,n,e)=>n in t?Ue(t,n,{enumerable:true,configurable:true,writable:true,value:e}):t[n]=e,ue=(t,n)=>{for(var e in n||(n={}))Be.call(n,e)&&ze(t,e,n[e]);if(Oe)for(var e of Oe(n))Ve.call(n,e)&&ze(t,e,n[e]);return t},Te=(t,n)=>He(t,We(n));var Ke=(t,n)=>{for(var e in n)Ue(t,e,{get:n[e],enumerable:true});};var ie=(t,n,e)=>new Promise((s,i)=>{var o=a=>{try{l(e.next(a));}catch(r){i(r);}},u=a=>{try{l(e.throw(a));}catch(r){i(r);}},l=a=>a.done?s(a.value):Promise.resolve(a.value).then(o,u);l((e=e.apply(t,n)).next());});function Xe(t){var u,l,a,r;let n=(u=t.avgFitnessHistory)==null?void 0:u.at(-1),e=(l=t.invalidCountHistory)==null?void 0:l.at(-1),s=(a=t.validShareHistory)==null?void 0:a.at(-1),i=t.metrics;return ["GP Result",` bestFitness: ${$e(t.bestFitness)}`,` generations: ${t.generations}`,` stopReason: ${(r=t.stopReason)!=null?r:"generations"}`,t.elapsedMs!==void 0?` elapsedMs: ${t.elapsedMs}`:void 0,i?` cfg: pop=${i.config.popSize}, gens=${i.config.generations}, cx=${i.config.cxProb}, mut=${i.config.mutProb}, imm=${i.config.immigration}, tour=${i.config.tournament}, stall=${i.config.stall}`:void 0,n!==void 0?` avgFitness(last): ${$e(n)}`:void 0,e!==void 0?` invalidCount(last): ${e}`:void 0,s!==void 0?` validShare(last): ${(s*100).toFixed(1)}%`:void 0,i?` evaluations: ${i.evaluations} (invalid: ${i.invalidEvaluations}, repaired: ${i.repaired}, repairFailures: ${i.repairFailures})`:void 0,i?` fitnessIssues: errors=${i.fitnessErrors}, nonFinite=${i.nonFiniteFitness}`:void 0,i?` ops: mutations=${i.mutations}, crossovers=${i.crossovers}, selections=${i.selections}, immigrants=${i.immigrants}, elites/gen=${i.elitesPerGen}`:void 0,i?` budgets: wallMs=${i.config.maxWallMs}, evals=${i.config.maxEvaluations}`:void 0].filter(Boolean).join(` `)}function $e(t){return Number.isFinite(t)?t%1===0?String(t):t.toFixed(4):String(t)}function q(t=Date.now()){let n=t>>>0,e=()=>{n|=0,n=Math.imul(n+1831565813,1)|0;let s=Math.imul(n^n>>>15,1|n);return s^=s+Math.imul(s^s>>>7,61|s),((s^s>>>14)>>>0)/4294967296};return {next:e,int:s=>Math.floor(s*e())}}function ye(t){try{let n=globalThis.structuredClone;if(typeof n=="function")return n(t)}catch(n){}return Array.isArray(t)?t.slice():t&&typeof t=="object"?ue({},t):t}var ke={};Ke(ke,{DEFAULT_CONCURRENCY:()=>Ae,DEFAULT_CROSSOVER_CHILDREN:()=>Se,DEFAULT_CX_PROB:()=>Pe,DEFAULT_ELITE:()=>Ge,DEFAULT_GENERATIONS:()=>Fe,DEFAULT_IMMIGRATION:()=>Re,DEFAULT_MAX_EVALUATIONS:()=>Ie,DEFAULT_MAX_WALL_MS:()=>Ne,DEFAULT_MUT_PROB:()=>je,DEFAULT_POP_SIZE:()=>Me,DEFAULT_STALL:()=>we,DEFAULT_TARGET_FITNESS:()=>_e,DEFAULT_TOURNAMENT:()=>Ce});var Me=100,Fe=1e3,Ge=t=>Math.max(1,Math.floor(.02*t)),Pe=.8,je=.2,Se=1,Re=.02,Ce=3,we=50,_e=1/0,Ne=1/0,Ie=1/0,Ae=1;function me(t){var u,l,a,r,m,p,f,g,b,T,_,h,M,L;let n=(u=t.popSize)!=null?u:100,e=(l=t.elite)!=null?l:Ge(n),s=(r=(a=t.maxWallMs)!=null?a:t.timeLimitMs)!=null?r:1/0,i=(m=t.cxProb)!=null?m:.8,o=(p=t.mutProb)!=null?p:1-i;return {popSize:n,generations:(f=t.generations)!=null?f:1e3,elite:e,cxProb:i,mutProb:o,crossoverChildren:(g=t.crossoverChildren)!=null?g:1,immigration:(b=t.immigration)!=null?b:.02,tournament:(T=t.tournament)!=null?T:3,stall:(_=t.stall)!=null?_:50,targetFitness:(h=t.targetFitness)!=null?h:1/0,timeLimitMs:s,maxWallMs:s,maxEvaluations:(M=t.maxEvaluations)!=null?M:1/0,concurrency:(L=t.concurrency)!=null?L:1}}var ce=class extends Error{constructor(n,e){super(n),this.name="GPLiteError",e&&(this.code=e);}},E=class extends ce{constructor(n,e){super(n,e),this.name="ConfigError";}},S=class extends ce{constructor(n,e){super(n,e),this.name="ProblemError";}},ge=class extends ce{constructor(n,e){super(n,e),this.name="EvolutionError";}};function he(t){if(t.popSize!==void 0&&(t.popSize<2||!Number.isInteger(t.popSize)))throw new E("Population size must be an integer >= 2","E_CFG_POPSIZE");if(t.generations!==void 0&&(t.generations<1||!Number.isInteger(t.generations)))throw new E("Generations must be an integer >= 1","E_CFG_GENERATIONS");if(t.elite!==void 0&&(t.elite<0||!Number.isInteger(t.elite)))throw new E("Elite count must be a non-negative integer","E_CFG_ELITE");if(t.cxProb!==void 0&&(t.cxProb<0||t.cxProb>1))throw new E("Crossover probability must be between 0 and 1","E_CFG_CXPROB");if(t.mutProb!==void 0&&(t.mutProb<0||t.mutProb>1))throw new E("Mutation probability must be between 0 and 1","E_CFG_MUTPROB");if(t.immigration!==void 0&&(t.immigration<0||t.immigration>1))throw new E("Immigration rate must be between 0 and 1","E_CFG_IMMIGRATION");if(t.cxProb!==void 0&&t.mutProb!==void 0){let n=t.cxProb+t.mutProb;if(Math.abs(n-1)>1e-6)throw new E("cxProb + mutProb must sum to 1 (immigration is separate)","E_CFG_PROPORTIONS_SUM")}if(t.tournament!==void 0&&(t.tournament<1||!Number.isInteger(t.tournament)))throw new E("Tournament size must be an integer >= 1","E_CFG_TOURNAMENT");if(t.maxWallMs!==void 0&&(t.maxWallMs<0||!Number.isFinite(t.maxWallMs)))throw new E("maxWallMs must be a finite number >= 0","E_CFG_MAX_WALL");if(t.maxEvaluations!==void 0&&(t.maxEvaluations<0||!Number.isFinite(t.maxEvaluations)))throw new E("maxEvaluations must be a finite number >= 0","E_CFG_MAX_EVALS");if(t.concurrency!==void 0&&(!Number.isInteger(t.concurrency)||t.concurrency<1))throw new E("concurrency must be an integer >= 1","E_CFG_CONCURRENCY");if(t.fitnessTimeoutMs!==void 0&&(t.fitnessTimeoutMs<0||!Number.isFinite(t.fitnessTimeoutMs)))throw new E("fitnessTimeoutMs must be a finite number >= 0","E_CFG_FITNESS_TIMEOUT");if(t.stall!==void 0&&(t.stall<0||!Number.isInteger(t.stall)))throw new E("stall must be a non-negative integer","E_CFG_STALL");if(t.targetFitness!==void 0&&!Number.isFinite(t.targetFitness)&&t.targetFitness!==1/0)throw new E("targetFitness must be a finite number or Infinity","E_CFG_TARGET_FITNESS")}function de(t){if(!t.fitness)throw new S("Problem must have a fitness function","E_PROBLEM_FITNESS");if(!t.createRandom)throw new S("Problem must have a createRandom function","E_PROBLEM_CREATE");if(!t.crossover)throw new S("Problem must have a crossover function","E_PROBLEM_CROSSOVER");if(!t.mutate)throw new S("Problem must have a mutate function","E_PROBLEM_MUTATE")}function be(t=3){return (n,e)=>{let s=e.int(n.length);for(let i=1;i<t;++i){let o=e.int(n.length);n[o].f>n[s].f&&(s=o);}return s}}var fe=class{constructor(n){n.enabled&&(n.fitnessKey?(this.keyFn=n.fitnessKey,this.byKey=new Map):this.byRef=new WeakMap);}get(n){if(this.keyFn&&this.byKey)try{let e=this.keyFn(n);return this.byKey.get(e)}catch(e){return}if(this.byRef&&typeof n=="object"&&n!==null)return this.byRef.get(n)}set(n,e){if(Number.isFinite(e)){if(this.keyFn&&this.byKey){try{let s=this.keyFn(n);this.byKey.set(s,e);}catch(s){}return}this.byRef&&typeof n=="object"&&n!==null&&this.byRef.set(n,e);}}};function Ee(t){let n=-1/0,e=0,s=0,i=0;for(let u=0;u<t.length;u++){let l=t[u].f;l>n&&(n=l),Number.isFinite(l)?(e+=l,s++):i++;}let o=s?e/s:-1/0;return {best:n,mean:o,invalidCount:i,finiteCount:s}}function pe(t,n){let{popSize:e,generations:s,cxProb:i,mutProb:o,crossoverChildren:u,immigration:l,tournament:a,stall:r,targetFitness:m,maxWallMs:p,maxEvaluations:f,elitesPerGen:g}=n;return {evaluations:t.evaluations,invalidEvaluations:t.invalidEvaluations,repaired:t.repaired,repairFailures:t.repairFailures,fitnessErrors:t.fitnessErrors,nonFiniteFitness:t.nonFiniteFitness,mutations:t.mutations,crossovers:t.crossovers,selections:t.selections,immigrants:t.immigrants,elitesPerGen:g,config:{popSize:e,generations:s,cxProb:i,mutProb:o,crossoverChildren:u,immigration:l,tournament:a,stall:r,targetFitness:m,maxWallMs:p,maxEvaluations:f}}}var ve=class{constructor(n,e={}){this.problem=n;var i,o,u,l,a;de(n),he(e);let s=me(e);if(this.cfg=Te(ue({},s),{rng:(i=e.rng)!=null?i:e.seed!==void 0?q(e.seed):q(),selector:(o=e.selector)!=null?o:be(s.tournament),hooks:(u=e.hooks)!=null?u:{},clone:(l=e.clone)!=null?l:ye,cacheFitness:(a=e.cacheFitness)!=null?a:false,fitnessKey:e.fitnessKey}),this.rng=this.cfg.rng,this.select=this.cfg.selector,this.fitnessCache=new fe({enabled:!!e.cacheFitness,fitnessKey:e.fitnessKey}),this.problemSync=this.problem,this.cfg.elite>this.cfg.popSize)throw new E("Elite count cannot exceed population size","E_CFG_ELITE_GT_POP")}static seed(n){return q(n)}assertNotPromise(n,e){if(e&&typeof e.then=="function")throw new ge(`${n} returned a Promise in sync engine. Use GPLiteAsync.run or make ${n} synchronous.`,"E_SYNC_PROMISE");return e}safeFitness(n,e){let s=n;e&&(e.evaluations+=1);{let i=this.fitnessCache.get(s);if(i!==void 0)return i}if(this.problemSync.isValid&&!this.problemSync.isValid(s))if(this.problemSync.repair){if(s=this.problemSync.repair(s,this.rng),this.assertNotPromise("repair",s),!this.problemSync.isValid(s))return e&&(e.invalidEvaluations+=1,e.repairFailures+=1),-1/0;e&&(e.repaired+=1);}else return e&&(e.invalidEvaluations+=1),-1/0;try{let i=this.problemSync.fitness(s);return this.assertNotPromise("fitness",i),!Number.isFinite(i)||i!==i?(e&&(e.invalidEvaluations+=1,e.nonFiniteFitness+=1),-1/0):(this.fitnessCache.set(s,i),i)}catch(i){return e&&(e.invalidEvaluations+=1,e.fitnessErrors+=1),-1/0}}run(n){var T,_,h,M,L,se,B,oe,Y,Z,J;let e=Date.now(),s={},i,o={evaluations:0,invalidEvaluations:0,repaired:0,repairFailures:0,fitnessErrors:0,nonFiniteFitness:0,mutations:0,crossovers:0,selections:0,immigrants:0},u=Math.max(0,this.cfg.popSize-this.cfg.elite),l=Math.min(Math.round(u*this.cfg.immigration),u),a=Date.now(),r=Array.from({length:this.cfg.popSize},()=>{let G=this.problemSync.createRandom(this.rng);return this.assertNotPromise("createRandom",G),{g:G,f:this.safeFitness(G,o)}});if(s={init:Date.now()-a},o.evaluations>=this.cfg.maxEvaluations)return r.sort((G,D)=>D.f-G.f),{bestGenome:r[0].g,bestFitness:r[0].f,generations:0,bestFitnessHistory:[r[0].f],bestGenomeHistory:[r[0].g],elapsedMs:Date.now()-e,stopReason:"evaluations",avgFitnessHistory:[-1/0],invalidCountHistory:[0],validShareHistory:[1],metrics:pe(o,{popSize:this.cfg.popSize,generations:this.cfg.generations,cxProb:this.cfg.cxProb,mutProb:this.cfg.mutProb,crossoverChildren:this.cfg.crossoverChildren,immigration:this.cfg.immigration,tournament:this.cfg.tournament,stall:this.cfg.stall,targetFitness:this.cfg.targetFitness,maxWallMs:this.cfg.maxWallMs,maxEvaluations:this.cfg.maxEvaluations,elitesPerGen:this.cfg.elite})};let m=[],p=[],f=[],g=[],b=[];for(let G=0;G<this.cfg.generations;++G){(_=(T=this.cfg.hooks).onGenerationStart)==null||_.call(T,{generation:G,popSize:this.cfg.popSize,elapsedMs:Date.now()-e}),r.sort((R,d)=>d.f-R.f);let{best:D,mean:Q,invalidCount:ee,finiteCount:te}=Ee(r);m.push(D),b.push(r[0].g),p.push(Q),f.push(ee),g.push(te/r.length);let V;if(D>=this.cfg.targetFitness)V="target";else if(Date.now()-e>=this.cfg.maxWallMs)V="time";else if(o.evaluations>=this.cfg.maxEvaluations)V="evaluations";else {let R=this.cfg.stall;R&&m.length>R&&m[m.length-1]<=m[m.length-1-R]&&(V="stall");}let y={generation:G,bestFitness:D,avgFitness:Q,popSize:r.length,invalidCount:ee,validShare:te/r.length,bestGenome:r[0].g,elapsedMs:Date.now()-e,stopReason:V,stageMaxMs:s};if(n==null||n(y),(M=(h=this.cfg.hooks).onGenerationEnd)==null||M.call(h,y),(se=(L=this.cfg.hooks).onIteration)==null||se.call(L,y),V){i=V;break}let v=r.slice(0,this.cfg.elite),x={},A=this.cfg.popSize-l;{let R=A-v.length,d=Math.min(R,Math.round((this.cfg.popSize-this.cfg.elite)*this.cfg.cxProb)),O=Math.max(0,R-d),P=0;for(;P<d;){let k=this.select(r,this.rng),re=this.select(r,this.rng);o.selections+=2;let z=this.cfg.clone(r[k].g),U=this.cfg.clone(r[re].g),c=Date.now(),F=this.problemSync.crossover(z,U,this.rng),K=Date.now()-c;K>((B=x.crossover)!=null?B:0)&&(x.crossover=K),this.assertNotPromise("crossover",F),o.crossovers+=1;let X=Math.min(F.length,d-P,A-v.length);for(let N=0;N<X;N++){let I=F[N];(I===z||I===U)&&(I=this.cfg.clone(I));let W=Date.now(),j=this.safeFitness(I,o),$=Date.now()-W;if($>((oe=x.evaluation)!=null?oe:0)&&(x.evaluation=$),v.push({g:I,f:j}),P+=1,o.evaluations>=this.cfg.maxEvaluations){i="evaluations";break}}if(i)break}if(i){r=v;break}for(let k=0;k<O&&v.length<A;k++){let re=this.select(r,this.rng);o.selections+=1;let z=this.cfg.clone(r[re].g),U=Date.now(),c=this.problemSync.mutate(z,this.rng),F=Date.now()-U;F>((Y=x.mutation)!=null?Y:0)&&(x.mutation=F),this.assertNotPromise("mutate",c),c===z&&(c=this.cfg.clone(c)),o.mutations+=1;{let K=Date.now(),X=this.safeFitness(c,o),N=Date.now()-K;N>((Z=x.evaluation)!=null?Z:0)&&(x.evaluation=N),v.push({g:c,f:X});}if(o.evaluations>=this.cfg.maxEvaluations){i="evaluations";break}}if(i){r=v;break}}if(i){r=v;break}for(let R=0;R<l;++R){let d=this.problemSync.createRandom(this.rng);this.assertNotPromise("createRandom",d);{let O=Date.now(),P=this.safeFitness(d,o),k=Date.now()-O;k>((J=x.evaluation)!=null?J:0)&&(x.evaluation=k),v.push({g:d,f:P});}if(o.immigrants+=1,o.evaluations>=this.cfg.maxEvaluations){i="evaluations";break}}if(i){r=v;break}s={init:void 0,evaluation:x.evaluation,mutation:x.mutation,crossover:x.crossover},r=v;}return r.sort((G,D)=>D.f-G.f),i||(i="generations"),{bestGenome:r[0].g,bestFitness:r[0].f,generations:m.length,bestFitnessHistory:m,bestGenomeHistory:b,elapsedMs:Date.now()-e,stopReason:i,avgFitnessHistory:p,invalidCountHistory:f,validShareHistory:g,metrics:pe(o,{popSize:this.cfg.popSize,generations:this.cfg.generations,cxProb:this.cfg.cxProb,mutProb:this.cfg.mutProb,crossoverChildren:this.cfg.crossoverChildren,immigration:this.cfg.immigration,tournament:this.cfg.tournament,stall:this.cfg.stall,targetFitness:this.cfg.targetFitness,maxWallMs:this.cfg.maxWallMs,maxEvaluations:this.cfg.maxEvaluations,elitesPerGen:this.cfg.elite})}}runUnitTests(){return !this.problem.unitTests||this.problem.unitTests.length===0?[]:this.problem.unitTests.map(n=>{try{let e=this.safeFitness(n.genome),s=n.test(e),i=s===!0,o=typeof s=="string"?s:void 0;return {name:n.name,genome:n.genome,fitness:e,passed:i,error:o}}catch(e){return {name:n.name,genome:n.genome,fitness:-1/0,passed:false,error:`Fitness evaluation failed: ${e instanceof Error?e.message:String(e)}`}}})}};var Le=class{constructor(n,e={}){this.problem=n;var i,o,u,l,a,r;de(n),he(e);let s=me(e);if(this.cfg=Te(ue({},s),{rng:(i=e.rng)!=null?i:e.seed!==void 0?q(e.seed):q(),selector:(o=e.selector)!=null?o:be(s.tournament),hooks:(u=e.hooks)!=null?u:{},clone:(l=e.clone)!=null?l:ye,cacheFitness:(a=e.cacheFitness)!=null?a:false,fitnessKey:e.fitnessKey,signal:e.signal,fitnessTimeoutMs:(r=e.fitnessTimeoutMs)!=null?r:1/0,initialPopulation:e.initialPopulation}),this.rng=this.cfg.rng,this.select=this.cfg.selector,this.fitnessCache=new fe({enabled:!!this.cfg.cacheFitness,fitnessKey:this.cfg.fitnessKey}),this.cfg.elite>this.cfg.popSize)throw new E("Elite count cannot exceed population size")}static seed(n){return q(n)}safeFitness(n,e){return ie(this,null,function*(){let s=n;e&&(e.evaluations+=1);{let i=this.fitnessCache.get(s);if(i!==void 0)return i}try{if(this.problem.isValid&&!(yield this.problem.isValid(s,{signal:this.cfg.signal})))if(this.problem.repair){if(s=yield this.problem.repair(s,this.rng,{signal:this.cfg.signal}),this.problem.isValid&&!(yield this.problem.isValid(s,{signal:this.cfg.signal})))return e&&(e.invalidEvaluations+=1,e.repairFailures+=1),-1/0;e&&(e.repaired+=1);}else return e&&(e.invalidEvaluations+=1),-1/0;let i=this.cfg.fitnessTimeoutMs,o=this.cfg.signal,u,l=new AbortController,a=()=>l.abort(o==null?void 0:o.reason);o!=null&&o.aborted?l.abort(o.reason):o&&o.addEventListener("abort",a);let r=Promise.resolve(this.problem.fitness(s,{signal:l.signal})).catch(()=>-1/0),m=new Promise(f=>{Number.isFinite(i)&&i>=0&&(u=setTimeout(()=>{try{l.abort(new Error("fitness timeout"));}catch(g){}f(-1/0);},i));}),p=Number.isFinite(i)&&i>=0?yield Promise.race([r,m]):yield r;return u&&clearTimeout(u),o&&o.removeEventListener("abort",a),!Number.isFinite(p)||p!==p?(e&&(e.invalidEvaluations+=1,e.nonFiniteFitness+=1),-1/0):(this.fitnessCache.set(s,p),p)}catch(i){return e&&(e.invalidEvaluations+=1,e.fitnessErrors+=1),-1/0}})}run(n){return ie(this,null,function*(){var T,_,h,M,L,se,B,oe,Y,Z,J,G,D,Q,ee,te,V;let e=Date.now(),s=()=>Date.now()-e>=this.cfg.maxWallMs,i,o={evaluations:0,invalidEvaluations:0,repaired:0,repairFailures:0,fitnessErrors:0,nonFiniteFitness:0,mutations:0,crossovers:0,selections:0,immigrants:0},u=Math.max(0,this.cfg.popSize-this.cfg.elite),l=Math.min(Math.round(u*this.cfg.immigration),u),a=[];{let y=this.cfg.popSize,v=this.cfg.initialPopulation,x=0,A=[],R=()=>{let d=ie(this,null,function*(){let O=v&&x<v.length?v[x++]:yield this.problem.createRandom(this.rng,{signal:this.cfg.signal}),P=yield this.safeFitness(O,o);return {g:O,f:P}});A.push(d);};for(;a.length<y;){if((T=this.cfg.signal)!=null&&T.aborted){i="aborted";break}if(s()){i="time";break}let d=y-a.length-A.length,O=this.cfg.maxEvaluations-o.evaluations-A.length;if(O<=0){i="evaluations";break}let P=Math.min(Math.max(0,this.cfg.concurrency-A.length),Math.max(0,d),Math.max(0,O));for(let U=0;U<P;U++)R();if(!A.length)break;let k=yield Promise.race(A.map((U,c)=>U.then(()=>c))),z=yield A.splice(k,1)[0];a.push(z);}}if(i||o.evaluations>=this.cfg.maxEvaluations||s()){a.sort((v,x)=>x.f-v.f);let y=(_=a[0])!=null?_:{};return {bestGenome:(h=y==null?void 0:y.g)!=null?h:void 0,bestFitness:(M=y==null?void 0:y.f)!=null?M:-1/0,generations:0,bestFitnessHistory:a.length?[y.f]:[],bestGenomeHistory:a.length?[y.g]:[],elapsedMs:Date.now()-e,stopReason:i!=null?i:o.evaluations>=this.cfg.maxEvaluations?"evaluations":"time",avgFitnessHistory:a.length?[-1/0]:[],invalidCountHistory:a.length?[0]:[],validShareHistory:a.length?[1]:[],metrics:pe(o,{popSize:this.cfg.popSize,generations:this.cfg.generations,cxProb:this.cfg.cxProb,mutProb:this.cfg.mutProb,crossoverChildren:this.cfg.crossoverChildren,immigration:this.cfg.immigration,tournament:this.cfg.tournament,stall:this.cfg.stall,targetFitness:this.cfg.targetFitness,maxWallMs:this.cfg.maxWallMs,maxEvaluations:this.cfg.maxEvaluations,elitesPerGen:this.cfg.elite})}}let r=[],m=[],p=[],f=[],g=[];for(let y=0;y<this.cfg.generations;++y){(se=(L=this.cfg.hooks).onGenerationStart)==null||se.call(L,{generation:y,popSize:this.cfg.popSize,elapsedMs:Date.now()-e}),a.sort((c,F)=>F.f-c.f);let{best:v,mean:x,invalidCount:A,finiteCount:R}=Ee(a);r.push(v),m.push(x),p.push(A),f.push(R/a.length),g.push(a[0].g);let d;if((B=this.cfg.signal)!=null&&B.aborted)d="aborted";else if(v>=this.cfg.targetFitness)d="target";else if(Date.now()-e>=this.cfg.maxWallMs)d="time";else if(o.evaluations>=this.cfg.maxEvaluations)d="evaluations";else {let c=this.cfg.stall;c&&r.length>c&&r[r.length-1]<=r[r.length-1-c]&&(d="stall");}let O={generation:y,bestFitness:v,avgFitness:x,popSize:a.length,invalidCount:A,validShare:R/a.length,bestGenome:a[0].g,elapsedMs:Date.now()-e,stopReason:d};if(n==null||n(O),(Y=(oe=this.cfg.hooks).onGenerationEnd)==null||Y.call(oe,O),(J=(Z=this.cfg.hooks).onIteration)==null||J.call(Z,O),d==="aborted"){i="aborted";break}if(d==="target"){i="target";break}if(d==="time"){i="time";break}if(d==="evaluations"){i="evaluations";break}if(d==="stall"){i="stall";break}let P=a.slice(0,this.cfg.elite),k=this.cfg.popSize-l,re=k-P.length,z=Math.min(re,Math.round((this.cfg.popSize-this.cfg.elite)*this.cfg.cxProb)),U=Math.max(0,re-z);{let c=0,F=[],K=X=>{let N=ie(this,null,function*(){let I=this.select(a,this.rng),W=this.select(a,this.rng);o.selections+=2;let j=this.cfg.clone(a[I].g),$=this.cfg.clone(a[W].g);o.crossovers+=1;let H=yield this.problem.crossover(j,$,this.rng,{signal:this.cfg.signal}),ae=[],xe=Math.min(H.length,X);for(let le=0;le<xe;le++){let ne=H[le];(ne===j||ne===$)&&(ne=this.cfg.clone(ne)),ae.push({g:ne,f:yield this.safeFitness(ne,o)});}return ae});F.push(N);};for(;c<z;){if(s()){i="time";break}if((G=this.cfg.signal)!=null&&G.aborted){i="aborted";break}if(this.cfg.maxEvaluations-o.evaluations<=0){i="evaluations";break}let N=this.cfg.concurrency-F.length;if(N>0){let H=z-c,ae=Math.ceil(H/this.cfg.crossoverChildren),xe=Math.min(N,ae);for(let le=0;le<xe;le++){let ne=z-c,De=Math.min(ne,this.cfg.crossoverChildren);K(De),c+=De;}}if(!F.length)break;let I=yield Promise.race(F.map((H,ae)=>H.then(()=>ae))),j=yield F.splice(I,1)[0],$=k-P.length;for(let H=0;H<Math.min($,j.length);H++)P.push(j[H]);}if(i){a=P;break}}{let c=[],F=()=>{let X=ie(this,null,function*(){let N=this.select(a,this.rng);o.selections+=1;let I=this.cfg.clone(a[N].g),W=yield this.problem.mutate(I,this.rng,{signal:this.cfg.signal});return W===I&&(W=this.cfg.clone(W)),o.mutations+=1,{g:W,f:yield this.safeFitness(W,o)}});c.push(X);},K=0;for(;K<U&&P.length<k;){if(s()){i="time";break}if((D=this.cfg.signal)!=null&&D.aborted){i="aborted";break}if(this.cfg.maxEvaluations-o.evaluations<=0){i="evaluations";break}let N=this.cfg.concurrency-c.length;for(let $=0;$<Math.min(N,U-K);$++)F(),K+=1;if(!c.length)break;let I=yield Promise.race(c.map(($,H)=>$.then(()=>H))),j=yield c.splice(I,1)[0];P.length<k&&P.push(j);}if(i){a=P;break}}if(i){a=P;break}for(let c=0;c<l;++c){if(s()){i="time";break}if((Q=this.cfg.signal)!=null&&Q.aborted){i="aborted";break}let F=yield this.problem.createRandom(this.rng,{signal:this.cfg.signal});if(P.push({g:F,f:yield this.safeFitness(F,o)}),o.immigrants+=1,o.evaluations>=this.cfg.maxEvaluations){i="evaluations";break}}if(i){a=P;break}a=P;}a.sort((y,v)=>v.f-y.f),i||(i="generations");let b=(ee=a[0])!=null?ee:{};return {bestGenome:(te=b==null?void 0:b.g)!=null?te:void 0,bestFitness:(V=b==null?void 0:b.f)!=null?V:-1/0,generations:r.length,bestFitnessHistory:r,bestGenomeHistory:g,elapsedMs:Date.now()-e,stopReason:i,avgFitnessHistory:m,invalidCountHistory:p,validShareHistory:f,metrics:pe(o,{popSize:this.cfg.popSize,generations:this.cfg.generations,cxProb:this.cfg.cxProb,mutProb:this.cfg.mutProb,crossoverChildren:this.cfg.crossoverChildren,immigration:this.cfg.immigration,tournament:this.cfg.tournament,stall:this.cfg.stall,targetFitness:this.cfg.targetFitness,maxWallMs:this.cfg.maxWallMs,maxEvaluations:this.cfg.maxEvaluations,elitesPerGen:this.cfg.elite})}})}runUnitTests(){return ie(this,null,function*(){return !this.problem.unitTests||this.problem.unitTests.length===0?[]:Promise.all(this.problem.unitTests.map(n=>ie(this,null,function*(){try{let e=yield this.safeFitness(n.genome),{exact:s,min:i,max:o,greaterThan:u,lessThan:l}=n.expect,a=!0,r;return s!==void 0&&e!==s&&(a=!1,r=`Expected exactly ${s}, got ${e}`),i!==void 0&&e<i&&(a=!1,r=`Expected at least ${i}, got ${e}`),o!==void 0&&e>o&&(a=!1,r=`Expected at most ${o}, got ${e}`),u!==void 0&&e<=u&&(a=!1,r=`Expected greater than ${u}, got ${e}`),l!==void 0&&e>=l&&(a=!1,r=`Expected less than ${l}, got ${e}`),{name:n.name,genome:n.genome,fitness:e,passed:a,error:r}}catch(e){return {name:n.name,genome:n.genome,fitness:-1/0,passed:false,error:`Fitness evaluation failed: ${e instanceof Error?e.message:String(e)}`}}})))})}};function qe(t={},n={}){var Y,Z,J,G,D,Q,ee,te;let e=me(t),s=(Y=n.expectedGenerations)!=null?Y:e.generations,i=Math.floor(e.popSize*e.immigration),o=Math.max(0,e.popSize-e.elite-i),u=Math.ceil(o/2),l=u*2,a=e.popSize,r=Math.max(0,e.popSize-e.elite),m=a+e.generations*r,p=a+s*r,f=Math.min(p,e.maxEvaluations),g=(J=(Z=n.units)==null?void 0:Z.perEvaluationMs)!=null?J:0,b=(D=(G=n.units)==null?void 0:G.perGenerationOverheadMs)!=null?D:0,T=(ee=(Q=n.units)==null?void 0:Q.perRunOverheadMs)!=null?ee:0,_=a*g+T,h=r*g+b,M=_+e.generations*h,L=_+s*h,se=Math.min(L,e.maxWallMs),B=(te=n.units)==null?void 0:te.perEvaluationCost,oe=B!==void 0?{perEval:B,plannedTotal:m*B,expectedTotal:p*B}:void 0;return {evaluations:{init:a,perGen:r,plannedTotal:m,expectedTotal:p,cappedByMaxEvaluations:Number.isFinite(e.maxEvaluations)?f:void 0},timeMs:g||b||T?{init:_,perGen:h,plannedTotal:M,expectedTotal:L,cappedByMaxWall:Number.isFinite(e.maxWallMs)?se:void 0}:void 0,monetary:oe,operations:{immigrantsPerGen:i,childrenFromBreedingPerGen:o,pairsPerGen:u,selectionsPerGen:l,expectedCrossoversPerGen:u*e.cxProb,expectedMutationsPerGen:o*e.mutProb},notes:["Estimates assume no early stop (target/stall/time/evaluations).","Per-generation evaluations equal popSize - elite by construction.","Crossovers are counted per parent-pair; mutations per child genome."]}}function Ye(t,n={}){var o;let e=t.evaluations,s=((o=n.perEvaluationMs)!=null?o:0)*e,i=n.perEvaluationCost!==void 0?n.perEvaluationCost*e:void 0;return {evaluations:e,timeMs:n.perEvaluationMs!==void 0?s:void 0,monetary:i!==void 0?{total:i,perEval:n.perEvaluationCost}:void 0}}function Ze(t){let n=Math.max(1,Math.floor(t.totalGenerations)),e,s,i=0,o=0,u,l={generation:-1,generationsObserved:0,totalGenerations:n,fractionByGenerations:0,time:{elapsedMs:0}};function a(m){if(e===void 0)e=m.elapsedMs,s=m.elapsedMs;else if(s!==void 0){let M=m.elapsedMs-s;M>=0&&(i+=M,o+=1,u=M),s=m.elapsedMs;}let p=m.generation+1,f=Math.max(0,Math.min(1,p/n)),g=o>0?i/o:void 0,b=e,T=b!==void 0&&g!==void 0?b+g*(n-1):void 0,_=T!==void 0?Math.max(0,T-m.elapsedMs):void 0,h=T!==void 0?Math.max(0,Math.min(1,m.elapsedMs/T)):void 0;return l={generation:m.generation,generationsObserved:p,totalGenerations:n,fractionByGenerations:f,stopReason:m.stopReason,time:{elapsedMs:m.elapsedMs,initMs:b,lastGenMs:u,perGenMsAvg:g,estimatedTotalMs:T,remainingMs:_,fractionTime:h}},l}return {hooks:{onGenerationEnd(m){var f;let p=a(m);(f=t.onUpdate)==null||f.call(t,p,m);}},get(){return l},reset(){e=void 0,s=void 0,i=0,o=0,u=void 0,l={generation:-1,generationsObserved:0,totalGenerations:n,fractionByGenerations:0,time:{elapsedMs:0}};}}}function Je(t={}){var u,l,a;let n=Math.max(1,(u=t.every)!=null?u:1),e=(l=t.log)!=null?l:(r=>console.log(r)),s=(a=t.header)!=null?a:true,i=false,o=r=>Number.isFinite(r)?r%1===0?String(r):r.toFixed(4):String(r);return function(m){m.generation%n===0&&(s&&!i&&(e("generation best avg pop elapsedMs"),i=true),e(`${m.generation} ${o(m.bestFitness)} ${o(m.avgFitness)} ${m.popSize} ${m.elapsedMs}`));}}function Qe(t){let{fitness:n,mutate:e,crossover:s,createRandom:i,init:o,isValid:u,repair:l,distance:a}=t;if(typeof n!="function")throw new S("fitness must be a function","E_INVALID_FITNESS_FN");if(typeof e!="function")throw new S("mutate must be a function","E_INVALID_MUTATE_FN");let r;if(i)r=f=>i(f);else if(o)r=f=>{let g=o(),b=1+f.int(3);for(let T=0;T<b;T++)g=e(g,f);return g};else throw new S("createProblem requires either createRandom or init to generate genomes","E_MISSING_INIT_RANDOM");let m=s!=null?s:((f,g)=>[f]);return {createRandom:(f,g)=>r(f),fitness:n,mutate:e,crossover:m,isValid:u,repair:l,distance:a}}function rn(t){let{initialPopulation:n,fitness:e,mutate:s,iterations:i,createRandom:o,crossover:u,cxProb:l,mutProb:a,immigration:r}=t;if(!Array.isArray(n)||n.length===0)throw new S("initialPopulation must be a non-empty array","E_INVALID_POP");if(typeof e!="function")throw new S("fitness must be a function","E_INVALID_FITNESS_FN");if(typeof s!="function")throw new S("mutate must be a function","E_INVALID_MUTATE_FN");if(!Number.isInteger(i)||i<0)throw new S("iterations must be a non-negative integer","E_INVALID_ITERATIONS");if((r!=null?r:0)>0&&typeof o!="function")throw new S("immigration > 0 requires a createRandom(rng) function","E_RUN_NEEDS_CREATE_RANDOM");let m=0,p={createRandom(h){if(typeof o=="function")return o(h);if(m<n.length)return n[m++];let M=n[h.int(n.length)];return s(M,h)},fitness(h){return e(h)},mutate(h,M){return s(h,M)},crossover(h,M,L){return typeof u=="function"?u(h,M,L):[h]}},g=typeof u=="function"?l!=null?l:.8:l!=null?l:0,b=r!=null?r:0,T=a!=null?a:1-g;return new ve(p,{popSize:n.length,generations:i,cxProb:g,mutProb:T,immigration:b}).run()}export{E as ConfigError,ge as EvolutionError,ve as GPLite,Le as GPLiteAsync,ce as GPLiteError,S as ProblemError,Qe as createProblem,Ze as createProgressTracker,ke as defaults,Ye as estimateFromMetrics,qe as estimateRun,Xe as formatResult,q as mulberry32,Je as progressLogger,rn as run,be as tournament,he as validateConfig,de as validateProblem};//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map