neat/export

Persistence helpers for the NEAT controller's evolutionary state.

This export chapter exists so snapshotting and rehydration stay discoverable as their own boundary instead of living in the shared root controller folder. The helpers here intentionally avoid importing the concrete Neat class directly, which keeps the serialization flow reusable across the public facade, tests, and static restore entrypoints.

Typical usage follows two tracks:

A useful way to read this chapter is as a pause-and-resume ladder:

That split matters because not every persistence use case is a full replay. Sometimes you want to archive candidate solutions for later inspection, benchmark the same population under a new fitness function, or ship genomes between environments without also freezing the controller's innovation history. Other times you need a true checkpoint that can continue evolving as if the process had never stopped.

Read the chapter in this order:

flowchart TD
  Runtime[Live NEAT controller] --> PopOnly[Population-only snapshot]
  Runtime --> MetaOnly[Meta-only checkpoint]
  Runtime --> FullState[Full state bundle]
  PopOnly --> ImportPop[Replace population in an existing controller]
  MetaOnly --> ImportMeta[Rebuild controller bookkeeping]
  FullState --> Resume[Restore bookkeeping and population together]

neat/export/neat.export.ts

exportPopulation

exportPopulation(): GenomeJSON[]

Export the current population (array of genomes) into plain JSON objects. Each genome is converted via its toJSON() method. You can persist this result (e.g. to disk, a database, or localStorage) and later rehydrate it with {@link importPopulation}.

Why export population only? Sometimes you want to snapshot just the set of candidate solutions (e.g. for ensemble evaluation) without freezing the innovation counters or hyper-parameters.

Example:

// Assuming `neat` is an instance exposing this helper
const popSnapshot = neat.exportPopulation();
fs.writeFileSync('population.json', JSON.stringify(popSnapshot, null, 2));

Returns: Array of genome JSON objects.

exportState

exportState(): NeatStateJSON

Convenience helper that returns a full evolutionary snapshot: both NEAT meta information and the serialized population array. Use this when you want a truly pause-and-resume capability including innovation bookkeeping.

In practice this is the "checkpoint" export. It is the safest default when you care about reproducible continuation rather than only preserving candidate genomes for later inspection.

Example:

const state = neat.exportState();
fs.writeFileSync('state.json', JSON.stringify(state));
// ...later / elsewhere...
const raw = JSON.parse(fs.readFileSync('state.json', 'utf8')) as NeatStateJSON;
const neat2 = Neat.importState(raw, fitnessFn); // identical evolutionary context

Returns: A {@link NeatStateJSON} bundle containing meta + population.

fromJSONImpl

fromJSONImpl(
  neatJSON: NeatMetaJSON,
  fitnessFunction: (network: GenomeWithSerialization) => number | Promise<number>,
): NeatControllerForExport

Static-style implementation that rehydrates a NEAT instance from previously exported meta JSON produced by {@link toJSONImpl}. This does not restore a population; callers typically follow up with importPopulation or use {@link importStateImpl} for a complete restore.

This helper is the mirror image of toJSONImpl(): rebuild the controller's evolution bookkeeping first, then decide separately whether the population should be restored from another source.

Example:

const meta: NeatMetaJSON = JSON.parse(fs.readFileSync('neat-meta.json', 'utf8'));
const neat = Neat.fromJSONImpl(meta, fitnessFn); // empty population, same innovations
neat.importPopulation(popSnapshot); // optional

Parameters:

Returns: Fresh NEAT instance with restored innovation history.

GenomeJSON

JSON representation of an individual genome (network). The concrete shape is produced by Network#toJSON() and re-hydrated via Network.fromJSON(). We use an open record signature here because the network architecture may evolve with plugins / future features (e.g. CPPNs, substrate metadata, ONNX export tags).

Treat this as a persistence boundary rather than a strict schema promise. The export helpers preserve whatever Network#toJSON() emits, which lets the broader architecture evolve without forcing this chapter to hard-code every possible serialized field.

GenomeWithSerialization

Genome with toJSON serialization method.

This is the smallest runtime contract needed by the export helpers when they only care about turning one genome into a JSON payload.

importPopulation

importPopulation(
  populationJSON: GenomeJSON[],
): Promise<void>

Import (replace) the current population from an array of serialized genomes. This does not touch NEAT meta state (generation, innovations, etc.) - only the population array and implied popsize are updated. That makes it the right tool when you want to swap candidate solutions into an existing controller context instead of restoring a full historical checkpoint.

Example:

const populationData: GenomeJSON[] = JSON.parse(fs.readFileSync('population.json', 'utf8'));
neat.importPopulation(populationData); // population replaced
neat.evolve(); // continue evolving with new starting genomes

Edge cases handled:

Parameters:

Returns: Promise that resolves once all genomes have been rehydrated and the controller population has been replaced.

importStateImpl

importStateImpl(
  stateBundle: NeatStateJSON,
  fitnessFunction: (network: GenomeWithSerialization) => number | Promise<number>,
): Promise<NeatControllerForExport>

Static-style helper that rehydrates a full evolutionary state previously produced by {@link exportState}. Invoke this with the NEAT class (not an instance) bound as this, e.g. Neat.importStateImpl(bundle, fitnessFn). It constructs a new NEAT instance using the meta data, then imports the population (if present).

This is the most complete restore path in the chapter. If a saved bundle is valid, the caller gets back a fresh controller that knows both where the run was in evolutionary time and which genomes were alive at that moment.

Safety and validation:

Example:

const bundle: NeatStateJSON = JSON.parse(fs.readFileSync('state.json', 'utf8'));
const neat = Neat.importStateImpl(bundle, fitnessFn);
neat.evolve();

Parameters:

Returns: Rehydrated NEAT instance ready to continue evolving.

InnovationMapEntry

Connection innovation map entry.

Innovation maps are serialized as [key, value] tuples so they can round-trip cleanly through JSON and later be restored into Map instances.

NeatConstructor

NEAT class constructor interface.

Static-style restore helpers depend on this constructor shape so they can rebuild a controller instance from persisted meta data and then optionally rehydrate the population.

NeatControllerForExport

NEAT controller interface for export operations.

The persistence helpers intentionally depend on this narrow host shape instead of the concrete Neat class. That keeps export and restore logic reusable in tests and static-style helper flows without coupling the file to the full controller implementation.

NeatMetaJSON

Serialized meta information describing a NEAT run, excluding the concrete population genomes. This allows you to persist and resume experiment context without committing to a particular population snapshot.

NeatStateJSON

Top-level bundle containing both NEAT meta information and the full array of serialized genomes (population). This is what you get from exportState() and feed into importStateImpl() to resume exactly where you left off.

If NeatMetaJSON is the controller checkpoint and GenomeJSON[] is the pool of candidate solutions, NeatStateJSON is the combined pause-and-resume artifact that preserves both layers together.

NetworkClass

Network class with static fromJSON method.

Import helpers use this contract when rebuilding genomes from serialized JSON without needing to know the concrete network implementation details.

toJSONImpl

toJSONImpl(): NeatMetaJSON

Serialize NEAT meta (excluding the mutable population) for persistence of innovation history and experiment configuration. This is sufficient to recreate a blank NEAT run at the same evolutionary generation with the same innovation counters, enabling deterministic continuation when combined later with a saved population.

Use this path when the controller context matters but the population payload should be stored, transferred, or versioned separately.

Example:

const meta = neat.toJSONImpl();
fs.writeFileSync('neat-meta.json', JSON.stringify(meta));
// ... later ...
const metaLoaded = JSON.parse(fs.readFileSync('neat-meta.json', 'utf8')) as NeatMetaJSON;
const neat2 = Neat.fromJSONImpl(metaLoaded, fitnessFn); // empty population

neat/export/neat.export.errors.ts

Raised when a persisted NEAT state bundle is missing or malformed.

NeatExportStateBundleValidationError

Raised when a persisted NEAT state bundle is missing or malformed.

NeatExportStateControllerRestoreError

Raised when a NEAT controller cannot be rehydrated from serialized state.

Generated from source JSDoc • GitHub