genetic-search
Version:
Multiprocessing genetic algorithm implementation library
311 lines (275 loc) • 10.5 kB
text/typescript
import { describe, expect, it } from "@jest/globals";
import {
AveragePhenomeCache,
ComposedGeneticSearch,
ComposedGeneticSearchConfig,
GeneticSearch,
GeneticSearchConfig,
GeneticSearchStrategyConfig,
DummyPhenomeCache,
SimplePhenomeCache,
DescendingSortingStrategy,
RandomSelectionStrategy,
ProportionalSelectionStrategy,
TruncationSelectionStrategy,
} from "../../src";
import {
TravelingCrossoverStrategy,
TravelingFitnessStrategy,
TravelingGenome,
TravelingMutationStrategy,
TravelingPopulateStrategy,
TravelingSinglePhenomeStrategy,
travelingPhenomeTask,
calcPathDistance,
getPermutations,
// @ts-ignore
} from "./fixtures";
// @ts-ignore
import { dataProviderForTravelingSalesman } from "./data";
import { TournamentSelectionStrategy } from "../../src";
describe.each([
...dataProviderForTravelingSalesman(),
] as Array<[number[][]]>)(
'Traveling Salesman With Random Selection Test',
(distanceMatrix) => {
it('', async () => {
const config: GeneticSearchConfig = {
populationSize: 30,
survivalRate: 0.5,
crossoverRate: 0.5,
};
const strategies: GeneticSearchStrategyConfig<TravelingGenome> = {
populate: new TravelingPopulateStrategy(distanceMatrix.length),
phenome: new TravelingSinglePhenomeStrategy({
task: travelingPhenomeTask,
distanceMatrix,
}),
fitness: new TravelingFitnessStrategy(),
sorting: new DescendingSortingStrategy(),
selection: new RandomSelectionStrategy(2),
mutation: new TravelingMutationStrategy(),
crossover: new TravelingCrossoverStrategy(),
cache: new DummyPhenomeCache(),
}
const search = new GeneticSearch<TravelingGenome>(config, strategies);
await search.fit({ generationsCount: 30 });
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);
});
},
);
describe.each([
...dataProviderForTravelingSalesman(),
] as Array<[number[][]]>)(
'Traveling Salesman With Truncation Selection Test',
(distanceMatrix) => {
it('', async () => {
const config: GeneticSearchConfig = {
populationSize: 30,
survivalRate: 0.5,
crossoverRate: 0.5,
};
const strategies: GeneticSearchStrategyConfig<TravelingGenome> = {
populate: new TravelingPopulateStrategy(distanceMatrix.length),
phenome: new TravelingSinglePhenomeStrategy({
task: travelingPhenomeTask,
distanceMatrix,
}),
fitness: new TravelingFitnessStrategy(),
sorting: new DescendingSortingStrategy(),
selection: new TruncationSelectionStrategy(2, config.survivalRate),
mutation: new TravelingMutationStrategy(),
crossover: new TravelingCrossoverStrategy(),
cache: new DummyPhenomeCache(),
}
const search = new GeneticSearch<TravelingGenome>(config, strategies);
await search.fit({ generationsCount: 30 });
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);
});
},
);
describe.each([
...dataProviderForTravelingSalesman(),
] as Array<[number[][]]>)(
'Traveling Salesman With Proportional Selection Test',
(distanceMatrix) => {
it('', async () => {
const config: GeneticSearchConfig = {
populationSize: 30,
survivalRate: 0.5,
crossoverRate: 0.5,
};
const strategies: GeneticSearchStrategyConfig<TravelingGenome> = {
populate: new TravelingPopulateStrategy(distanceMatrix.length),
phenome: new TravelingSinglePhenomeStrategy({
task: travelingPhenomeTask,
distanceMatrix,
}),
fitness: new TravelingFitnessStrategy(),
sorting: new DescendingSortingStrategy(),
selection: new ProportionalSelectionStrategy(2),
mutation: new TravelingMutationStrategy(),
crossover: new TravelingCrossoverStrategy(),
cache: new DummyPhenomeCache(),
}
const search = new GeneticSearch<TravelingGenome>(config, strategies);
await search.fit({ generationsCount: 30 });
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);
});
},
);
describe.each([
...dataProviderForTravelingSalesman(),
] as Array<[number[][]]>)(
'Traveling Salesman With Tournament Selection Test',
(distanceMatrix) => {
it('', async () => {
const config: GeneticSearchConfig = {
populationSize: 30,
survivalRate: 0.5,
crossoverRate: 0.5,
};
const strategies: GeneticSearchStrategyConfig<TravelingGenome> = {
populate: new TravelingPopulateStrategy(distanceMatrix.length),
phenome: new TravelingSinglePhenomeStrategy({
task: travelingPhenomeTask,
distanceMatrix,
}),
fitness: new TravelingFitnessStrategy(),
sorting: new DescendingSortingStrategy(),
selection: new TournamentSelectionStrategy(2, 5),
mutation: new TravelingMutationStrategy(),
crossover: new TravelingCrossoverStrategy(),
cache: new DummyPhenomeCache(),
}
const search = new GeneticSearch<TravelingGenome>(config, strategies);
await search.fit({ generationsCount: 30 });
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);
});
},
);
describe.each([
...dataProviderForTravelingSalesman(),
] as Array<[number[][]]>)(
'Traveling Salesman Simple Cached Test',
(distanceMatrix) => {
it('', async () => {
const config: GeneticSearchConfig = {
populationSize: 30,
survivalRate: 0.5,
crossoverRate: 0.5,
};
const strategies: GeneticSearchStrategyConfig<TravelingGenome> = {
populate: new TravelingPopulateStrategy(distanceMatrix.length),
phenome: new TravelingSinglePhenomeStrategy({
task: travelingPhenomeTask,
distanceMatrix,
}),
fitness: new TravelingFitnessStrategy(),
sorting: new DescendingSortingStrategy(),
selection: new RandomSelectionStrategy(2),
mutation: new TravelingMutationStrategy(),
crossover: new TravelingCrossoverStrategy(),
cache: new SimplePhenomeCache(),
}
const search = new GeneticSearch<TravelingGenome>(config, strategies);
await search.fit({ generationsCount: 30 });
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);
});
},
);
describe.each([
...dataProviderForTravelingSalesman(),
] as Array<[number[][]]>)(
'Traveling Salesman Average Cached Test',
(distanceMatrix) => {
it('', async () => {
const config: GeneticSearchConfig = {
populationSize: 30,
survivalRate: 0.5,
crossoverRate: 0.5,
};
const strategies: GeneticSearchStrategyConfig<TravelingGenome> = {
populate: new TravelingPopulateStrategy(distanceMatrix.length),
phenome: new TravelingSinglePhenomeStrategy({
task: travelingPhenomeTask,
distanceMatrix,
}),
fitness: new TravelingFitnessStrategy(),
sorting: new DescendingSortingStrategy(),
selection: new RandomSelectionStrategy(2),
mutation: new TravelingMutationStrategy(),
crossover: new TravelingCrossoverStrategy(),
cache: new AveragePhenomeCache(),
}
const search = new GeneticSearch<TravelingGenome>(config, strategies);
await search.fit({ generationsCount: 30 });
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);
});
},
);
describe.each([
...dataProviderForTravelingSalesman(),
] as Array<[number[][]]>)(
'Traveling Salesman Composed Test',
(distanceMatrix) => {
it('', async () => {
const config: ComposedGeneticSearchConfig = {
eliminators: {
populationSize: 10,
survivalRate: 0.5,
crossoverRate: 0.5,
},
final: {
populationSize: 10,
survivalRate: 0.5,
crossoverRate: 0.5,
}
};
const strategies: GeneticSearchStrategyConfig<TravelingGenome> = {
populate: new TravelingPopulateStrategy(distanceMatrix.length),
phenome: new TravelingSinglePhenomeStrategy({
task: travelingPhenomeTask,
distanceMatrix,
}),
fitness: new TravelingFitnessStrategy(),
sorting: new DescendingSortingStrategy(),
selection: new TournamentSelectionStrategy(2, 10),
mutation: new TravelingMutationStrategy(),
crossover: new TravelingCrossoverStrategy(),
cache: new DummyPhenomeCache(),
}
const search = new ComposedGeneticSearch<TravelingGenome>(config, strategies);
await search.fit({ generationsCount: 30 });
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);
});
},
);