Genetic algorithm to solve TSP problem notes __ Genetic algorithm

Source: Internet
Author: User
Tags rand shuffle

Today saw a JS program, the source program is: Https://github.com/parano/GeneticAlgorithm-TSP, example see:
http://parano.github.io/GeneticAlgorithm-TSP/
Feel this program write very well, carefully read the source code, carefully made notes, this record. Initializing part of Calculate Distance

The distance calculation is done in the countdistances () function.
function to keep the distance in the DIS variable.
The DIS variable is a two-dimensional array in which the [i][j] element is the distance between point I and Point J.

Key statement:

for (var j = 0; J < length; J + +) {
    //>> 0 is for rounding
    dis[i][j] = distance (Points[i], points[j]) >> 0;
  }

Where the distance function is defined in utils.js, defined as:

function Distance (p1, p2) {return
    Euclidean (p1.x-p2.x, p1.y-p2.y);
}
function Euclidean (dx, dy) {return
    math.sqrt (DX*DX, Dy*dy);
}

As for the points array, it is initialized in Main.js, and you can see from the program that the elements in the array are objects with X and Y properties.
In Main.js's Init_mouse (), you can see its initialization:

Points.push (new Point (x, y));

The definition of point in utils.js
function point (x, y) {
    this.x = x;
    This.y = y;
}
Generating population

The individual DNA is generated by the Ramdomindivial function, which is actually:

function randomindivial (n) {
    var a = [];
    for (var i = 0; i < n; i++) {
        a.push (i);
    }
    return A.shuffle ();
}

This is a random arrangement, meaning a random path (the order in which nodes are reached). The shuffle function is defined in Utils.js, which is an empirical code, so it is efficient, reusable, but not very readable:

Array.prototype.shuffle = function () {for
    (Var j, x, i = this.length-1;
        i;
        j = Randomnumber (i), x = This[--i], this[i] = This[j], this[j] = x);
    return this;
};

function Randomnumber (boundary) {return
    parseint (math.random () * boundary);
}

It is now possible to randomly generate an individual DNA, generating a certain number of random individuals, to become a population:

for (var i = 0; i < population_size i++) {
    Population.push (randomindivial (points.length));

This code generates the population variable, which is a two-dimensional array with population_size elements, each of which is an array of lengths of nodes, which are random node permutations that represent paths. get the Fit value

Genetic algorithms when there is the fittest, so for each individual should have a number to measure the degree of adaptation of the individual to nature. In TSP, nature is the path length, the shorter the path, the better the advantage. This value is obtained by the Setbestvalue function:

function Setbestvalue () {for (var i = 0; i < population.length; i++) {//per individual in the population calculates fitness//and saves it in VA
    The corresponding position of the lues values[i] = Evaluate (population[i));
    //Get the best path and value currentbest = Getcurrentbest ();
      if (Bestvalue = = Undefined | |
        Bestvalue > Currentbest.bestvalue) {best =population [Currentbest.bestposition].clone ();
        Bestvalue = Currentbest.bestvalue;
    Unchanged_gens = 0;
    else {unchanged_gens = 1;
    } function Getcurrentbest () {//Best individual position and value var bestp = 0;

    Currentbestvalue = Values[0]; for (var i = 1; i < population.length i++) {if (values[i) < Currentbestvalue) {Currentbestval
            UE = Values[i];
        BESTP = i; } return {BESTPOSITION:BESTP, bestvalue:currentbestvalue}}//calculate individual fitness i.e. path (loop) length F Unction Evaluate (indivial) {var sum= dis [indivial[0]][indivial[indivial.length-1]];
    for (var i = 1; i < indivial.length i++) {sum + = dis[indivial[i]][indivial[i-1]];
return sum; }
The fittest, the natural choice

Now start the formal algorithm. The first step is to select individuals (DNA) with a higher degree of adaptability and then give them priority to produce the next generation.

Highly adaptable individuals are more likely to inherit, so there is an initialization of a turntable, and a different area (sector) on the turntable represents a different individual. The pointer on the turntable rotates randomly. The higher the degree of individual adaptation, the greater the angle of the corresponding area, and the more likely it is to be selected.

The setting of the turntable is accomplished by the Setroulette function:

function Setroulette () {
    //Calculates all individual fitness: the reciprocal of path length
    (var i = 0; i < values.length; i++) {
        Fitnessvalues[i] = 1.0/values[i];
    }
    Set the turntable
    var sum = 0;
    for (var i = 0; i < fitnessvalues.length i++) {
        sum + + fitnessvalues[i];
    }
    for (var i = 0; i < roulette.length i++) {
        roulette[i] = fitnessvalues[i]/sum;
    }
    This is a probability distribution
    //The reason for this setting can be seen from Wheelout for
    (var i = 1; i < roulette.length; i++) {
        Roulette[i] = Roulette [I-1];
    }

function Wheelout (rand) {
    var i;
    for (i = 0; i < roulette.length. i++) {
        if (rand <= roulette[i)) {return
            i;
        }

}} In the InitData function of main.js, there is a roulette definition
roulette = new Array (population_size);

After setting the turntable, start selecting the individual, completed by the selection function:

function selection () {
    var parents = new Array ();
    var initnum = 4;
    Parents.push
        (population[currentbest.bestposition]);
    Parents.push (Domutate (Best.clone ()));
    Parents.push (Pushmutate (Best.clone ()));
    Parents.push (Best.clone ());

    Setroulette ();
    for (var i = Initnum i < population_size i++) {
        Parents.push (Population[wheelout (Math.random ())]);
    Population = parents;
}

The first 4 items of parents are: the best individual, the best individual's two variations, the best individual. The following are randomly selected in the manner of the turntable.
The first variant is Domutate, by selecting a passage in the middle of the DNA and flipping it. The second variant is pushmutate, by cutting the DNA into three segments and exchanging the order. The implementation code is:

function domutate (seq) {
    //global variable, recording variation times
    mutationtimes++;

    do {
        m = randomnumber (seq.length-2);
        n = randomnumber (seq.length);
    } while (M >= N);

    for (var i = 0, j = (n-m + 1) >> 1;
        I < J; i++) {
        Seq.swap (M + i, n-i);
    }
    return seq;
}

function pushmutate (seq) {
    mutationtimes++;
    var m, N;
    do {
        m = randomnumber (seq.length >> 1);
        n = randomnumber (seq.length);
    } while (M >= N);

    var S1 = seq.slice (0, M);
    var s2 = seq.slice (m, n);
    var s3 = Seq.slice (n, seq.length);
    Return S2.concat (S1). Concat (S3). Clone ();

Utils.js
Array.prototype.swap = function (x, y) {
    if (x > This.length | |
        Y > This.length | |
        x = = y) {return
        ;
    }
    var tem = this[x];
    THIS[X] = This[y];
    This[y] = tem;
}
Genetic Variation

Here is the most critical part of the algorithm: how two individuals mate to produce the next generation. The next generation should have the characteristics of two male fathers to continue to evolve in the best direction.

Let's look at a few ways to add an array:

Array.prototype.indexOf = function (value) {for
    (var i = 0; i < this.length; i++) {
        if (this[i] = = value) {
  return i;
        }
}} Array.prototype.deleteByValue = function (value) {
    var pos = this.indexof (value);
    This.splice (POS, 1);
}
Array.prototype.next = function (index) {
    if (index = = this.length-1) {return
        this[0];
    } else {
        re Turn This[index + 1];
    }
Array.prototype.previous = function (index) {
    if (index = = 0) {return
        this[this.length-1];
    } else {
  return this[index-1];
    }

These methods are to find the subscript by value, delete by value, return next, and return to the previous one.

The code for mating is:

X, Y is the parent's subscript
function docrossover (x, y) {
    child1 = getchild (' Next ', X, y);
    Child2 = Getchild (' previous ', x, y);
    POPULATION[X] = child1;
    Population[y] = child2;
}
function Getchild (fun, x, y) {
    solution = new Array ();
    var px = Population[x].clone ();
    var py = Population[y].clone ();
    var dx, dy;
    var c = Px[randomnumber (px.length)];
    Solution.push (c);
    while (Px.length > 1) {
        dx = Px[fun] (Px.indexof (c));
        DY = Py[fun] (Py.indexof (c));
        Px.deletebyvalue (c);
        Py.deletebyvalue (c);
        c = Dis[c][dx] < Dis[c][dy]? Dx:dy;
        Solution.push (c);
    }
    return solution;
}

That is: first from the father's DNA (node) to choose a point C, put in the next generation, and then keep looking backwards, and update C for the next jump (or the last jump), until the end of the search.

The whole mating of the population is accomplished by the crossover function:

function Crossover () {
    var queue = new Array ();
    for (var i = 0; i < population_size i++) {
        if (Math.random () < crossover_probability) {
            queue.push (i);
        }
    queue.shuffle ();
    for (var i = 0; i < queue.length-1 i+= 2) {
        docrossover (queue[i], queue[i+1]);
    }
mutation

In order to prevent the algorithm from converging to the wrong result, the algorithm needs the function of mutation. The mutation is accomplished by the mutation function:

function mutation () {for
    (var i = 0; i < population_size; i++) {
        if (Math.random () < mutation_probability {
            if (math.random () > 0.5) {
                population[i] = pushmutate (Population[i]);
            } else {
                population[i] = Domutate (Population[i]);
            i--
        }}
    }

Two mutation methods are randomly selected. Overview of Algorithms

The overall steps of the algorithm are:

gainitialize (); function ganextgeneration () {currentgeneration++;
    Selection ();
    Crossover ();
    Multation ();
Setbestvalue (); }

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.