Skip to content

Denikozub/Genetic-routing

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Genetic algorithm for pathfinding

by Denis Kozub

  • Non-convex polygonal obstacles on a plane
  • Gene sequence with variable length
  • Wang et al. greedy hybrid operator mutation for long routes
  • One-point greedy hybrid operator mutation for short routes
  • One-point operator crossing

Usage

#include <iostream>
#include "../geometry/polygon.hpp"
#include "../geometry/point.hpp"
#include "../genetic_algorithm/genetic_algo.hpp"
#include "../genetic_data/map_data.hpp"
using namespace std;

int main()
{
    try {
        Polygon p1({ { 1, 0 }, { 2, 0 }, { 2, 4 }, { 1, 4 }, { 1, 0 } }),
                p2({ { 3, 2.5 }, { 3, 4 }, { 5, 4 }, { 5, 2.5 }, { 3, 2.5 } }),
                p3({ { 6, 0 }, { 7, 0 }, { 7, 4 }, { 6, 4 }, { 6, 0 } }),
                p4({ { 4, 5 }, { 4, 6 }, { 8, 6 }, { 8, 5 }, { 4, 5 } }),
                p5({ { 0, 5 }, { 0, 7 }, { 4, 7 }, { 4, 5 }, { 0, 5 } }),
                p6({ { 3, 7 }, { 3, 8 }, { 7, 8 }, { 7, 7 }, { 3, 7 } });
        vector<pair<Polygon, int>> obstacles({ {p1, 100}, {p2, 100}, {p3, 100}, {p4, 100}, {p5, 100}, {p6, 100} });
        Point start({ 4, 2 }), end({ 4, 10 });

        MapData data (obstacles, start, end);
        GeneticAlgo pathfinder;

        size_t population_size = 100;
        size_t epoch_number = 300;
        size_t valueless_epoch_number = 100;
        size_t preserve_best = 5;
        size_t preserve_worst = 5;
        size_t remove_duplicates = 5;
        double cross_percent = 1;
        double mutate_percent = 0.2;

        const auto& path = pathfinder.solve(&data, population_size, epoch_number, valueless_epoch_number,
            preserve_best, preserve_worst, remove_duplicates, cross_percent, mutate_percent, false);
        cout << "Path found: " << start << " -> ";
        for (const auto& point : path) {
            cout << data.pts[point] << " -> ";
        }
        cout << end << endl;
    }
    catch (std::exception& e) {
        std::cerr << typeid(e).name() << ": " << e.what() << std::endl;
    }

    return 0;
}

Result:
Path found: ( 4, 2 ) -> ( 3, 2.5 ) -> ( 2, 4 ) -> ( 0, 5 ) -> ( 0, 7 ) -> ( 4, 10 )

Documentation

1. Data interface class

vitrual size_t get_range() = 0;

Return maximum value to be coded (number of coded elements).

virtual double fitness(const std::vector<size_t>&) = 0;

Return fitness value of a gene.

2. Gene class - work with genes of variable length

Gene(const Data*);

Pointer to Data class should define fitness function for a particular routing task.

void init();

Randomly initialize a gene with values in range (from Data::get_range()).

void update_chance(double average);

Update chance value for proportional selection according to average fitness value of whole population.

bool selected();

Proportional selection: according to chance value check if gene is selected for crossing / mutating.
If chance value >= 1 gene is selected and chance value is decreased by 1.

bool survived() const;

Proportional selection: according to chance value check if gene escaped killing attempt.
Formula survive_chance = chance / (chance + 1) is used.
The higher chance value is, more likely gene is to survive.

std::pair<Gene, Gene> cross(const Gene& partner);

Perform one-point crossing: point is chosen randomly and parents swap their genes around this point.

Gene mutate();

Perform either Wang greedy hybrid operator (>= 6 points) or one-point greedy hybrid operator (< 6 points).
Randomly choose 2 points of a gene and perform 3 operators: inverse, insert, swap and return best mutant.
Randomly choose 1 point of a gene and perform 3 operators: change, insert, remove and return best mutant.

3. Population class

Population(size_t population_size, const Data*);

Pointer to Data class should define fitness function for a particular routing task.

void fill();

Fill population up to max number of genes (population_size).

void update_chance();

Update chance values of all genes in population for proportional selection.

void remove_duplicates();

Duplicate genes are ones with the same fitness value.

void cross(double cross_percent);

Perform crossing on a given percent of genes.
First population_size * cross_percent / 8 genes are guaranteed to be chosen as one of the parents, others are chosen randomly.

void mutate(double mutate_percent);

Perform mutation on a given percent of genes.
First population_size * cross_percent / 4 genes are guaranteed to be mutated, others are chosen randomly.

void select(size_t preserve_best, size_t preserve_worst);

Perform selection preserving best and worst genes.
Killing attempts will be made until there are population_size number of genes in population.

4. GeneticAlgo class

std::vector<size_t> solve();

Starts genetic algorithm. Returns best gene.
Parameters:

  • const Data* data: pointer to Data class should define fitness function for a particular routing task.
  • size_t population_size: max number of genes in population
  • size_t epoch_number: max number of iterations
  • size_t valueless_epoch_number: max number of iterations without improvements
  • size_t preserve_best: number of best genes preserved during selection
  • size_t preserve_worst: number of worst genes preserved during selection
  • size_t remove_duplicates: remove duplicate genes each ...th iteration
  • double cross_percent: share of genes in population crossed (from 0 to 1)
  • double mutate_percent: share of genes in population mutated (from 0 to 1)
  • bool report = false: whether to print info about each iteration

Structure of the algorithm:

1) initialize population  
2) FOR epoch_number:  
3)     selection  
4)     remove duplicates  
5)     fill population 
6)     crossing  
7)     mutation  
8)     IF valueless_epoch_number reached  
9)         BREAK

5. Fitness function

Input data: a route (represented by a gene sequence) and a set of polygons on a plane.

fitness value = 0
FOR each segment of the route:
    FOR each polygon:
        IF a segment does not intersect a polygon, its length is added to fitness value
        ELSE its length is multiplied by surface parameter and added to fitness value

About

Genetic Algorithm for Pathfinding

Topics

Resources

License

Stars

Watchers

Forks

Contributors