Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Генетические алгоритмы

01.01.2007
{ **** UBPFD *********** by kladovka.net.ru ****
>> Генетические алгоритмы
 
Класс, реализующий генетический алгоритм.
 
Зависимости: Classes, SysUtils, Windows, Math
Автор:       Mystic, mystic2000@newmail.ru, ICQ:125905046, Харьков
Copyright:   Mystic
Дата:        25 апреля 2002 г.
********************************************** }
 
unit Genes;
 
interface
 
uses {Fuzzy,} Classes, SysUtils, Windows, Math;
 
type
  TGeneAlgorithm = class;
  TExtendedArray = array of Extended;
 
  TEstimateEvent = procedure (Sender: TObject; const X: TExtendedArray; var Y: Extended) of object;
  TIterationEvent = procedure (Sender: TObject; Iteration: Integer);
  TBestChangeEvent = procedure (Sender: TObject; BestEstimate: Extended);
 
  EGeneError = class(Exception) end;
 
  TCardinalArray = array of Cardinal;
  TGeneRecord = record
    Bits: TCardinalArray;
    Values: TExtendedArray;
    Estimate: Extended;
  end;
  TGeneRecords = array of TGeneRecord;
 
  TSolutionThread = class(TThread)
  private
    FOwner: TGeneAlgorithm;
  protected
    procedure Execute; override;
    property Owner: TGeneAlgorithm read FOwner;
  public
    constructor Create(AOwner: TGeneAlgorithm);
  end;
 
  TGeneState = (gsExecute, gsSuspend, gsTune);
 
  TGeneAlgorithm = class
  private
    FData: array of TGeneRecord; // Algorithm data
    FLock: TRTLCriticalSection;
    FLowValues: TExtendedArray;
    FHighValues: TExtendedArray;
    FSolutionThread: TSolutionThread;
    FMutation: Extended;
    FInversion: Extended;
    FCrossover: Extended;
    FMaxPopulation: Integer;
    FBitPerNumber: Integer;
    FMinPopulation: Integer;
    FDimCount: Integer;
    FOnBestChange: TBestChangeEvent;
    FOnEstimate: TEstimateEvent;
    FOnIteration: TIterationEvent;
    FIteration: Integer;
// FBestEstimate: Extended;
    FState: TGeneState;
 
    BitSize: Integer;
 
    function GetBestEstimate: Extended;
    function GetHighValues(I: Integer): Extended;
    function GetIteration: Integer;
    function GetLowValues(I: Integer): Extended;
    procedure SetBitPerNumber(const Value: Integer);
    procedure SetCrossover(const Value: Extended);
    procedure SetDimCount(const Value: Integer);
    procedure SetHighValues(I: Integer; const Value: Extended);
    procedure SetInversion(const Value: Extended);
    procedure SetLowValues(I: Integer; const Value: Extended);
    procedure SetMaxPopulation(const Value: Integer);
    procedure SetMinPopulation(const Value: Integer);
    procedure SetMutation(const Value: Extended);
    procedure SetOnBestChange(const Value: TBestChangeEvent);
    procedure SetOnEstimate(const Value: TEstimateEvent);
    procedure SetOnIteration(const Value: TIterationEvent);
    procedure Lock;
    procedure Unlock;
    function GetBestX(I: Integer): Extended;
    function GetState: TGeneState;
 
    procedure DoCrossover(N: Integer);
    procedure DoMutation(N: Integer);
    procedure DoInversion(N: Integer);
 
    procedure EstimatePopulation(StartIndex: Integer);
    procedure SortPopulation;
    procedure MakeChild;
 
  public
    // Creation & destroying
    constructor Create;
    destructor Destroy; override;
 
    // Running / stopping
    procedure Run;
    procedure Abort;
    procedure Suspend;
    procedure Resume;
 
    // Saving / opening
    procedure LoadFromStream(S: TStream);
    procedure SaveToStream(S: TStream);
 
    // Algorithm param
    property BitPerNumber: Integer read FBitPerNumber write SetBitPerNumber;
    property MaxPopulation: Integer read FMaxPopulation write SetMaxPopulation;
    property MinPopulation: Integer read FMinPopulation write SetMinPopulation;
    property Crossover: Extended read FCrossover write SetCrossover;
    property Mutation: Extended read FMutation write SetMutation;
    property Inversion: Extended read FInversion write SetInversion;
    property DimCount: Integer read FDimCount write SetDimCount;
    property LowValues[I: Integer]: Extended read GetLowValues write SetLowValues;
    property HighValues[I: Integer]: Extended read GetHighValues write SetHighValues;
 
    // Info property
    property Iteration: Integer read GetIteration;
    property BestX[I: Integer]: Extended read GetBestX;
    property BestEstimate: Extended read GetBestEstimate;
    property State: TGeneState read GetState;
 
    // Events
    property OnEstimate: TEstimateEvent read FOnEstimate write SetOnEstimate;
    property OnIteration: TIterationEvent read FOnIteration write SetOnIteration;
    property OnBestChange: TBestChangeEvent read FOnBestChange write SetOnBestChange;
 
  end;
 
implementation
 
resourcestring
  SCannotSetParam = 'Невозможно установить параметр %s в состоянии %s';
  SCannotGetParam = 'Невозможно прочитать параметр %s в состоянии %s';
  SInvalidParam = 'Параметр %s не может быть %s (%d).';
  SNonPositive = 'отрицательным или нулевым';
  SInvalidProbality = 'вероятность %s должна быть в диапазоне 0..1 (%f).';
  SLess2 = 'меньше двух';
  SEmpty = 'Неправильный индекс при обращении к %s (%d) при нулевом количества элементов.';
  SInvalidIndex = 'Неправильный индекс при обращении к %s (%d). Индекс должен лежать в диапазоне от %d до %d';
  SNonEstimate = 'Не задана функция оценки.';
 
const
  SState: array[TGeneState] of string = (
    'настройки параметров алгоритма',
    'работы алгоритма',
    'остановки алгоритма');
 
{ TGeneAlgorithm }
 
procedure TGeneAlgorithm.Abort;
var
  I: Integer;
begin
  if FState=gsExecute then
  begin
    FSolutionThread.Terminate;
    FSolutionThread.WaitFor;
  end;
  Lock;
  try
    for I:=0 to Length(FData)-1 do
    begin
      SetLength(FData[I].Bits, 0);
      SetLength(FData[I].Values, 0);
    end;
    SetLength(FData, 0);
    FState := gsTune;
  finally
    Unlock;
  end;
end;
 
constructor TGeneAlgorithm.Create;
begin
  InitializeCriticalSection(FLock);
  FBitPerNumber := 8;
  FMinPopulation := 5000;
  FMaxPopulation := 10000;
  FMutation := 0.1;
  FCrossover := 0.89;
  FInversion := 0.01;
  FDimCount := 0;
  FState := gsTune;
end;
 
destructor TGeneAlgorithm.Destroy;
begin
  Abort;
  DeleteCriticalSection(FLock);
  SetLength(FLowValues, 0);
  SetLength(FHighValues, 0);
  inherited;
end;
 
procedure TGeneAlgorithm.DoCrossover(N: Integer);
var
  I: Integer;
  Parent1, Parent2: Integer;
  Bit, ByteCount: Integer;
  BitPos: Byte;
  Mask: Integer;
begin
  Parent1 := Random(FMinPopulation);
  Parent2 := Random(FMinPopulation);
  Bit := Random(FDimCount*FBitPerNumber-1);
  ByteCount := Bit div 32;
  for I:=0 to ByteCount-1 do
    FData[N].Bits[I] := FData[Parent1].Bits[I];
  for I:=ByteCount+1 to BitSize-1 do
    FData[N].Bits[I] := FData[Parent2].Bits[I];
  BitPos := Bit - 32*ByteCount;
  asm
    MOV CL, BitPos
    MOV EAX, -1
    SHL EAX, CL
    MOV Mask, EAX
  end;
  FData[N].Bits[ByteCount] :=
    (FData[Parent1].Bits[ByteCount] and not Mask) or
    (FData[Parent2].Bits[ByteCount] and Mask);
end;
 
procedure TGeneAlgorithm.DoInversion(N: Integer);
 
function GetBit(Addr: Pointer; No: Integer): Byte; assembler;
asm
  MOV EAX, Addr
  MOV ECX, No
  BT [EAX], ECX
  SBB EAX, EAX
  AND EAX, 1
end;
 
procedure SetBit(Addr: Pointer; No: Integer; Value: Byte); assembler;
asm
  MOV EAX, Addr
  OR Value,Value
  JZ @@1
  BTS [EAX], No
  RET
@@1:
  BTR [EAX], No
  RET
end;
 
var
  Parent, Bit, I: Integer;
  B: Byte;
 
begin
  Parent := Random(FMinPopulation);
  Bit := Random(FDimCount*FBitPerNumber-1);
  FData[N].Bits := FData[Parent].Bits;
  repeat
    B := GetBit(FData[N].Bits, 0);
    for I:=0 to FDimCount*FBitPerNumber-2 do
      SetBit(FData[N].Bits, I, GetBit(FData[N].Bits, I+1));
    SetBit(FData[N].Bits, FDimCount*FBitPerNumber-1, B);
    if Bit=0 then Break;
    Bit := Bit - 1;
  until False;
end;
 
procedure TGeneAlgorithm.DoMutation(N: Integer);
var
  Parent: Integer;
  Bit, BitPos, ByteCount: Integer;
  Mask: Cardinal;
begin
  Parent := Random(FMinPopulation);
  Bit := Random(FDimCount*FBitPerNumber);
  ByteCount := Bit div 32;
  BitPos := Bit - 32 * ByteCount;
  Mask := 1 shl BitPos;
  FData[N].Bits := FData[Parent].Bits;
  FData[N].Bits[ByteCount] := FData[N].Bits[ByteCount] xor Mask;
end;
 
procedure TGeneAlgorithm.EstimatePopulation(StartIndex: Integer);
var
  I, J, K, Index: Integer;
  P, Q, Y: Extended;
  MaxWeight, Weight: Extended;
  Addr: Pointer;
  GrayBit, BinBit: Cardinal;
begin
  MaxWeight := Power(2, FBitPerNumber);
  for I:=StartIndex to Length(FData)-1 do
  begin
    Index := 0;
    Addr := FData[I].Bits;
    for J:=0 to FDimCount-1 do
    begin
      Weight := 0.5 * MaxWeight;
      P := 0.0;
      BinBit := 0;
 
      for K:=0 to FBitPerNumber-1 do
      begin
        asm
          MOV EAX, Addr
          MOV ECX, Index
          BT [EAX], ECX
          SBB EAX, EAX
          AND EAX, 1
          MOV GrayBit, EAX
          INC Index
        end;
        BinBit := BinBit xor GrayBit;
        if BinBit=1 then P := P + Weight;
        Weight := 0.5 * Weight;
      end;
 
      P := P / MaxWeight;
      Q := 1 - P;
      FData[I].Values[J] := P * FHighValues[J] + Q * FLowValues[J];
    end;
    Y := 0;
    FOnEstimate(Self, FData[I].Values, Y);
    FData[I].Estimate := Y;
  end;
end;
 
function TGeneAlgorithm.GetBestEstimate: Extended;
begin
  Lock;
  try
    Result := 0.0; //Kill warning
    if FState=gsTune then
      raise EGeneError.CreateFmt(SCannotGetParam, ['BestEstimate', SState[FState]]);
    Result := FData[0].Estimate;
  finally
    Unlock;
  end;
end;
 
function TGeneAlgorithm.GetBestX(I: Integer): Extended;
begin
  Lock;
  try
    Result := 0.0; // Kill warning
    if FState=gsTune then
      raise EGeneError.CreateFmt(SCannotGetParam, ['BestX', SState[FState]]);
    if (FDimCount=0) then
      raise EGeneError.CreateFmt(SEmpty, ['BestX', I]);
    if (I<0) or (I>=FDimCount) then
      raise EGeneError.CreateFmt(SInvalidIndex, ['BestX', I, 0, DimCount]);
    Result := FData[0].Values[I];
  finally
    Unlock;
  end;
end;
 
function TGeneAlgorithm.GetHighValues(I: Integer): Extended;
begin
  Lock;
  try
    Result := 0.0; // Kill warning
    if FState <> gsTune then
      raise EGeneError.CreateFmt(SCannotGetParam, ['HighValues', SState[FState]]);
    if (FDimCount=0) then
      raise EGeneError.CreateFmt(SEmpty, ['HighValues', I]);
    if (I<0) or (I>=FDimCount) then
      raise EGeneError.CreateFmt(SInvalidIndex, ['HighValues', I, 0, DimCount]);
    Result := FHighValues[I];
  finally
    Unlock;
  end;
end;
 
function TGeneAlgorithm.GetIteration: Integer;
begin
  Lock;
  try
    Result := 0; // Kill warning
    if FState=gsTune then
      raise EGeneError.CreateFmt(SCannotGetParam, ['Iteration', SState[FState]]);
    Result := FIteration;
  finally
    Unlock;
  end;
end;
 
function TGeneAlgorithm.GetLowValues(I: Integer): Extended;
begin
  Lock;
  try
    Result := 0.0; // Kill warning
    if FState <> gsTune then
      raise EGeneError.CreateFmt(SCannotGetParam, ['LowValues', SState[FState]]);
    if (FDimCount=0) then
      raise EGeneError.CreateFmt(SEmpty, ['LowValues', I]);
    if (I<0) or (I>=FDimCount) then
      raise EGeneError.CreateFmt(SInvalidIndex, ['LowValues', I, 0, DimCount]);
    Result := FLowValues[I];
  finally
    Unlock;
  end;
end;
 
function TGeneAlgorithm.GetState: TGeneState;
begin
  Lock;
  try
    Result := FState;
  finally
    Unlock;
  end;
end;
 
procedure TGeneAlgorithm.LoadFromStream(S: TStream);
begin
 
end;
 
procedure TGeneAlgorithm.Lock;
begin
  EnterCriticalSection(FLock);
end;
 
procedure TGeneAlgorithm.MakeChild;
var
  I: Integer;
  RandomValue: Extended;
begin
  for I:=FMinPopulation to FMaxPopulation-1 do
  begin
    RandomValue := Random;
    if RandomValue<FCrossover then DoCrossover(I) else
    if RandomValue<FCrossover+FMutation then DoMutation(I) else
      DoInversion(I);
  end;
end;
 
procedure TGeneAlgorithm.Resume;
begin
  if FState <> gsSuspend then
    raise EGeneError.Create('Прежде чем возобновить, надо начать!');
  FSolutionThread.Create(Self);
  FState := gsExecute;
end;
 
procedure TGeneAlgorithm.Run;
var
  I, J: Integer;
  b1, b2: Cardinal;
begin
  Lock;
  try
    if not Assigned(FOnEstimate) then
      raise EGeneError.Create(SNonEstimate);
    Abort;
 
    try
 
      // Getting memory
      SetLength(FData, FMaxPopulation);
      for I:=0 to Length(FData)-1 do
      begin
        FData[I].Values := nil;
        FData[I].bits := nil;
      end;
      BitSize := FDimCount * FBitPerNumber + 31;
      BitSize := BitSize and not 31;
      BitSize := BitSize div 32;
      for I:=0 to Length(FData)-1 do
      begin
        SetLength(FData[I].Values, DimCount);
        SetLength(FData[I].Bits, BitSize);
      end;
 
      // Initializing Population
      for I:=0 to Length(FData)-1 do
      begin
        for J:=0 to BitSize-1 do
        begin
          b1 := Random(35536);
          b2 := Random(35536);
          FData[I].Bits[J] := b1 shl 16 + b2;
        end;
      end;
 
      EstimatePopulation(0);
      SortPopulation;
      FIteration := 0;
      FState := gsExecute;
      FSolutionThread := TSolutionThread.Create(Self);
 
    except
 
      Abort;
 
    end;
 
 
  finally
    Unlock;
  end;
 
 
end;
 
procedure TGeneAlgorithm.SaveToStream(S: TStream);
begin
 
end;
 
procedure TGeneAlgorithm.SetBitPerNumber(const Value: Integer);
begin
  Lock;
  try
    if FState <> gsTune then
      raise EGeneError.CreateFmt(SCannotSetParam, ['BitPerNumber', SState[FState]]);
    if Value<=0 then
      raise EGeneError.CreateFmt(SInvalidParam, ['BitPerNumber', SNonPositive, Value]);
    FBitPerNumber := Value;
  finally
    Unlock;
  end;
end;
 
procedure TGeneAlgorithm.SetCrossover(const Value: Extended);
begin
  Lock;
  try
    if FState <> gsTune then
      raise EGeneError.CreateFmt(SCannotSetParam, ['Crossover', SState[FState]]);
    if (Value<0) or (Value>1) then
      raise EGeneError.CreateFmt(SInvalidProbality, ['кроссовера', Value]);
    FCrossover := Value;
    if FCrossover + FMutation > 1.0 then
    begin
      FMutation := 1.0 - FCrossover;
      FInversion := 0.0;
    end
    else begin
      FInversion := 1.0 - FMutation - FCrossover;
    end;
  finally
    Unlock;
  end;
end;
 
procedure TGeneAlgorithm.SetDimCount(const Value: Integer);
var
  I: Integer;
begin
  Lock;
  try
    if FState <> gsTune then
      raise EGeneError.CreateFmt(SCannotSetParam, ['DimCount', SState[FState]]);
    if FDimCount=Value then Exit;
    if Value<=0 then
      raise EGeneError.CreateFmt(SInvalidParam, ['DimCount', SNonPositive, Value]);
    SetLength(FLowValues, Value);
    SetLength(FHighValues, Value);
    for I:=FDimCount to Value-1 do
    begin
      FLowValues[I] := 0.0;
      FHighValues[I] := 1.0;
    end;
    FDimCount := Value;
  finally
    Unlock;
  end;
end;
 
procedure TGeneAlgorithm.SetHighValues(I: Integer; const Value: Extended);
begin
  Lock;
  try
    if FState <> gsTune then
      raise EGeneError.CreateFmt(SCannotSetParam, ['HighValues', SState[FState]]);
    if (FDimCount=0) then
      raise EGeneError.CreateFmt(SEmpty, ['HighValues', Value]);
    if (I<0) or (I>=FDimCount) then
      raise EGeneError.CreateFmt(SInvalidIndex, ['HighValues', Value, 0, DimCount]);
    FHighValues[I] := Value;
    if FLowValues[I] > FHighValues[I] then
      FLowValues[I] := FHighValues[I];
  finally
    Unlock;
  end;
end;
 
procedure TGeneAlgorithm.SetInversion(const Value: Extended);
begin
  Lock;
  try
    if FState <> gsTune then
      raise EGeneError.CreateFmt(SCannotSetParam, ['Crossover', SState[FState]]);
    if (Value<0) or (Value>1) then
      raise EGeneError.CreateFmt(SInvalidProbality, ['инверсии', Value]);
    FInversion := Value;
    if FCrossover + FInversion > 1.0 then
    begin
      FCrossover := 1.0 - FInversion;
      FMutation := 0.0;
    end
    else begin
      FMutation := 1.0 - FInversion - FCrossover;
    end;
  finally
    Unlock;
  end;
end;
 
procedure TGeneAlgorithm.SetLowValues(I: Integer; const Value: Extended);
begin
  Lock;
  try
    if FState <> gsTune then
      raise EGeneError.CreateFmt(SCannotSetParam, ['LowValues', SState[FState]]);
    if (FDimCount=0) then
      raise EGeneError.CreateFmt(SEmpty, ['LowValues', Value]);
    if (I<0) or (I>=FDimCount) then
      raise EGeneError.CreateFmt(SInvalidIndex, ['LowValues', Value, 0, DimCount]);
    FLowValues[I] := Value;
    if FHighValues[I] < FLowValues[I] then
      FHighValues[I] := FLowValues[I];
  finally
    Unlock;
  end;
end;
 
procedure TGeneAlgorithm.SetMaxPopulation(const Value: Integer);
begin
  Lock;
  try
    if FState <> gsTune then
      raise EGeneError.CreateFmt(SCannotSetParam, ['MaxPopulation', SState[FState]]);
    if Value<2 then
      raise EGeneError.CreateFmt(SInvalidParam, ['MaxPopulation', SLess2, Value]);
    FMaxPopulation := Value;
    if FMinPopulation >= FMaxPopulation then FMinPopulation := FMaxPopulation - 1;
  finally
    Unlock;
  end;
end;
 
procedure TGeneAlgorithm.SetMinPopulation(const Value: Integer);
begin
  Lock;
  try
    if FState <> gsTune then
      raise EGeneError.CreateFmt(SCannotSetParam, ['MinPopulation', SState[FState]]);
    if Value<=0 then
      raise EGeneError.CreateFmt(SInvalidParam, ['MinPopulation', SNonPositive, Value]);
    FMinPopulation := Value;
    if FMinPopulation >= FMaxPopulation then FMaxPopulation := FMinPopulation + 1;
  finally
    Unlock;
  end;
end;
 
procedure TGeneAlgorithm.SetMutation(const Value: Extended);
begin
  Lock;
  try
    if FState <> gsTune then
      raise EGeneError.CreateFmt(SCannotSetParam, ['Crossover', SState[FState]]);
    if (Value<0) or (Value>1) then
      raise EGeneError.CreateFmt(SInvalidProbality, ['мутации', Value]);
    FMutation := Value;
    if FCrossover + FMutation > 1.0 then
    begin
      FCrossover := 1.0 - FMutation;
      FInversion := 0.0;
    end
    else begin
      FInversion := 1.0 - FMutation - FCrossover;
    end;
  finally
    Unlock;
  end;
end;
 
procedure TGeneAlgorithm.SetOnBestChange(const Value: TBestChangeEvent);
begin
  Lock;
  try
    FOnBestChange := Value;
  finally
    Unlock;
  end;
end;
 
procedure TGeneAlgorithm.SetOnEstimate(const Value: TEstimateEvent);
begin
  Lock;
  try
    if FState <> gsTune then
      raise EGeneError.CreateFmt(SCannotSetParam, ['OnEstimate', SState[FState]]);
    FOnEstimate := Value;
  finally
    Unlock;
  end;
end;
 
procedure TGeneAlgorithm.SetOnIteration(const Value: TIterationEvent);
begin
  Lock;
  try
    FOnIteration := Value;
  finally
    Unlock;
  end;
end;
 
procedure TGeneAlgorithm.SortPopulation;
 
procedure QuickSort(L, R: Integer);
var
  I, J: Integer;
  P: Extended;
  T: TGeneRecord;
begin
  repeat
    I := L;
    J := R;
    P := FData[(L + R) shr 1].Estimate;
    repeat
      while FData[I].Estimate > P do
        Inc(I);
      while FData[J].Estimate < P do
        Dec(J);
      if I <= J then
      begin
        if (I=0) or (J=0) then Lock;
        try
          T := FData[I];
          FData[I] := FData[J];
          FData[J] := T;
        finally
          if (I=0) or (J=0) then UnLock;
        end;
        Inc(I);
        Dec(J);
      end;
    until I > J;
    if L < J then
      QuickSort(L, J);
    L := I;
  until I >= R;
end;
 
begin
  QuickSort(0, Length(FData) - 1);
end;
 
procedure TGeneAlgorithm.Suspend;
begin
  if FState<>gsExecute then
    raise EGeneError.Create('Прежде чем остановить, надо запустить!');
  FSolutionThread.Terminate;
// FSolutionThread.WaitFor;
  FState := gsSuspend;
end;
 
procedure TGeneAlgorithm.Unlock;
begin
  LeaveCriticalSection(FLock);
end;
 
{ TSolutionThread }
 
constructor TSolutionThread.Create(AOwner: TGeneAlgorithm);
begin
  FOwner := AOwner;
  FreeOnTerminate := True;
  inherited Create(False);
end;
 
procedure TSolutionThread.Execute;
begin
  repeat
    Owner.MakeChild;
    Owner.EstimatePopulation(Owner.FMinPopulation);
    Owner.SortPopulation;
    Inc(Owner.FIteration);
  until Terminated;
  Sleep(10);
end;
 
end. 

Пример использования:

unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Genes, ExtCtrls, Grids;
 
type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Edit4: TEdit;
    Button4: TButton;
    Button5: TButton;
    Timer1: TTimer;
    Button7: TButton;
    Label1: TLabel;
    Grid: TStringGrid;
    Label2: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button7Click(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    procedure Refresh;
    procedure GeneEstimate(Sender: TObject; const X: TExtendedArray; var Y: Extended);
  public
    FGene: TGeneAlgorithm;
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.DFM}
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  DecimalSeparator := '.';
  FGene := TGeneAlgorithm.Create;
  Refresh;
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
  FGene.Free;
end;
 
procedure TForm1.Refresh;
begin
  Edit1.Text := FloaTtoStr(FGene.Crossover);
  Edit2.Text := FloatToStr(FGene.Mutation);
  Edit3.Text := FloatToStr(FGene.Inversion);
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  FGene.Crossover := StrTofloat(Edit1.Text);
  Refresh;
end;
 
procedure TForm1.Button2Click(Sender: TObject);
begin
  FGene.Mutation := StrTofloat(Edit2.Text);
  Refresh;
end;
 
procedure TForm1.Button3Click(Sender: TObject);
begin
  FGene.Inversion := StrTofloat(Edit3.Text);
  Refresh;
end;
 
procedure TForm1.Button4Click(Sender: TObject);
begin
  FGene.BitPerNumber := StrToInt(Edit4.Text);
  Edit4.Text := IntToStr(FGene.BitPerNumber);
end;
 
procedure TForm1.Button5Click(Sender: TObject);
var I: Integer;
begin
  Randomize;
  FGene.DimCount := 5;
  FGene.MaxPopulation := 10000;
  FGene.MinPopulation := 5000;
  FGene.OnEstimate := GeneEstimate;
  for I:=0 to 4 do
  begin
    FGene.LowValues[I] := 0;
    FGene.HighValues[I] := 10;
  end;
  FGene.Run;
  Timer1.Enabled := True;
end;
 
procedure TForm1.GeneEstimate(Sender: TObject; const X: TExtendedArray;
  var Y: Extended);
var I: Integer;
begin
  Y := 0;
  for I:=Low(X) to High(X) do
    Y := Y + Sqr(X[I]-I);
  Y := -Y; 
end;
 
procedure TForm1.Button7Click(Sender: TObject);
var I: Integer;
begin
  Timer1.Enabled := False;
  Label1.Caption := '';
  FGene.Suspend;
  Grid.RowCount := FGene.DimCount + 1;
  for I:=0 to FGene.DimCount-1 do
    Grid.Cells[0,I+1] := FloattoStr(FGene.BestX[I]);
  FGene.Abort;
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Label1.Caption := FloatToStr(FGene.BestEstimate);
end;
 
end.