Products & Services Solutions Academia Support User Community Company

Learn more about Genetic Algorithm and Direct Search Toolbox   

Genetic Algorithm Examples

Improving Your Results

To get the best results from the genetic algorithm, you usually need to experiment with different options. Selecting the best options for a problem involves trial and error. This section describes some ways you can change options to improve results. For a complete description of the available options, see Genetic Algorithm Options.

Population Diversity

One of the most important factors that determines the performance of the genetic algorithm performs is the diversity of the population. If the average distance between individuals is large, the diversity is high; if the average distance is small, the diversity is low. Getting the right amount of diversity is a matter of trial and error. If the diversity is too high or too low, the genetic algorithm might not perform well.

This section explains how to control diversity by setting the Initial range of the population. Setting the Amount of Mutation describes how the amount of mutation affects diversity.

This section also explains how to set the population size.

Example — Setting the Initial Range

By default, ga creates a random initial population using a creation function. You can specify the range of the vectors in the initial population in the Initial range field in Population options.

If you know approximately where the solution to a problem lies, specify the initial range so that it contains your guess for the solution. However, the genetic algorithm can find the solution even if it does not lie in the initial range, if the population has enough diversity.

The following example shows how the initial range affects the performance of the genetic algorithm. The example uses Rastrigin's function, described in Example — Rastrigin's Function. The minimum value of the function is 0, which occurs at the origin.

To run the example, open the ga solver in the Optimization Tool by entering optimtool('ga') at the command line. Set the following:

Click Start in Run solver and view results. Although the results of genetic algorithm computations are random, your results are similar to the following figure, with a best fitness function value of approximately 2.

The upper plot, which displays the best fitness at each generation, shows little progress in lowering the fitness value. The lower plot shows the average distance between individuals at each generation, which is a good measure of the diversity of a population. For this setting of initial range, there is too little diversity for the algorithm to make progress.

Next, try setting Initial range to [1;100] and running the algorithm. This time the results are more variable. You might obtain a plot with a best fitness value of 35, as in the following plot. You might obtain different results.

This time, the genetic algorithm makes progress, but because the average distance between individuals is so large, the best individuals are far from the optimal solution.

Finally, set Initial range to [1;2] and run the genetic algorithm. Again, there is variability in the result, but you might obtain a result similar to the following figure. Run the optimization several times, and you eventually obtain a final point near [0;0], with a fitness function value near 0.

The diversity in this case is better suited to the problem, so ga usually returns a better result than in the previous two cases.

Example — Linearly Constrained Population and Custom Plot Function

This example shows how the default creation function for linearly constrained problems, gacreationlinearfeasible, creates a well-dispersed population that satisfies linear constraints and bounds. It also contains an example of a custom plot function.

The problem uses the objective function in lincontest6.m, a quadratic:

To see code for the function, enter type lincontest6. The constraints are three linear inequalities:

x1 + x2 ≤ 2,
x1 + 2x2 ≤ 2,
2x1 + x2 ≤ 3.

Also, the variables xi are restricted to be positive.

  1. Create a custom plot function file containing the following code:

    function state = gaplotshowpopulation2(unused,state,flag,fcn)
    % This plot function works in 2-d only
    if size(state.Population,2) > 2
        return;
    end
    if nargin < 4 % check to see if fitness function exists
        fcn = [];
    end
    % Dimensions to plot
    dimensionsToPlot = [1 2];
    
    switch flag
        % Plot initialization
        case 'init'
            pop = state.Population(:,dimensionsToPlot);
            plotHandle = plot(pop(:,1),pop(:,2),'*');
            set(plotHandle,'Tag','gaplotshowpopulation2')
            title('Population plot in two dimension',...
                        'interp','none')
            xlabelStr = sprintf('%s %s','Variable ',...
                        num2str(dimensionsToPlot(1)));
            ylabelStr = sprintf('%s %s','Variable ',...
                        num2str(dimensionsToPlot(2)));
            xlabel(xlabelStr,'interp','none');
            ylabel(ylabelStr,'interp','none');
            hold on;
           
            % plot the inequalities
            plot([0 1.5],[2 0.5],'m-.') %  x1 + x2 <= 2
            plot([0 1.5],[1 3.5/2],'m-.'); % -x1 + 2*x2 <= 2
            plot([0 1.5],[3 0],'m-.'); % 2*x1 + x2 <= 3
            % plot lower bounds
            plot([0 0], [0 2],'m-.'); % lb = [ 0 0];
            plot([0 1.5], [0 0],'m-.'); % lb = [ 0 0];
            set(gca,'xlim',[-0.7,2.2])
            set(gca,'ylim',[-0.7,2.7])
            
            % Contour plot the objective function
            if ~isempty(fcn) % if there is a fitness function
                range = [-0.5,2;-0.5,2];
                pts = 100;
                span = diff(range')/(pts - 1);
                x = range(1,1): span(1) : range(1,2);
                y = range(2,1): span(2) : range(2,2);
    
                pop = zeros(pts * pts,2);
                values = zeros(pts,1);
                k = 1;
                for i = 1:pts
                    for j = 1:pts
                        pop(k,:) = [x(i),y(j)];
                        values(k) = fcn(pop(k,:));
                        k = k + 1;
                    end
                end
                values = reshape(values,pts,pts);
                contour(x,y,values);
                colorbar
            end
            % Pause for three seconds to view the initial plot
            pause(3);
        case 'iter'
            pop = state.Population(:,dimensionsToPlot);
            plotHandle = findobj(get(gca,'Children'),'Tag',...
                         'gaplotshowpopulation2');
            set(plotHandle,'Xdata',pop(:,1),'Ydata',pop(:,2));
    end

    The custom plot function plots the lines representing the linear inequalities and bound constraints, plots level curves of the fitness function, and plots the population as it evolves. This plot function expects to have not only the usual inputs (options,state,flag), but also a function handle to the fitness function, @lincontest6 in this example. To generate level curves, the custom plot function needs the fitness function.

  2. At the command line, enter the constraints as a matrix and vectors:

    A = [1,1;-1,2;2,1]; b = [2;2;3]; lb = zeros(2,1);
  3. Set options to use gaplotshowpopulation2, and pass in @lincontest6 as the fitness function handle:

    options = gaoptimset('PlotFcn',...
              {{@gaplotshowpopulation2,@lincontest6}});
  4. Run the optimization using options:

    [x,fval] = ga(@lincontest6,2,A,b,[],[],lb,[],[],options);

A plot window appears showing the linear constraints, bounds, level curves of the objective function, and initial distribution of the population:

You can see that the initial population is biased to lie on the constraints.

The population eventually concentrates around the minimum point:

Setting the Population Size

The Population size field in Population options determines the size of the population at each generation. Increasing the population size enables the genetic algorithm to search more points and thereby obtain a better result. However, the larger the population size, the longer the genetic algorithm takes to compute each generation.

You can experiment with different settings for Population size that return good results without taking a prohibitive amount of time to run.

Fitness Scaling

Fitness scaling converts the raw fitness scores that are returned by the fitness function to values in a range that is suitable for the selection function. The selection function uses the scaled fitness values to select the parents of the next generation. The selection function assigns a higher probability of selection to individuals with higher scaled values.

The range of the scaled values affects the performance of the genetic algorithm. If the scaled values vary too widely, the individuals with the highest scaled values reproduce too rapidly, taking over the population gene pool too quickly, and preventing the genetic algorithm from searching other areas of the solution space. On the other hand, if the scaled values vary only a little, all individuals have approximately the same chance of reproduction and the search will progress very slowly.

The default fitness scaling option, Rank, scales the raw scores based on the rank of each individual instead of its score. The rank of an individual is its position in the sorted scores: the rank of the most fit individual is 1, the next most fit is 2, and so on. The rank scaling function assigns scaled values so that

Rank fitness scaling removes the effect of the spread of the raw scores.

The following plot shows the raw scores of a typical population of 20 individuals, sorted in increasing order.

The following plot shows the scaled values of the raw scores using rank scaling.

Because the algorithm minimizes the fitness function, lower raw scores have higher scaled values. Also, because rank scaling assigns values that depend only on an individual's rank, the scaled values shown would be the same for any population of size 20 and number of parents equal to 32.

Comparing Rank and Top Scaling

To see the effect of scaling, you can compare the results of the genetic algorithm using rank scaling with one of the other scaling options, such as Top. By default, top scaling assigns 40 percent of the fittest individuals to the same scaled value and assigns the rest of the individuals to value 0. Using the default selection function, only 40 percent of the fittest individuals can be selected as parents.

The following figure compares the scaled values of a population of size 20 with number of parents equal to 32 using rank and top scaling.

Because top scaling restricts parents to the fittest individuals, it creates less diverse populations than rank scaling. The following plot compares the variances of distances between individuals at each generation using rank and top scaling.

Selection

The selection function chooses parents for the next generation based on their scaled values from the fitness scaling function. An individual can be selected more than once as a parent, in which case it contributes its genes to more than one child. The default selection option, Stochastic uniform, lays out a line in which each parent corresponds to a section of the line of length proportional to its scaled value. The algorithm moves along the line in steps of equal size. At each step, the algorithm allocates a parent from the section it lands on.

A more deterministic selection option is Remainder, which performs two steps:

Reproduction Options

Reproduction options control how the genetic algorithm creates the next generation. The options are

Mutation and Crossover

The genetic algorithm uses the individuals in the current generation to create the children that make up the next generation. Besides elite children, which correspond to the individuals in the current generation with the best fitness values, the algorithm creates

Both processes are essential to the genetic algorithm. Crossover enables the algorithm to extract the best genes from different individuals and recombine them into potentially superior children. Mutation adds to the diversity of a population and thereby increases the likelihood that the algorithm will generate individuals with better fitness values.

See Creating the Next Generation for an example of how the genetic algorithm applies mutation and crossover.

You can specify how many of each type of children the algorithm creates as follows:

For example, if the Population size is 20, the Elite count is 2, and the Crossover fraction is 0.8, the numbers of each type of children in the next generation are as follows:

Setting the Amount of Mutation

The genetic algorithm applies mutations using the option that you specify on the Mutation function pane. The default mutation option, Gaussian, adds a random number, or mutation, chosen from a Gaussian distribution, to each entry of the parent vector. Typically, the amount of mutation, which is proportional to the standard deviation of the distribution, decreases at each new generation. You can control the average amount of mutation that the algorithm applies to a parent in each generation through the Scale and Shrink options:

You can see the effect of mutation by selecting the plot options Distance and Range, and then running the genetic algorithm on a problem such as the one described in Example — Rastrigin's Function. The following figure shows the plot.

The upper plot displays the average distance between points in each generation. As the amount of mutation decreases, so does the average distance between individuals, which is approximately 0 at the final generation. The lower plot displays a vertical line at each generation, showing the range from the smallest to the largest fitness value, as well as mean fitness value. As the amount of mutation decreases, so does the range. These plots show that reducing the amount of mutation decreases the diversity of subsequent generations.

For comparison, the following figure shows the plots for Distance and Range when you set Shrink to 0.5.

With Shrink set to 0.5, the average amount of mutation decreases by a factor of 1/2 by the final generation. As a result, the average distance between individuals decreases by approximately the same factor.

Setting the Crossover Fraction

The Crossover fraction field, in the Reproduction options, specifies the fraction of each population, other than elite children, that are made up of crossover children. A crossover fraction of 1 means that all children other than elite individuals are crossover children, while a crossover fraction of 0 means that all children are mutation children. The following example show that neither of these extremes is an effective strategy for optimizing a function.

The example uses the fitness function whose value at a point is the sum of the absolute values of the coordinates at the points. That is,

You can define this function as an anonymous function by setting Fitness function to

@(x) sum(abs(x))

To run the example,

Run the example with the default value of 0.8 for Crossover fraction, in the Options > Reproduction pane. This returns the best fitness value of approximately 0.2 and displays the following plots.

Crossover Without Mutation

To see how the genetic algorithm performs when there is no mutation, set Crossover fraction to 1.0 and click Start. This returns the best fitness value of approximately 1.3 and displays the following plots.

In this case, the algorithm selects genes from the individuals in the initial population and recombines them. The algorithm cannot create any new genes because there is no mutation. The algorithm generates the best individual that it can using these genes at generation number 8, where the best fitness plot becomes level. After this, it creates new copies of the best individual, which are then are selected for the next generation. By generation number 17, all individuals in the population are the same, namely, the best individual. When this occurs, the average distance between individuals is 0. Since the algorithm cannot improve the best fitness value after generation 8, it stalls after 50 more generations, because Stall generations is set to 50.

Mutation Without Crossover

To see how the genetic algorithm performs when there is no crossover, set Crossover fraction to 0 and click Start. This returns the best fitness value of approximately 3.5 and displays the following plots.

In this case, the random changes that the algorithm applies never improve the fitness value of the best individual at the first generation. While it improves the individual genes of other individuals, as you can see in the upper plot by the decrease in the mean value of the fitness function, these improved genes are never combined with the genes of the best individual because there is no crossover. As a result, the best fitness plot is level and the algorithm stalls at generation number 50.

Comparing Results for Varying Crossover Fractions

The demo deterministicstudy.m, which is included in the software, compares the results of applying the genetic algorithm to Rastrigin's function with Crossover fraction set to 0, .2, .4, .6, .8, and 1. The demo runs for 10 generations. At each generation, the demo plots the means and standard deviations of the best fitness values in all the preceding generations, for each value of the Crossover fraction.

To run the demo, enter

deterministicstudy

at the MATLAB prompt. When the demo is finished, the plots appear as in the following figure.

The lower plot shows the means and standard deviations of the best fitness values over 10 generations, for each of the values of the crossover fraction. The upper plot shows a color-coded display of the best fitness values in each generation.

For this fitness function, setting Crossover fraction to 0.8 yields the best result. However, for another fitness function, a different setting for Crossover fraction might yield the best result.

Example — Global vs. Local Minima

Sometimes the goal of an optimization is to find the global minimum or maximum of a function—a point where the function value is smaller or larger at any other point in the search space. However, optimization algorithms sometimes return a local minimum—a point where the function value is smaller than at nearby points, but possibly greater than at a distant point in the search space. The genetic algorithm can sometimes overcome this deficiency with the right settings.

As an example, consider the following function

The following figure shows a plot of the function.

The function has two local minima, one at x = 0, where the function value is –1, and the other at x = 21, where the function value is –1 – 1/e. Since the latter value is smaller, the global minimum occurs at x = 21.

Running the Genetic Algorithm on the Example

To run the genetic algorithm on this example,

  1. Copy and paste the following code into a new M-file in the MATLAB Editor.

    function y = two_min(x)
    if x<=20
        y = -exp(-(x/20).^2);
    else
        y = -exp(-1)+(x-20)*(x-22);
    end
    
  2. Save the file as two_min.m in a folder on the MATLAB path.

  3. In the Optimization Tool,

    • Set Fitness function to @two_min.

    • Set Number of variables to 1.

    • Click Start.

The genetic algorithm returns a point very close to the local minimum at x = 0.

The following custom plot shows why the algorithm finds the local minimum rather than the global minimum. The plot shows the range of individuals in each generation and the best individual.

Note that all individuals are between -2 and 2.5. While this range is larger than the default Initial range of [0;1], due to mutation, it is not large enough to explore points near the global minimum at x = 21.

One way to make the genetic algorithm explore a wider range of points—that is, to increase the diversity of the populations—is to increase the Initial range. The Initial range does not have to include the point x = 21, but it must be large enough so that the algorithm generates individuals near x = 21. Set Initial range to [0;15] as shown in the following figure.

Then click Start. The genetic algorithm returns a point very close to 21.

This time, the custom plot shows a much wider range of individuals. By the second generation there are individuals greater than 21, and by generation 12, the algorithm finds a best individual that is approximately equal to 21.

Using a Hybrid Function

A hybrid function is an optimization function that runs after the genetic algorithm terminates in order to improve the value of the fitness function. The hybrid function uses the final point from the genetic algorithm as its initial point. You can specify a hybrid function in Hybrid function options.

This example uses Optimization Toolbox function fminunc, an unconstrained minimization function. The example first runs the genetic algorithm to find a point close to the optimal point and then uses that point as the initial point for fminunc.

The example finds the minimum of Rosenbrock's function, which is defined by

The following figure shows a plot of Rosenbrock's function.

The software provides an M-file, dejong2fcn.m, that computes Rosenbrock's function. To see a demo of this example, enter

hybriddemo

at the MATLAB prompt.

To explore the example, first enter optimtool('ga') to open the Optimization Tool to the ga solver. Enter the following settings:

Before adding a hybrid function, click Start to run the genetic algorithm by itself. The genetic algorithm displays the following results in the Run solver and view results pane:

The final point is somewhat close to the true minimum at (1, 1). You can improve this result by setting Hybrid function to fminunc (in the Hybrid function options).

fminunc uses the final point of the genetic algorithm as its initial point. It returns a more accurate result, as shown in the Run solver and view results pane.

You can set options for the hybrid function separately from the calling function. Use optimset (or psoptimset for the patternsearch hybrid function) to create the options structure. For example:

hybridopts = optimset('display','iter','LargeScale','off');

In the Optimization Tool enter the name of your options structure in the Options box under Hybrid function:

At the command line, the syntax is as follows:

options = gaoptimset('HybridFcn',{@fminunc,hybridopts});

hybridopts must exist before you set options.

Setting the Maximum Number of Generations

The Generations option in Stopping criteria determines the maximum number of generations the genetic algorithm runs for—see Stopping Conditions for the Algorithm. Increasing the Generations option often improves the final result.

As an example, change the settings in the Optimization Tool as follows:

Run the genetic algorithm for approximately 300 generations and click Stop. The following figure shows the resulting best fitness plot after 300 generations.

Note that the algorithm stalls at approximately generation number 170—that is, there is no immediate improvement in the fitness function after generation 170. If you restore Stall generations to its default value of 50, the algorithm would terminate at approximately generation number 230. If the genetic algorithm stalls repeatedly with the current setting for Generations, you can try increasing both the Generations and Stall generations options to improve your results. However, changing other options might be more effective.

Vectorizing the Fitness Function

The genetic algorithm usually runs faster if you vectorize the fitness function. This means that the genetic algorithm only calls the fitness function once, but expects the fitness function to compute the fitness for all individuals in the current population at once. To vectorize the fitness function,

The following comparison, run at the command line, shows the improvement in speed with Vectorize set to On.

tic;ga(@rastriginsfcn,20);toc

elapsed_time =

    4.3660
options=gaoptimset('Vectorize','on');
tic;ga(@rastriginsfcn,20,[],[],[],[],[],[],[],options);toc

elapsed_time =

    0.5810

If there are nonlinear constraints, the objective function and the nonlinear constraints all need to be vectorized in order for the algorithm to compute in a vectorized manner.

Constrained Minimization Using ga

Suppose you want to minimize the simple fitness function of two variables x1 and x2,

subject to the following nonlinear inequality constraints and bounds

Begin by creating the fitness and constraint functions. First, create an M-file named simple_fitness.m as follows:

function y = simple_fitness(x)
y = 100*(x(1)^2 - x(2))^2 + (1 - x(1))^2;

The genetic algorithm function, ga, assumes the fitness function will take one input x, where x has as many elements as the number of variables in the problem. The fitness function computes the value of the function and returns that scalar value in its one return argument, y.

Then create an M-file, simple_constraint.m, containing the constraints

function [c, ceq] = simple_constraint(x)
c = [1.5 + x(1)*x(2) + x(1) - x(2);...
-x(1)*x(2) + 10];
ceq = [];

The ga function assumes the constraint function will take one input x, where x has as many elements as the number of variables in the problem. The constraint function computes the values of all the inequality and equality constraints and returns two vectors, c and ceq, respectively.

To minimize the fitness function, you need to pass a function handle to the fitness function as the first argument to the ga function, as well as specifying the number of variables as the second argument. Lower and upper bounds are provided as LB and UB respectively. In addition, you also need to pass a function handle to the nonlinear constraint function.

ObjectiveFunction = @simple_fitness;
nvars = 2;    % Number of variables
LB = [0 0];   % Lower bound
UB = [1 13];  % Upper bound
ConstraintFunction = @simple_constraint;
[x,fval] = ga(ObjectiveFunction,nvars,[],[],[],[],LB,UB,ConstraintFunction)

Optimization terminated: average change in the fitness value
less than options.TolFun and constraint violation is 
less than options.TolCon.

x =
    0.8122   12.3122

fval =
  1.3578e+004

The genetic algorithm solver handles linear constraints and bounds differently from nonlinear constraints. All the linear constraints and bounds are satisfied throughout the optimization. However, ga may not satisfy all the nonlinear constraints at every generation. If ga converges to a solution, the nonlinear constraints will be satisfied at that solution.

ga uses the mutation and crossover functions to produce new individuals at every generation. ga satisfies linear and bound constraints by using mutation and crossover functions that only generate feasible points. For example, in the previous call to ga, the mutation function mutationguassian does not necessarily obey the bound constraints. So when there are bound or linear constraints, the default ga mutation function is mutationadaptfeasible. If you provide a custom mutation function, this custom function must only generate points that are feasible with respect to the linear and bound constraints. All the included crossover functions generate points that satisfy the linear constraints and bounds except the crossoverheuristic function.

To see the progress of the optimization, use the gaoptimset function to create an options structure that selects two plot functions. The first plot function is gaplotbestf, which plots the best and mean score of the population at every generation. The second plot function is gaplotmaxconstr, which plots the maximum constraint violation of nonlinear constraints at every generation. You can also visualize the progress of the algorithm by displaying information to the command window using the 'Display' option.

options = gaoptimset('PlotFcns',{@gaplotbestf,@gaplotmaxconstr},'Display','iter');

Rerun the ga solver.

[x,fval] = ga(ObjectiveFunction,nvars,[],[],[],[],...
              LB,UB,ConstraintFunction,options)
                           Best       max        Stall
Generation  f-count        f(x)     constraint  Generations
    1         849       14915.8            0      0
    2        1567       13578.3            0      0
    3        2334       13578.3            0      1
    4        3043       13578.3            0      2
    5        3752       13578.3            0      3
Optimization terminated: average change in the fitness value
less than options.TolFun and constraint violation is 
less than options.TolCon.

x =
    0.8122   12.3123

fval =
  1.3578e+004

You can provide a start point for the minimization to the ga function by specifying the InitialPopulation option. The ga function will use the first individual from InitialPopulation as a start point for a constrained minimization.

X0 = [0.5 0.5]; % Start point (row vector)
options = gaoptimset(options,'InitialPopulation',X0);

Now, rerun the ga solver.

[x,fval] = ga(ObjectiveFunction,nvars,[],[],[],[],...
              LB,UB,ConstraintFunction,options)
                           Best       max        Stall
Generation  f-count        f(x)     constraint  Generations
    1         965       13579.6            0      0
    2        1728       13578.2   1.776e-015      0
    3        2422       13578.2            0      0
Optimization terminated: average change in the fitness value
less than options.TolFun and constraint violation is 
less than options.TolCon.

x =
    0.8122   12.3122

fval =
  1.3578e+004

Vectorized Constraints

If there are nonlinear constraints, the objective function and the nonlinear constraints all need to be vectorized in order for the algorithm to compute in a vectorized manner.

Vectorizing the Objective and Constraint Functions contains an example of how to vectorize both for the solver patternsearch. The syntax is nearly identical for ga. The only difference is that patternsearch can have its patterns appear as either row or column vectors; the corresponding vectors for ga are the population vectors, which are always rows.

  


Recommended Products

Includes the most popular MATLAB recorded presentations with Q&A sessions led by MATLAB experts.

 © 1984-2009- The MathWorks, Inc.    -   Site Help   -   Patents   -   Trademarks   -   Privacy Policy   -   Preventing Piracy   -   RSS