Demonstration of Crossovers

 

Let’s write a program demonstrating permutational operators. The well-known operators are the next ones:

 

- Partial Matched Crossover (PMX)

- Order Crossover (OX)

- Cycle Crossover (CX).

 

In genetic algorithms crossover is a genetic operator used to vary the programming of a chromosome (example: inversion operator) or two chromosomes from one generation to the next. It is similar to reproduction and biological crossover on which genetic algorithms are based.

 

The aim of the crossover operator is to interchange the information and genes between chromosomes. Therefore crossover operator combines two parents to reproduce new children, then one of these children may hopefully collect all good features that exist in parents.

 

This screen-shots made in run time, Partial Matched Crossover (PMX):

 

 

Order Crossover (OX):

 

 

Cycle Crossover (CX):

 

 

We have to select in crossovers to choose number of genes, and in case of PMX and OX two cut spaces. The genes of parents setup the program (random values), or we fix by +/- signs.

 

The list of program:

 

unit UCODemo;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, 

  Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;

Const M=32;
      FontS=18;
      XOrig=320;
      YOrigP1=132;
      YOrigP2=212;
      YOrigC1=332;
      YOrigC2=412;
      GenM=10;
type
  TfmCODemo = class(TForm)
    lbCODemo: TLabel;
    btExit: TButton;
    btP1RND: TButton;
    rgCO: TRadioGroup;
    btP2RND: TButton;
    btCutClear: TButton;
    lbCuts: TLabel;
    btCrossover: TButton;
    edGensNum: TEdit;
    lbGensNum: TLabel;
    lbChild1: TLabel;
    lbChild2: TLabel;
    lbCutSet: TLabel;
    Procedure GensShow;
    Procedure ChildShow;
    Procedure GensHide;
    Procedure ChildDel;
    Procedure ShowCuts;
    procedure btExitClick(Sender: TObject);
    procedure FormPaint(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure FormClick(Sender: TObject);
    procedure btP1RNDClick(Sender: TObject);
    procedure btP2RNDClick(Sender: TObject);
    procedure FormDblClick(Sender: TObject);
    procedure btCutClearClick(Sender: TObject);
    procedure edGensNumChange(Sender: TObject);
    procedure btCrossoverClick(Sender: TObject);
    procedure rgCOClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

Type
  TGen=Class
    FNum: Integer;
    FX, FY: Integer;
    FWidth, FHeight: Word;
    FBGColor, FFGColor: TColor;
    FSign: Boolean;
    Procedure Init(INum, IX, IY, IWidth, IHeight: Integer; ISign: Boolean);
    Procedure SetColors(IBGColor, IFGColor: TColor);
    Function GetBGColor: TColor;
    Procedure Show;
    Procedure Hide;
    Function GetLeft: Integer;
    Function GetTop: Integer;
    Function GetNum: Byte;
    Procedure SetNum(SNum: Byte);
  End;

var
  fmCODemo: TfmCODemo;
  GenP1, GenP2, GenC1, GenC2: Array[1..GenM] Of TGen;
  P1, P2, PX1, PX2, C1, C2: Array[1..GenM] Of Byte;
  Parents: Byte;
  GenN: Byte;
  P1OK, P2OK: Boolean;
  MouseX, MouseY: Integer;
  ActGen, SelGen, Cut, Cut1, Cut2: Byte;

implementation

{$R *.dfm}

Procedure TGen.Init(INum, IX, IY, IWidth, IHeight: Integer; ISign: Boolean);
Begin
  FNum:= INum; FX:= IX; FY:= IY; FWidth:= IWidth; FHeight:= IHeight;
  FSign:= ISign;
End;

Procedure TGen.SetColors(IBGColor, IFGColor: TColor);
Begin
  FBGColor:= IBGColor; FFGColor:= IFGColor;
End;

Function TGen.GetBGColor: TColor;
Begin
  GetBGColor:= FBGColor;
End;

Procedure TGen.Show;
Begin
  With fmCODemo.Canvas Do
  Begin
    Brush.Color:= FBGColor;
    Pen.Color:= FFGColor;
    RecTangle(FX,FY,FX+FWidth,FY+FHeight);
    With Font Do
    Begin
      Color:= FFGColor;
      Size:= FontS;
    End;
    TextOut(FX+FontS Div 2, FY+2, IntToStr(FNum));
    If FSign Then
    Begin
      Brush.Color:= clBtnFace;
      Font.Size:= 14;
      TextOut((2*FX+FWidth) Div 2-6,Fy-24,'+');
      TextOut((2*FX+FWidth) Div 2-3,Fy+FHeight,'-');
    End;
  End;
End;

Procedure TGen.Hide;
Begin
  With fmCODemo.Canvas Do
  Begin
    Brush.Color:= clBtnFace;
    Pen.Color:= clBtnFace;
    RecTangle(FX,FY-24,FX+FWidth,FY+FHeight+24);
  End;
End;

Function TGen.GetLeft: Integer;
Begin
  GetLeft:= FX;
End;

Function TGen.GetTop: Integer;
Begin
  GetTop:= FY;
End;

Function TGen.GetNum: Byte;
Begin
  GetNum:= FNum;
End;

Procedure TGen.SetNum(SNum: Byte);
Begin
  FNum:= SNum;
End;

procedure TfmCODemo.btExitClick(Sender: TObject);
begin
  Close;
end;

procedure TfmCODemo.FormPaint(Sender: TObject);
begin
  GensShow;
end;

Procedure TfmCODemo.GensShow;
Var I: Word;
Begin
  For I:= 1 To GenN Do
  Begin
    GenP1[I].Show;
    GenP2[I].Show;
    GenC1[I].Show;
    GenC2[I].Show;
  End;
End;

Procedure TfmCODemo.ChildShow;
Var I: Word;
Begin
  For I:= 1 To GenN Do
  Begin
    GenC1[I].Show;
    GenC2[I].Show;
  End;
End;

Procedure TfmCODemo.GensHide;
Var I: Word;
Begin
  For I:= 1 To GenN Do
  Begin
    GenP1[I].Hide;
    GenP2[I].Hide;
    GenC1[I].Hide;
    GenC2[I].Hide;
  End;
End;

Procedure TfmCODemo.ChildDel;
Var I: Word;
Begin
  For I:= 1 To GenN Do
  Begin
    GenC1[I].SetNum(0);
    GenC2[I].SetNum(0);
  End;
End;

Procedure TfmCODemo.ShowCuts;
Begin
  lbCuts.Caption:= IntToStr(Cut1)+' - '+IntToStr(Cut2);
End;

procedure TfmCODemo.FormCreate(Sender: TObject);
Var I: Word;
begin
  Randomize;
  GenN:= 9; Cut1:= 1; Cut2:= GenN;
  For I:= 1 To GenN Do
  Begin
    GenP1[I]:= TGen.Create;
    With GenP1[I] Do
    Begin
      Init(0,XOrig+(M-1)*(I-1),YOrigP1,M,M, True);
      SetColors(clWhite,clBlack);
    End;
    GenP2[I]:= TGen.Create;
    With GenP2[I] Do
    Begin
      Init(0,XOrig+(M-1)*(I-1),YOrigP2,M,M, True);
      SetColors(clWhite,clBlack);
    End;

    GenC1[I]:= TGen.Create;
    With GenC1[I] Do
    Begin
      Init(0,XOrig+(M-1)*(I-1),YOrigC1,M,M, False);
      SetColors(clWhite,clBlack);
    End;
    GenC2[I]:= TGen.Create;
    With GenC2[I] Do
    Begin
      Init(0,XOrig+(M-1)*(I-1),YOrigC2,M,M, False);
      SetColors(clWhite,clBlack);
    End;
  End;
  rgCO.ItemIndex:= 0; P1OK:= False; P2OK:= False;
  ShowCuts;
end;

procedure TfmCODemo.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  MouseX:= X; MouseY:= Y;
end;

procedure TfmCODemo.FormClick(Sender: TObject);
begin
  ActGen:= 0; Parents:= 0; SelGen:= 0;
  If (MouseX<GenP1[1].GetLeft) Or (MouseX>GenP1[GenN].GetLeft+M) Then Exit;
  If (MouseY>GenP1[1].GetTop-M) And (MouseY<GenP1[1].GetTop+2*M) Then
  Parents:= 1;
  If (MouseY>GenP2[1].GetTop-M) And (MouseY<GenP2[1].GetTop+2*M) Then
  Parents:= 2;
  SelGen:= (MouseX-GenP1[1].GetLeft+M Div 7) Div M +1;
  Case Parents Of
    1: With GenP1[SelGen] Do
         Begin
           If (MouseY<GetTop) And (GetNum<GenN) Then SetNum(GetNum+1);
           If (MouseY>GetTop+M) And (GetNum>1) Then SetNum(GetNum-1);
           Hide; Show;
         End;
    2: With GenP2[SelGen] Do
         Begin
           If (MouseY<GetTop) And (GetNum<GenN) Then SetNum(GetNum+1);
           If (MouseY>GetTop+M) And (GetNum>1) Then SetNum(GetNum-1);
           Hide; Show;
         End;
  End;
end;

procedure TfmCODemo.btP1RNDClick(Sender: TObject);
Var I, J, K, P: Word;
    T: Array[1..GenM] Of Integer;
begin
  For I:= 1 To GenN Do T[I]:= I;
  For K:= 1 To 10*GenN Do
  Begin
    I:= Random(GenN)+1; J:= Random(GenN)+1;
    P:= T[I]; T[I]:= T[J]; T[J]:= P;
  End;
  For I:= 1 To GenN Do With GenP1[I] Do
  Begin Hide; SetNum(T[I]); Show End;
  ChildDel; ChildShow;
  P1OK:= True; btCrossover.Enabled:= P1OK And P2OK;
end;

procedure TfmCODemo.btP2RNDClick(Sender: TObject);
Var I, J, K, P: Word;
    T: Array[1..GenM] Of Integer;
begin
  For I:= 1 To GenN Do T[I]:= I;
  For K:= 1 To 10*GenN Do
  Begin
    I:= Random(GenN)+1; J:= Random(GenN)+1;
    P:= T[I]; T[I]:= T[J]; T[J]:= P;
  End;
  For I:= 1 To GenN Do With GenP2[I] Do
  Begin Hide; SetNum(T[I]); Show End;
  ChildDel; ChildShow;
  P2OK:= True; btCrossover.Enabled:= P1OK And P2OK;
end;

procedure TfmCODemo.FormDblClick(Sender: TObject);
begin
  If rgCO.ItemIndex=2 Then Exit; 
  Cut:= (MouseX-GenP1[1].GetLeft+M Div 7) Div M +1;
  With GenP1[Cut] Do Begin SetColors(clYellow,clBlack); Show End;
  With GenP2[Cut] Do Begin SetColors(clYellow,clBlack); Show End;
  With GenC1[Cut] Do Begin SetColors(clYellow,clBlack); Show End;
  With GenC2[Cut] Do Begin SetColors(clYellow,clBlack); Show End;
  Cut1:= 1; While GenP1[Cut1].GetBGColor=clWhite Do Inc(Cut1);
  Cut2:= GenN; While GenP1[Cut2].GetBGColor=clWhite Do Dec(Cut2);
  ShowCuts;
end;

procedure TfmCODemo.btCutClearClick(Sender: TObject);
Var I: Word;
begin
  For I:= 1 To GenN Do
  Begin
    With GenP1[I] Do Begin SetColors(clWhite,clBlack); Show  End;
    With GenP2[I] Do Begin SetColors(clWhite,clBlack); Show  End;
    With GenC1[I] Do Begin SetColors(clWhite,clBlack); Show  End;
    With GenC2[I] Do Begin SetColors(clWhite,clBlack); Show  End;
  End;
  Cut1:= 1; Cut2:= GenN; ShowCuts; ChildDel; ChildShow;
end;

procedure TfmCODemo.edGensNumChange(Sender: TObject);
Var I: Word;
    Kod: Integer;
begin
  btCutClearClick(Sender); GensHide;
  Val(edGensNum.Text,GenN,Kod); If GenN>9 Then GenN:= 9;
  edGensNum.Text:= IntToStr(GenN);
  For I:= 1 To GenN Do
  Begin
    GenP1[I].SetNum(0); GenP2[I].SetNum(0);
    GenC1[I].SetNum(0); GenC2[I].SetNum(0);
  End;
  GensShow; Cut1:= 1; Cut2:= GenN; ShowCuts;
  P1OK:= False; P2OK:= False; btCrossover.Enabled:= False;
end;

procedure TfmCODemo.btCrossoverClick(Sender: TObject);
Var I, J, A, B, C, P: Word;
begin
  For I:= 1 To GenN Do
  Begin
    P1[I]:= GenP1[I].GetNum; P2[I]:= GenP2[I].GetNum; C1[I]:= 0; C2[I]:= 0;
  End;
  Case rgCO.ItemIndex Of
    0: Begin                  //PMX (Partially Matched Crossover)
         A:= 0; B:= 0;
         For I:= Cut1 To Cut2 Do
         Begin
           For J:= 1 To GenN Do If P1[J]=P2[I] Then A:= J;
           For J:= 1 To GenN Do If P2[J]=P1[I] Then B:= J;
           P:= P1[I]; P1[I]:= P2[I]; P2[I]:= P;
           P:= P1[A]; P1[A]:= P2[B]; P2[B]:= P;
         End;
         C1:= P1;
         C2:= P2;
       End;

    1: Begin                  //OX (Order Crossover)
         For I:= 1 To GenN Do Begin PX1[I]:= P1[I]; PX2[I]:= P2[I] End;

         For I:= Cut1 To Cut2 Do For J:= 1 To GenN Do
         If P2[J]=PX1[I] Then P2[J]:= 0;
         For I:= Cut1 To Cut2 Do For J:= 1 To GenN Do
         If P1[J]=PX2[I] Then P1[J]:= 0;

         A:= 0; B:= 0;
         For I:= Cut1 To GenN Do
         Begin
           If P1[I]<>0 Then
           Begin
             Inc(A); If A=Cut1 Then A:= Cut2+1; PX1[A]:= P1[I];
           End;
           If P2[I]<>0 Then
           Begin
             Inc(B); If B=Cut1 Then B:= Cut2+1; PX2[B]:= P2[I];
           End;
         End;

         For I:= 1 To Cut1-1 Do
         Begin
           If P1[I]<>0 Then
           Begin
             Inc(A); If A=Cut1 Then A:= Cut2+1; PX1[A]:= P1[I];
           End;
           If P2[I]<>0 Then
           Begin
             Inc(B); If B=Cut1 Then B:= Cut2+1; PX2[B]:= P2[I];
           End;
         End;

         For I:= 1 To Cut1 Do P1[I]:= PX1[I];
         For I:= Cut1 To Cut2 Do P1[I]:= PX2[I];
         For I:= Cut2+1 To GenN Do P1[I]:= PX1[I];

         For I:= 1 To Cut1 Do P2[I]:= PX2[I];
         For I:= Cut1 To Cut2 Do P2[I]:= PX1[I];
         For I:= Cut2+1 To GenN Do P2[I]:= PX2[I];

         C1:= P1;
         C2:= P2;

       End;
    2: Begin                  //CX (Cycle Crossover)
         For I:= 1 To GenN Do Begin PX1[I]:= 0; PX2[I]:= 0 End;

         For I:= 1 To GenN Do If P1[I]=P2[I] Then
         Begin PX1[I]:= P1[I]; PX2[I]:= P2[I] End;

         A:= 1;
         While PX1[A]<>0 Do Inc(A); B:= A;
         Repeat
           PX1[A]:= P1[A];
           PX2[A]:= P2[A];
           C:= 0; For J:= 1 To GenN Do
           If P1[J]=PX2[A] Then C:= J; A:= C;
         Until A=B;

         For I:= 1 To GenN Do
         Begin
           If PX1[I]=0 Then PX1[I]:= P2[I];
           If PX2[I]=0 Then PX2[I]:= P1[I];
         End;
         C1:= PX1;
         C2:= PX2;
       End;
  End;
  For I:= 1 To GenN Do
  Begin GenC1[I].SetNum(C1[I]); GenC2[I].SetNum(C2[I]) End;
  GensShow;
end;

procedure TfmCODemo.rgCOClick(Sender: TObject);
begin
  If rgCO.ItemIndex=2 Then
  Begin
    btCutClearClick(Sender);
    btCutClear.Enabled:= False;
  End Else btCutClear.Enabled:= True;
end;

end.