UNPKG

gp-lite

Version:

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

67 lines (48 loc) 3.48 kB
# Architecture Overview `gp-lite` is a minimal, zero-dependency GA/GP engine designed for clarity, determinism, and extensibility. ## Core Principles - Deterministic by default: seeded Mulberry32 RNG drives all randomness. - Pure and synchronous: no async in the core loop. - Safety-first: robust validation and guarded fitness evaluation. - Extensible: custom selection (`Selector<T>`), hooks, and problem-specific strategies. ## Key Modules - `src/types.ts` – Public types and config/result shapes. - `src/core/engine.ts` – GA/GP loop implementation with selection, breeding, budgets, and metrics. - `src/core/selection.ts` – Selection operators (e.g., `tournament`). - `src/lib/rng.ts` – RNG (`mulberry32`). - `src/lib/format.ts``formatResult` helper for human-readable summaries. - `src/lib/estimate.ts` – Generic time/cost estimator using evaluation counts. - `src/lib/config.ts` – Shared default normalization (single source of truth). - `src/lib/errors.ts` – Error types and validation helpers. - `src/index.ts` – Public export surface. ## Layering & Boundaries The codebase follows a simple, enforced layering to keep dependencies acyclic and intent clear: - Core: `src/core/**` implements the evolution engine and selection. It may depend on `src/lib/**` and `src/types.ts`, but must not import from `src/index.ts` or `src/cli.ts`. - Lib: `src/lib/**` provides pure utilities, config normalization, RNG, errors, and helpers. It must not depend on `src/core/**`. - Public API: `src/index.ts` re-exports curated types and modules; downstream users should not import deep internals. - CLI: `src/cli.ts` consumes library APIs but is not imported by any library code. These boundaries are enforced via ESLint `no-restricted-imports` rules targeting `src/core/**` and `src/lib/**`. ## Data Flow 1. Initialize population via `problem.createRandom` and guarded `fitness`. 2. Rank population, compute stats, and fire generation hooks. - Unified per-generation payload across sync/async engines: `{ generation, bestFitness, avgFitness, popSize, invalidCount, validShare, bestGenome, elapsedMs, stopReason? }`. 3. Early-stop checks (target, time, evaluations, stall). 4. Breed next generation via selection → crossover/mutation → evaluation. - Parents are deep-cloned before operator calls; mutation and crossover are expected to return new genomes. The engine enforces non-aliasing by cloning results that are returned by reference. 5. Inject immigrants, loop until budget or generation limit. ## Budgets & Concurrency - `maxEvaluations` – hard cap on total fitness evaluations. - `maxWallMs`/`timeLimitMs` – wall-clock time budget. - Engine stops immediately after init if `maxEvaluations` is already exhausted. Async engine concurrency semantics: - `concurrency` bounds in-flight `createRandom`/`fitness` work; tasks complete out-of-order, but hooks fire exactly once per generation on the main thread after stats are computed. - Budgets are enforced between task completions and before scheduling more work. - `initialPopulation` may seed `GPLiteAsync` without invoking `createRandom` for those individuals. ## Error Handling - Non-finite or throwing fitness → counted as invalid and mapped to `-Infinity`. - Optional `isValid` / `repair` hooks for domain-specific validation. ## Selection - Built-in `tournament(k)` with sampling-with-replacement. - Users can supply any `Selector<T>` to model different pressures.