The GA Procedure

Using Standard Genetic Operators and Objective Functions

The GA procedure includes a set of objective functions and crossover and mutation operators, and also enables you to define your own with a subroutine. The standard operators and objectives that are provided for each encoding type are summarized in Table 4.8.

Table 4.8: Standard Genetic Operators for Each Encoding

Encoding

Crossover

Mutation

Objective

real

arithmetic

delta

 
 

heuristic

null

 
 

null

uniform

 
 

simple

   
 

twopoint

   
 

uniform

   

integer

arithmetic

delta

 
 

null

null

 
 

simple

uniform

 
 

twopoint

   
 

uniform

   

Boolean

simple

null

 
 

null

uniform

 
 

twopoint

   
 

uniform

   

sequence

cycle

invert

TSP

 

null

null

 
 

order

swap

 
 

pmatch

   


The following sections describe the standard genetic operators and objectives and how to invoke them.

Crossover Operators

Arithmetic

This operator is defined for real and integer encoding. It treats the solution segment as a vector, and computes offspring of parents $ P$ and $ Q$ as

\[  \emph{child1} = a P + (1-a) Q  \]
\[  \emph{child2} = a Q + (1-a) P  \]

where $ a$ is a random number between 0 and 1 generated by the GA procedure. For integer encoding, each component is rounded to the nearest integer. It has the advantage that it always produces feasible offspring for a convex solution space. A disadvantage of this operator is that it tends to produce offspring toward the interior of the search region, so it might not work if the optimum lies on or near the search region boundary. For single-segment encoding, you can specify the use of this operator with the call

call SetCross( 'Arithmetic');

For multisegment encoding, you can specify the segment to which the operator should be applied with the call

call SetCross( 'Arithmetic', segment);

From within a user crossover subroutine, you can use the call

call Cross(selected, segment, 'Arithmetic');

where selected is the selection parameter passed to your subroutine, and segment is the segment to which the arithmetic crossover operator is to be applied.

Cycle

This operator is defined for sequence encoding. It produces offspring such that the position of each element value in the offspring comes from one of the parents. For example, consider parents $ P$ and $ Q$,

\[  P=\left[1,2,3,4,5,6,7,8,9\right]  \]
\[  Q=\left[8,7,9,3,4,1,2,5,6\right]  \]

For the first child, pick the first element from the first parent:

\[  \emph{child1}=\left[1,.,.,.,.,.,.,.,.\right]  \]

To maintain the condition that the position of each element value must come from one of the parents, the position of the '8' value must come from $ P$, because the '8' position in $ Q$ is already taken by the '1' in $ \emph{child1}$:

\[  \emph{child1}=\left[1,.,.,.,.,.,.,8,.\right]  \]

Now the position of '5' must come from $ P$, and so on until the process returns to the first position:

\[  \emph{child1}=\left[1,.,3,4,5,6,.,8,9\right]  \]

At this point, choose the remaining element positions from $ Q$:

\[  \emph{child1}=\left[1,7,3,4,5,6,2,8,9\right]  \]

For the second child, starting with the first element from the second parent, similar logic produces

\[  \emph{child2}=\left[8,2,9,3,4,1,7,5,6\right]  \]

This operator is most useful when the absolute position of the elements is of most importance to the objective value. For single-segment encoding, you can specify this operator with the call

call SetCross( 'Cycle');

For multisegment encoding, you can specify the segment to which the operator should be applied with the call

call SetCross( 'Cycle', segment);

From within a user crossover subroutine, you can use the use the call

call Cross(selected, segment, 'Cycle');

where selected is the selection parameter passed to your subroutine, and segment is the segment to which the cycle crossover operator is to be applied.

Heuristic

This operator is defined for real encoding. It treats the solution segments as real vectors. It computes the first offspring from two parents $ P$ and $ Q$, where $ Q$ is the parent with the best objective value, as

\[  \emph{child1} = a (Q-P) + Q  \]
\[  \emph{child2} = a Q + (1-a) P  \]

where $ a$ is a random number between 0 and 1 generated by the GA procedure. The first child is a projection, and the second child is a convex combination, as with the arithmetic operator. This operator is unusual in that it uses the objective value. It has the advantage of directing the search in a promising direction, and automatically fine-tuning the search in an area where solutions are clustered. If the solution space has upper and lower bound constraints, the offspring are checked against the bounds, and any component outside its bound is set equal to that bound. The heuristic operator performs best when the objective function is smooth, and might not work well if the objective function or its first derivative is discontinuous.

For single-segment encoding, you can specify this operator with the call

call SetCross( 'Heuristic');

For multisegment encoding, you can specify the segment to which the operator should be applied with the call

call SetCross( 'Heuristic', segment);

From within a user crossover subroutine, you can use the call

call Cross(selected, segment, 'Heuristic');

where selected is the selection parameter passed to your subroutine, and segment is the segment to which the heuristic crossover operator is to be applied.

Null

This operator is used to specify that no crossover operator be applied. It is not usually necessary to specify the null operator, except when you want to cancel a previous operator selection. You can specify the null operator with the call

call SetCross( 'null');

For multisegment encoding, you can specify a segment to which the operator should be applied with the call

call SetCross( 'null', segment);

Order

This operator is defined for sequence encoding. It produces offspring by transferring a randomly chosen subsequence of random length and position from one parent, and filling the remaining positions according to the order from the other parent. For parents $ P$ and $ Q$, first choose two random cutpoints to define a subsequence:

\[  P=\left[1,2,|3,4,5,6,|7,8,9\right]  \]
\[  Q=\left[8,7,|9,3,4,1,|2,5,6\right]  \]
\[  \emph{child1}=\left[.,.,3,4,5,6,.,.,.\right]  \]
\[  \emph{child2}=\left[.,.,9,3,4,1,.,.,.\right]  \]

Starting at the second cutpoint and cycling back to the beginning, the elements of $ Q$ in order are as follows:

       2 5 6 8 7 9 3 4 1

After removing 3, 4, 5 and 6, which have already been placed in $ \emph{child1}$, you have the following entries:

       2 8 7 9 1

Placing these back in order starting at the second cutpoint yields the following sequence:

\[  \emph{child1}=\left[9,1,3,4,5,6,2,8,7\right]  \]

Applying this logic to $ \emph{child2}$ yields the following sequence:

\[  \emph{child2}=\left[5,6,9,3,4,1,7,8,2\right]  \]

This operator maintains the similarity of the relative order, or adjacency, of the sequence elements of the parents. It is especially effective for circular path-oriented optimizations, such as the traveling salesman problem. For single-segment encoding, you can specify this operator with the call

call SetCross( 'Order');

For multisegment encoding, you can specify the segment to which the operator should be applied with the call

call SetCross( 'Order', segment);

From within a user crossover subroutine, you can use the call

call Cross(selected, segment, 'Order');

where selected is the selection parameter passed to your subroutine, and segment is the segment to which the order crossover operator is to be applied.

Pmatch

The partial match operator is defined for sequence encoding. It produces offspring by transferring a subsequence from one parent, and filling the remaining positions in a way consistent with the position and ordering in the other parent. Start with two parents and randomly chosen cutpoints as indicated:

\[  P=\left[1,2,|3,4,5,6,|7,8,9\right]  \]
\[  Q=\left[8,7,|9,3,4,1,|2,5,6\right]  \]

The first step is to cross the selected subsegments as follows (note that '.' indicates positions yet to be determined):

\[  \emph{child1}=\left[.,.,9,3,4,1,.,.,.\right]  \]
\[  \emph{child2}=\left[.,.,3,4,5,6,.,.,.\right]  \]

Next, define a mapping according to the two selected subsegments:

       9-3, 3-4, 4-5, 1-6

Then, fill in the positions where there is no conflict from the corresponding parent, as follows:

\[  \emph{child1}=\left[.,2,9,3,4,1,7,8,.\right]  \]
\[  \emph{child2}=\left[8,7,3,4,5,6,2,.,.\right]  \]

Last, fill in the remaining positions from the subsequence mapping. In this case, for the first child, $1 \rightarrow 6$ and $9 \rightarrow 3$, $3 \rightarrow 4$, $4 \rightarrow 5$, and for the second child, $5 \rightarrow 4$, $4 \rightarrow 3$, $3 \rightarrow 9$, and $6 \rightarrow 1$.

\[  \emph{child1}=\left[6,2,9,3,4,1,7,8,5\right]  \]
\[  \emph{child2}=\left[8,7,3,4,5,6,2,9,1\right]  \]

This operator tends to maintain similarity of both the absolute position and relative ordering of the sequence elements, it and is useful for a wide range of sequencing problems. For single-segment encoding, you can specify this operator with the call

call SetCross( 'Pmatch');

For multisegment encoding, you can specify the segment to which the operator should be applied with the call

call SetCross( 'Pmatch', segment);

From within a user crossover subroutine, you can use the call

call Cross(selected, segment, 'Pmatch');

where selected is the selection parameter passed to your subroutine, and segment is the segment to which the Pmatch crossover operator is to be applied.

Simple

This operator is defined for integer, real, and Boolean encoding. It has one property, $\text {\emph{alpha}}$. This operator performs the following action: a position $ k$ within an encoding of length $ n$ is chosen at random, such that $1 \leq k < n$. Then for parents $ P$ and $ Q$, the offspring are as follows:

\[  \emph{child1} = \left[P_1, P_2,\ldots ,P_ k,Q_{k+1},Q_{k+2},\ldots ,Q_ n\right]  \]
\[  \emph{child2} = \left[Q_1, Q_2,\ldots ,Q_ k,P_{k+1},P_{k+2},\ldots ,P_ n\right]  \]

For integer and real encoding, you can specify an additional $\text {\emph{alpha}}$ property of value $ a$, where $0 < a \leq 1$. It modifies the offspring as follows:

\[  p_ i = a P_ i + (1-a) Q_ i, \:  i=k+1,k+2,\ldots ,n  \]
\[  q_ i = a Q_ i + (1-a) P_ i, \:  i=k+1,k+2,\ldots ,n  \]
\[  \emph{child1}= \left[P_1,P_2,\ldots ,P_ k,q_{k+1},q_{k+2},\ldots ,q_ n\right]  \]
\[  \emph{child2}= \left[Q_1,Q_2,\ldots ,Q_ k,p_{k+1},p_{k+2},\ldots ,p_ n\right]  \]

For integer encoding, the elements are then rounded to the nearest integer. For Boolean encoding, the $ a$ parameter is ignored, and is effectively 1.

For single-segment encoding, you can specify this operator with the call

call SetCross( 'Simple', 'alpha', a);

For multisegment encoding, you can specify the segment to which the operator should be applied with the call

call SetCross( 'Simple', segment, 'alpha', a);

From within a user crossover subroutine, you can use

call Cross(selected, segment, 'Simple', a);

where selected is the selection passed to your subroutine, and segment is the segment to which the simple crossover operator is to be applied.

Twopoint

This operator is defined for integer, real, and Boolean encoding of length $n \geq 3$, and has one property, $\text {\emph{alpha}}$. Two positions, $ k1$ and $ k2$, are chosen at random, such that $1 \leq k1 < k2 < n$. Element values between those positions are swapped between parents. For parents $ Q$ and $ P$, the offspring are as follows:

\[  \emph{child1}=\left[P_1,P_2,\ldots ,P_{k1},Q_{k1+1},\ldots ,Q_{k2},P_{k2+1},\ldots ,P_ n\right]  \]
\[  \emph{child2}=\left[Q_1,Q_2,\ldots ,Q_{k1},P_{k1+1},\ldots ,P_{k2},Q_{k2+1},\ldots ,Q_ n\right]  \]

For integer and real encoding, you can specify an additional $\text {\emph{alpha}}$ property of value $ a$, where $0 < a \leq 1$. It modifies the offspring as follows:

\[  p_ i = a P_ i + (1-a) Q_ i, \:  i=k1+1,k1+2,\ldots , k2  \]
\[  q_ i = a Q_ i + (1-a) P_ i, \:  i=k1+1,k1+2,\ldots , k2  \]
\[  \emph{child1}=\left[P_1,P_2,\ldots ,P_{k1},q_{k1+1},\ldots ,q_{k2},P_{k2+1},\ldots ,P_ n\right]  \]
\[  \emph{child2}=\left[Q_1,Q_2,\ldots ,Q_{k1},p_{k1+1},\ldots ,p_{k2},Q_{k2+1},\ldots ,Q_ n\right]  \]

Note that small values of $ a$ reduce the difference between the offspring and parents. For Boolean encoding, $ a$ is always 1. For single-segment encoding, you can specify the use of this operator with the call

call SetCross( 'Twopoint', 'alpha', a);

For multisegment encoding, you can specify the segment to which the operator should be applied with the call

call SetCross(selected, segment, 'Twopoint', 'alpha', a);

From within a user crossover subroutine, you can use the call

call Cross(selected, segment, 'Twopoint', a);

where selected is the selection passed to your subroutine, and seg is the segment to which the two-point crossover operator is to be applied.

Uniform

This operator is defined for integer, real, and Boolean encoding of length $n \geq 3$, and has two properties, $ \text {\emph{alpha}}$ and $ p$, where $ 0 < \text {\emph{alpha}} \leq 1 $ and $0 < p \leq 0.5$. For $ \text {\emph{alpha}} = a$ and parents $ S$ and $ T$, offspring $ s$ and $ t$ are generated such that

\[  s_ i = \left\{  \begin{array}{ll} a T_ i + (1-a)S_ i, &  \mr { with\  probability\  } \mi { p } \\ S_ i, &  \mr { otherwise } \end{array} \right.  \]
\[  t_ i = \left\{  \begin{array}{ll} a S_ i + (1-a)T_ i, &  \mr { with\  probability\  } \mi { p } \\ T_ i, &  \mr { otherwise } \end{array} \right.  \]

Note that $ \text {\emph{alpha}}$ and $ p$ determine how much interchange there is between parents. Lower values of $ \text {\emph{alpha}}$ and $ p$ imply less change between offspring and parents. For Boolean encoding, $ \text {\emph{alpha}}$ is always assigned to be 1. If you do not specify $ \text {\emph{alpha}}$, it defaults to a value of 1. If you do not specify $ p$, it defaults to a value of 0.5.

For single-segment encoding, you can specify the use of this operator with the call

call SetCross( 'Uniform', 'alpha', a, 'p', p);

For multisegment encoding, you can specify the segment to which the operator should be applied with the call

call SetCross( 'Uniform', segment, 'alpha', a, 'p', p);

From within a user crossover subroutine, you can use the call

call Cross(selected, seg, 'Uniform', a, p);

where selected is the selection parameter passed to your crossover subroutine, and seg is the segment to which the uniform crossover operator is to be applied. In both cases, if the encoding is Boolean, the $ a$ parameter is ignored, and $ a$ is effectively 1.

Mutation Operators

Delta

This operator is defined for integer and real encoding. It has two properties, $ delta$ and $ nchange$. It first chooses $ n$ elements of the solution at random, where $ n$ is the value of the $ nchange$ property, and then perturbs each chosen element by a fixed amount, set by $ d$, the value of the $ delta$ property. $ d$ must be an array with the same length as the encoding. A randomly chosen element $ k$ of the solution $ S$ is modified such that

\[  S_ k \in \{  S_ k - \mi {d}_ k , S_ k + \mi {d}_ k \}   \]

If upper and lower bounds are specified with a SetBounds call, then $ S_ k$ is adjusted as necessary to fit within the bounds. This operator gives you the ability to fine-tune the search by modifying the magnitude of the $ delta$ property. One possible strategy is to start with larger $ d$ values, and then reduce them as the search progresses and begins to converge to an optimum. This operator is also useful if the optimum is known to be on or near a boundary, in which case $ d$ can be set large enough to always perturb the solution element to a boundary. For single-segment encoding, you can specify this operator with the call

call SetMut( 'delta', 'nchange', n, 'delta', d);

For multisegment encoding, you can specify the segment to which the operator should be applied with the call

call SetMut( 'delta', segment, 'nchange', n, 'delta', d);

You can invoke this operator on a solution segment from within a user mutation subroutine with the call

call Mutate( selected, segment, 'delta', d, n);

where $ selected$ is the selection parameter passed into the subroutine.

Invert

This operator is defined for sequence encoding. It picks two locations at random and reverses the order of elements between them. This operator is most often applied to the traveling salesman problem. For single-segment encoding, you can specify this operator with the call

call SetMut( 'invert');

For multisegment encoding, you can specify the segment to which the operator should be applied with the call

call SetMut( 'invert', segment);

You can invoke this operator on a solution segment from within a user mutation subroutine with the call

call Mutate( selected, segment, 'invert');

where $ selected$ is the selection parameter passed into the subroutine.

Null

This operator is used to specify that no mutation operator be applied. It is not usually necessary to specify the null operator, except when you want to cancel a previous operator selection. You can specify the null operator with the call

call SetMut( 'null');

For multisegment encoding, you can specify a segment to which the operator should be applied with

call SetMut( 'null', segment);

Swap

This operator is defined for sequence problem encoding. It picks two random locations in the solution vector and swaps their values. You can also specify that multiple swaps be made for each mutation, by setting the $ nswap$ property. For single-segment encoding, you can specify the swap operator with the call

call SetMut( 'swap', 'nswap', n);

where $n$ is the number of swaps for each mutation. For multisegment encoding, you can specify the segment to which the operator should be applied with the call

call SetMut( 'swap', segment, 'nswap', n);

You can invoke this operator on a solution segment from within a user mutation subroutine with the call

call Mutate( selected, segment, 'swap', n);

where $ selected$ is the selection parameter passed into the subroutine.

Uniform

This operator is defined for Boolean encoding or for real or integer encoding with upper and lower bounds specified with a SetBounds call. To apply this operator, a position $ k$ is randomly chosen within the solution $ S$, and $ S_ k$ is modified to a random value between the upper and lower bounds for element $ k$. There are two properties you can specify, $ nchange$ and $ pchange$. If you set the $ nchange$ property to $ n$, the operator is applied to $ n$ locations. If you set the $ pchange$ property to a value $ p$, where $0 < p < 1$, the operator is applied at each position with probability $ p$. Only the last property setting is active, overriding any previous settings. If no property is set, a default $ nchange$ value of 1 is used. You can specify this operator with one of the following two calls:

call SetMut( 'uniform', 'nchange', n);

call SetMut( 'uniform', 'pchange', p);

For multisegment encoding, you can specify the segment to which the operator should be applied with the call

call SetMut( 'uniform', segment, 'nchange', n);

You can invoke this operator on a solution segment from within a user mutation subroutine by using one of the following statements, where $ selected$ is the selection parameter passed into the subroutine:

call Mutate( selected, segment, 'uniform', n);

call Mutate( selected, segment, 'uniform', p);

This operator can prove especially useful in early stages of the optimization, since it tends to distribute solutions widely across the search space, and to avoid premature convergence to a local optimum. However, in later stages of an optimization, when the search needs to be fine-tuned to home in on an optimum, the uniform operator can hinder the optimization.

Objective Functions

TSP

The TSP objective calculates the value of the traveling salesman problem objective. It has one property, $ distances$, which is a two-dimensional array representing distances between locations. If $ distances = d$, then d[$i$,$j$] is the distance between location $i$ and location $j$.