UNPKG

genetic-search-multiprocess

Version:

Multiprocessing genetic algorithm implementation library extension

250 lines (221 loc) 8.26 kB
import { describe, expect, it } from "@jest/globals"; import { AveragePhenomeCache, ComposedGeneticSearch, ComposedGeneticSearchConfig, GeneticSearch, GeneticSearchConfig, GeneticSearchStrategyConfig, DummyPhenomeCache, SimplePhenomeCache, DescendingSortingStrategy, RandomSelectionStrategy, TournamentSelectionStrategy, } from "genetic-search"; import { calcPathDistance, getPermutations, TravelingCrossoverStrategy, TravelingFitnessStrategy, TravelingGenome, TravelingMultiprocessingPhenomeStrategy, TravelingMutationStrategy, TravelingPopulateStrategy, // @ts-ignore } from "./fixtures"; // @ts-ignore import { dataProviderForTravelingSalesman } from "./data"; describe.each([ ...dataProviderForTravelingSalesman(), ] as Array<[number[][]]>)( 'Traveling Salesman Test', (distanceMatrix: number[][]) => { it('', () => { const config: GeneticSearchConfig = { populationSize: 30, survivalRate: 0.5, crossoverRate: 0.5, }; const strategies: GeneticSearchStrategyConfig<TravelingGenome> = { populate: new TravelingPopulateStrategy(distanceMatrix.length), phenome: new TravelingMultiprocessingPhenomeStrategy({ poolSize: 4, distanceMatrix, task: (data) => { const [path, distanceMatrix] = data; let totalDistance = 0; for (let i = 0; i < path.length; i++) { const from = path[i]; const to = path[(i + 1) % path.length]; totalDistance += distanceMatrix[from][to]; } return Promise.resolve([1 / totalDistance]); }, }), fitness: new TravelingFitnessStrategy(), sorting: new DescendingSortingStrategy(), selection: new TournamentSelectionStrategy<TravelingGenome>(2, 5), mutation: new TravelingMutationStrategy(), crossover: new TravelingCrossoverStrategy(), cache: new DummyPhenomeCache(), } const search = new GeneticSearch<TravelingGenome>(config, strategies); return search.fit({ generationsCount: 30 }).then(() => { const bestGenome = search.bestGenome; const expectedMinDistance = getPermutations(distanceMatrix.length) .map((path) => calcPathDistance(path, distanceMatrix)) .sort((a, b) => a - b)[0]; expect(calcPathDistance(bestGenome.path, distanceMatrix)).toBeCloseTo(expectedMinDistance); }); }, 10000); }, ); describe.each([ ...dataProviderForTravelingSalesman(), ] as Array<[number[][]]>)( 'Traveling Salesman Cached Test', (distanceMatrix: number[][]) => { it('', () => { const config: GeneticSearchConfig = { populationSize: 30, survivalRate: 0.5, crossoverRate: 0.5, }; const strategies: GeneticSearchStrategyConfig<TravelingGenome> = { populate: new TravelingPopulateStrategy(distanceMatrix.length), phenome: new TravelingMultiprocessingPhenomeStrategy({ poolSize: 4, distanceMatrix, task: (data) => { const [path, distanceMatrix] = data; let totalDistance = 0; for (let i = 0; i < path.length; i++) { const from = path[i]; const to = path[(i + 1) % path.length]; totalDistance += distanceMatrix[from][to]; } return Promise.resolve([1 / totalDistance]); }, }), fitness: new TravelingFitnessStrategy(), sorting: new DescendingSortingStrategy(), mutation: new TravelingMutationStrategy(), selection: new RandomSelectionStrategy<TravelingGenome>(2), crossover: new TravelingCrossoverStrategy(), cache: new SimplePhenomeCache(), } const search = new GeneticSearch<TravelingGenome>(config, strategies); return search.fit({ generationsCount: 30 }).then(() => { const bestGenome = search.bestGenome; const expectedMinDistance = getPermutations(distanceMatrix.length) .map((path) => calcPathDistance(path, distanceMatrix)) .sort((a, b) => a - b)[0]; expect(calcPathDistance(bestGenome.path, distanceMatrix)).toBeCloseTo(expectedMinDistance); }); }, 10000); }, ); describe.each([ ...dataProviderForTravelingSalesman(), ] as Array<[number[][]]>)( 'Traveling Salesman Composed Test', (distanceMatrix: number[][]) => { it('', () => { const config: ComposedGeneticSearchConfig = { eliminators: { populationSize: 10, survivalRate: 0.5, crossoverRate: 0.5, }, final: { populationSize: 2, survivalRate: 0.5, crossoverRate: 0.5, } }; const strategies: GeneticSearchStrategyConfig<TravelingGenome> = { populate: new TravelingPopulateStrategy(distanceMatrix.length), phenome: new TravelingMultiprocessingPhenomeStrategy({ poolSize: 4, distanceMatrix, task: (data) => { const [path, distanceMatrix] = data; let totalDistance = 0; for (let i = 0; i < path.length; i++) { const from = path[i]; const to = path[(i + 1) % path.length]; totalDistance += distanceMatrix[from][to]; } return Promise.resolve([1 / totalDistance]); }, }), fitness: new TravelingFitnessStrategy(), sorting: new DescendingSortingStrategy(), selection: new TournamentSelectionStrategy<TravelingGenome>(2, 5), mutation: new TravelingMutationStrategy(), crossover: new TravelingCrossoverStrategy(), cache: new DummyPhenomeCache(), } const search = new ComposedGeneticSearch<TravelingGenome>(config, strategies); return search.fit({ generationsCount: 30 }).then(() => { const bestGenome = search.bestGenome; const expectedMinDistance = getPermutations(distanceMatrix.length) .map((path) => calcPathDistance(path, distanceMatrix)) .sort((a, b) => a - b)[0]; expect(calcPathDistance(bestGenome.path, distanceMatrix)).toBeCloseTo(expectedMinDistance); }); }, 100000); } ); describe.each([ ...dataProviderForTravelingSalesman(), ] as Array<[number[][]]>)( 'Traveling Salesman Cached Composed Test', (distanceMatrix: number[][]) => { it('', () => { const config: ComposedGeneticSearchConfig = { eliminators: { populationSize: 10, survivalRate: 0.5, crossoverRate: 0.5, }, final: { populationSize: 2, survivalRate: 0.5, crossoverRate: 0.5, } }; const strategies: GeneticSearchStrategyConfig<TravelingGenome> = { populate: new TravelingPopulateStrategy(distanceMatrix.length), phenome: new TravelingMultiprocessingPhenomeStrategy({ poolSize: 4, distanceMatrix, task: (data) => { const [path, distanceMatrix] = data; let totalDistance = 0; for (let i = 0; i < path.length; i++) { const from = path[i]; const to = path[(i + 1) % path.length]; totalDistance += distanceMatrix[from][to]; } return Promise.resolve([1 / totalDistance]); }, }), fitness: new TravelingFitnessStrategy(), sorting: new DescendingSortingStrategy(), mutation: new TravelingMutationStrategy(), selection: new RandomSelectionStrategy<TravelingGenome>(2), crossover: new TravelingCrossoverStrategy(), cache: new AveragePhenomeCache(), } const search = new ComposedGeneticSearch<TravelingGenome>(config, strategies); return search.fit({ generationsCount: 30 }).then(() => { const bestGenome = search.bestGenome; const expectedMinDistance = getPermutations(distanceMatrix.length) .map((path) => calcPathDistance(path, distanceMatrix)) .sort((a, b) => a - b)[0]; expect(calcPathDistance(bestGenome.path, distanceMatrix)).toBeCloseTo(expectedMinDistance); }); }, 100000); } );