unit SimKohonen;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, StdCtrls,Math, Buttons;
type
  TForm_Kohonen = class (TForm)
  GroupBox2 : TGroupBox;
  GroupBox3 : TGroupBox;
  //ImagePontos : TImage;
  GroupBox4 : TGroupBox;
  GroupBox5 : TGroupBox;
  GroupBox6 : TGroupBox;
  GroupBox7 : TGroupBox;
  ImageCurva : TImage;
  GroupBox8 : TGroupBox;
  Button_para : TButton;
  Treinar : TButton;
  BtReset : TButton;
    cbCalcCurva: TCheckBox;
    cbPausa: TCheckBox;
  Label1 : TLabel;
  Label2 : TLabel;
  Label3 : TLabel;
  Edit5 : TEdit;
    edCritParada: TEdit;
  Edit6 : TEdit;
  Edit7 : TEdit;
    rbDistribuido: TRadioButton;
    rbAleatorio: TRadioButton;
    edSigma: TEdit;
    edLambda0: TEdit;
    edVizMin: TEdit;
  Label4 : TLabel;
    edTaxaAp: TEdit;
    edNumIt: TEdit;
  Label5 : TLabel;
  Label6 : TLabel;
  Label7 : TLabel;
  Label8 : TLabel;
  Label9 : TLabel;
  Label10 : TLabel;
  Label11 : TLabel;
  Label12 : TLabel;
  OpenDialog1 : TOpenDialog;
    btAbre: TButton;
    ImageRede: TImage;
    ImagePontos: TImage;
  procedure btAbreClick (Sender : TObject);
  procedure UniformeClick (Sender : TObject);
  procedure TreinarClick (Sender : TObject);
  procedure Button_paraClick (Sender : TObject);
  procedure BtResetClick (Sender : TObject);
  procedure FormCreate (Sender : TObject);
  procedure AjustaPesoRede(tempo,vencedori,vencedorj,padrao:integer;TaxaAprendizagemAtual:real);
  procedure Vencedor(Var vencedori,vencedorj:integer;padrao:integer);
  //procedure AgrupadoClick (Sender : TObject);
  procedure RotularTestarRede (ConjTreinamento : integer);
private
  // Private declarations
public
  // Public declarations
end;
ponto = record
  x, y : real;
  classe : char;
end;

//definicao do neuronio e seus pesos
neuronio = record
  w1, w2 : real;
  rotulo : integer;
  rotulou : byte;
end;

// Prototype
procedure PlotaRede;
procedure PlotaCurvaAprendizagem;
function DistanciaEuclidiana (x, y, padrao : integer) : real;
procedure InicializaRede;
function TaxaAprendizagem (n : real) : real;
procedure PlotaPontos (QtdePontos : integer);
function Vizinhanca (n, VencedorI, VencedorJ, AtualI, AtualJ : integer) : real;
procedure PintaPixel (x, y : real; Imagem : TImage; Cor : TColor);
var
  Form_Kohonen : TForm_Kohonen;
  rede : array [0..9, 0..9] of neuronio;
  EspacoDominio : array [0..999] of ponto;
  // 1 a 50 depois de 10 em 10 ate 500 ==> Total de 95 pontos
  // Quantidade de acertos
  CurvaAprendizagem : array [0..94] of integer;
  arqporc : string;
  indicecurva, NumeroNeuroniosL, NumeroNeuroniosC, parar : integer;
implementation

{$R *.DFM}
//--------------------------------------------------------------------------
function ExtraiChar (classe : string) : char;
Var i : integer;
begin
  i := 1;
  while classe [i] = ' ' do
    inc (i);
  result := classe [i];
end;

//--------------------------------------------------------------------------
//Abre arquivo de pontos
//--------------------------------------------------------------------------
procedure TForm_Kohonen.btAbreClick (Sender : TObject);
Var
  arq : TextFile;
  classe, diretorio, namefile : string;
  x, y : real;
  cont, tam, posarq : integer;
begin
  if OpenDialog1.Execute then begin
    namefile := OpenDialog1.FileName;
    AssignFile (arq, namefile);
    try
      try
        reset (arq);
      except
        showmessage ('Nome de arquivo inválido:' + namefile);
      end;
    finally
      tam := Length (namefile);
      diretorio := GetCurrentDir + '\';
      posarq := Length(diretorio) + 1;
      tam := tam - posarq;
      //adiciona um k (de Kohonen), para o arquivo de porc de acertos
      arqporc := 'k' + Copy (namefile, posarq, tam + 1);
      tam := Length (arqporc) - 3; //tam - extensao
      arqporc := diretorio + Copy (arqporc, 1, tam) + 'dat';
      ReadLn (arq, x, y, classe);
      cont := 0;
      //Atribui ao domínio as coordenadas dos pontos do arquivo
      while (not eof (arq)) do
      begin
        EspacoDominio [cont].x := x; //posicoes
        EspacoDominio [cont].y := y;
        EspacoDominio [cont].classe := ExtraiChar (classe);//guarda a classe
        inc (cont);
        ReadLn (arq, x, y, classe);
      end;
    end
  end;
  CloseFile (arq);
  //Imprime os pontos na tela
  PlotaPontos (1000);
end;
//--------------------------------------------------------------------------
//---------------------------------------------------------------------------
//  USAR ESTE PROCEDIMENTO PARA FAZER COM QUE OS PONTOS APAREÇAM BEM MAIS,
//
//--------------------------------------------------------------------------
procedure PintaPixel (x, y : real; Imagem : TImage; Cor : TColor);
Var ix, iy : integer;
begin
  ix := Round (x);
  iy := Round (y);
  // Pinta ao redor do ponto
  Imagem.Canvas.Pixels [ix, iy] :=Cor;
  Imagem.Canvas.Pixels [ix -1, iy] :=Cor;
  Imagem.Canvas.Pixels [ix, iy - 1] :=Cor;
  Imagem.Canvas.Pixels [ix + 1, iy] :=Cor;
  Imagem.Canvas.Pixels [ix,iy + 1] :=Cor;
end;
//--------------------------------------------------------------------------
//Plota a malha de neuronios de acordo com sua posição
// . -->   . -->    .
// |       |        |
// v       v        v
// . -->   . -->    .
//--------------------------------------------------------------------------
procedure PlotaRede;
Var x, y, xaux, yaux : real;
  i, j : integer;
begin
  // Limpa imagem
  Form_Kohonen.ImageRede.Canvas.Brush.Color := clWhite;
  Form_Kohonen.ImageRede.Canvas.FillRect (Rect (0, 0, 300, 300));
  // Desenha a malha de neuronios
  for i := 0 to NumeroNeuroniosL - 1 do begin
    for j := 0 to NumeroNeuroniosC - 1 do begin
      x := (rede [i, j].w1 + 1) * 150;
      y := (rede [i, j].w2 + 1) * 150;
      Form_Kohonen.ImageRede.Canvas.MoveTo (Round (x), Round (y));
      if (i <> 0) then begin
        xaux := (rede [i - 1, j].w1 + 1) * 150;
        yaux := (rede [i - 1, j].w2 + 1) * 150;
        Form_Kohonen.ImageRede.Canvas.LineTo (Round (xaux), Round (yaux));
        Form_Kohonen.ImageRede.Canvas.MoveTo (Round (x), Round (y));
      end;
      if (j <> 0) then begin
        xaux := (rede [i, j - 1].w1 + 1) * 150;
        yaux := (rede [i, j - 1].w2 + 1) * 150;
        Form_Kohonen.ImageRede.Canvas.LineTo (Round (xaux), Round (yaux));
        Form_Kohonen.ImageRede.Canvas.MoveTo (Round (x), Round (y));
      end;
      Form_Kohonen.ImageRede.Canvas.MoveTo (Round (x), Round (y));
      if (rede[i,j].rotulou<>0) then begin //se foi excitado por algum neuronio
        if (rede[i,j].rotulo = 0) then begin
          Form_Kohonen.ImageRede.Canvas.Brush.Color := clWhite;
          Form_Kohonen.ImageRede.Canvas.Ellipse(Round(x-3),Round(y-3),Round(x+3),Round(y+3));
        end
        else begin
          if (rede [i, j].rotulo > 0) then begin  //se for do grupo azul
            Form_Kohonen.ImageRede.Canvas.Brush.Color := clBlue;//plota azul
            Form_Kohonen.ImageRede.Canvas.Ellipse(Round(x-3),Round(y-3),Round(x+3),Round(y+3));
          end
          else begin
            Form_Kohonen.ImageRede.Canvas.Brush.Color := clRed;
            Form_Kohonen.ImageRede.Canvas.Ellipse(Round(x-3),Round(y-3),Round(x+3),Round(y+3));
          end;
        end;
      end;
    end;
  end;
  Form_Kohonen.ImageRede.Refresh;
end;
//--------------------------------------------------------------------------
//Desenha os pontos na imagem
//--------------------------------------------------------------------------
procedure PlotaPontos (QtdePontos : integer);
Var
  x, y : real;
  i : integer;
begin
  Form_Kohonen.ImageRede.Canvas.Brush.Color := clWhite;
  Form_Kohonen.ImagePontos.Canvas.FillRect (Rect (0, 0, 300, 300));

  for i := 0 to QtdePOntos - 1 do begin
    x := (EspacoDominio [i].x + 1) * 150;
    y := (EspacoDominio [i].y + 1) * 150;
    if (EspacoDominio [i].classe = 'B') then begin
      PintaPixel (x, y, Form_Kohonen.ImagePontos, clBlue);
    end
    else begin
      PintaPixel (x, y, Form_Kohonen.ImagePontos, clRed);
    end;
  end;
end;


//---------------------------------------------------------------------------
//ATRIBUI ALEATORIAMENTE OS PESOS INICIAIS
//---------------------------------------------------------------------------
procedure InicializaRede;
Var
  x, y : real;
  i, j : integer;
begin
  // Setando o número de neurônios
  NumeroNeuroniosL := StrToInt (Form_Kohonen.Edit6.Text);
  NumeroNeuroniosC := StrToInt (Form_Kohonen.Edit7.Text);
  if (NumeroNeuroniosL > 10) then NumeroNeuroniosL := 10;  //nao deixa ser maior que 10
  if (NumeroNeuroniosC > 10) then NumeroNeuroniosC := 10;
  //Imagem 300 x 300
  for i := 0 to NumeroNeuroniosL - 1 do begin
    for j := 0 to NumeroNeuroniosC - 1 do begin
      if (Form_Kohonen.rbDistribuido.Checked) then begin //iniciar distribuido
        x := (i * 30) + 15;  //|--,15,45,75, ..,285,--|
        y := (j * 30) + 15;
      end
      else begin
        //Inicia a partir da posicao 100 até 200 no maximo
        Randomize();
        x := 100 + random (100);
        Randomize();
        y := 100 + random (100);
      end;
      //                    W1 \
      //atribui os pesos        O-
      //                    W2 /
      rede [i, j].w1 := (x / 150) - 1; //150 = 300/2
      rede [i, j].w2 := (y / 150) - 1;

      rede [i, j].rotulo := 0;
      rede [i, j].rotulou := 0;
    end;
  end;
end;

//---------------------------------------------------------------------------
//BUG
//Verificar posteriormente
//---------------------------------------------------------------------------
procedure TForm_Kohonen.UniformeClick (Sender : TObject);
Var
  x, y : real;
  i : integer;
begin
  Form_Kohonen.ImageRede.Canvas.Brush.Color := clWhite;
  ImagePontos.Canvas.FillRect (Rect (0, 0, 300, 300));

  for i:=0 to 999 do begin
    Randomize;
    x := random (300);
    Randomize;
    y := random (300);
    EspacoDominio [i].x := (x / 150) - 1;
    EspacoDominio [i].y := (y / 150) - 1;
    if (random(2) = 0) then begin
      EspacoDominio [i].classe := 'B';
      PintaPixel (x, y, ImagePontos, clBlue);
    end
    else begin
      EspacoDominio [i].classe := 'R';
      PintaPixel (x, y, ImagePontos, clRed);
    end;
  end;
end;


//------------------------------------------------------------------------------
//Atualiza os vizinhos de acordo com a função de vizinhança. Qto mais afastados,
//menos atualizações
//------------------------------------------------------------------------------
procedure TForm_Kohonen.AjustaPesoRede(tempo,vencedori,vencedorj,padrao:integer;TaxaAprendizagemAtual:real);
var hij:real;
    i,j:integer;
begin
  for i := 0 to NumeroNeuroniosL - 1 do
  begin

    for j := 0 to NumeroNeuroniosC - 1 do
    begin
       hij := Vizinhanca (tempo, vencedori, vencedorj, i,j );
       //deltawj=ap*hij*(x - wj)
       //w(n+1)j=w(n)j+deltawj
       //Qto mais afastados menos atualizados
       rede[i,j].w1:=rede[i,j].w1+(TaxaAprendizagemAtual*hij*(EspacoDominio[padrao].x-rede[i,j].w1));
       rede[i,j].w2:=rede[i,j].w2+(TaxaAprendizagemAtual*hij*(EspacoDominio[padrao].y-rede[i,j].w2));
    end;
  end;
end;

//------------------------------------------------------------------------------
//Encontra o neuronio nv mais proximo do padrao. Este é neuronio vencedor
//                       p
//                 n1     nv
//
//                   n2
//------------------------------------------------------------------------------
procedure TForm_Kohonen.Vencedor(Var vencedori,vencedorj:integer;padrao:integer);
Var i,j:integer;
    MenorDistanciaEuclidianaAtual,aux:real;
begin
   MenorDistanciaEuclidianaAtual := distanciaEuclidiana (0, 0, padrao);
   vencedori := 0;
   vencedorj := 0;

   // Procurando na rede o melhor neuronio para o padrao
   for i := 0 to NumeroNeuroniosL - 1 do begin

      for j := 0 to NumeroNeuroniosC - 1 do begin
           aux:=distanciaEuclidiana (i, j, padrao);
           // Argumento minimo da distancia euclidiana
           if (aux < MenorDistanciaEuclidianaAtual) then begin
             MenorDistanciaEuclidianaAtual := aux;
             vencedori := i;
             vencedorj := j;
           end;
     end;
   end;
end;

//---------------------------------------------------------------------------
//Treina a rede
//---------------------------------------------------------------------------
procedure TForm_Kohonen.TreinarClick  (Sender : TObject);
Var
   padrao,aux2, vencedori, vencedorj : integer;
   MenorDistanciaEuclidianaAtual, TaxaAprendizagemAtual : real;
   VizinhancaAux, aux, editTaxa : real;
   tempo, ControleTamanhoTreinamento, i, j : integer;
   ConjTreinamento : integer;
   begin
   if (cbCalcCurva.Checked) then begin  //calcular curva de aprendizagem
     ControleTamanhoTreinamento := 500;
     ConjTreinamento := 1;
   end
   else begin
     ControleTamanhoTreinamento := 1000;
     ConjTreinamento := 1000;
   end;
   parar := 0;
   // Loop de curva de aprendizagem
   while ((ConjTreinamento <= ControleTamanhoTreinamento) and (parar = 0)) do begin
     InicializaRede; //Atribui pesos aleatorios para a rede
     tempo := 1;
     TaxaAprendizagemAtual := TaxaAprendizagem (tempo);
     Form_Kohonen.edTaxaAp.Text := FloatToStr (TaxaAprendizagemAtual);
     Form_Kohonen.edTaxaAp.Refresh();//atualiza taxa no form
     editTaxa := StrToFloat (Form_Kohonen.edCritParada.Text);
     // Loop de treinamento da primeira fase
     // Enquanto aprendizagem nao atingiu objetivo
     while ((TaxaAprendizagemAtual > editTaxa) and (parar = 0)) do begin
       //Pára aprendizagem temporariamente ate pausa ser alterada
       while (cbPausa.Checked) do begin
         Application.ProcessMessages;
       end;
       if (not cbCalcCurva.Checked) then begin
         // Limpando a imagem
         ImageRede.Canvas.FillRect (Rect (0, 0, 300, 300));
         // Plot do estado atual da rede
         PlotaRede;
       end;
       // Seleção do padrão apresentado a rede
       // Dentro do limite do conj. de treinamento
       Randomize;

       //===============================================================
       //Aleatorio ou sequencial no treinamento?
       padrao := random (ConjTreinamento); //seleciona um valor do conjunto
       //===============================================================

       // Busca pelo neurônio vencedor
       // vencedori,vencedorj, posicao do neuronio na rede
       Vencedor(vencedori,vencedorj,padrao);

       // Ajuste dos pesos sinapticos de toda a grade com base no vencedor
       AjustaPesoRede(tempo,vencedori,vencedorj,padrao,TaxaAprendizagemAtual);

       inc (tempo);

       TaxaAprendizagemAtual := TaxaAprendizagem (tempo);
       Form_Kohonen.edTaxaAp.Text := FloatToStr (TaxaAprendizagemAtual);
       Form_Kohonen.edTaxaAp.Refresh;
       Form_Kohonen.edNumIt.Text := FloatToStr (tempo);
       Form_Kohonen.edNumIt.Refresh;
       Application.ProcessMessages;
     end;


     //==============================================
     //Testa a rede
     //==============================================
     RotularTestarRede (ConjTreinamento);
     PlotaRede;
     PlotaPontos (ConjTreinamento);
     //Mostra numero de elementos ja apresentados 1,2,..50,60,70,..,1000
     Form_Kohonen.Edit5.Text := IntToStr (ConjTreinamento);
     Form_Kohonen.Edit5.Refresh;
     // Atualizando o tamanho do conjunto de treinamento
     if (ConjTreinamento < 50) then begin
       inc (ConjTreinamento);
     end
     else begin
       ConjTreinamento := ConjTreinamento + 10;
     end;
   end;
   PlotaCurvaAprendizagem;
end;

//---------------------------------------------------------------------------
//
//
procedure TForm_Kohonen.Button_paraClick (Sender : TObject);
begin
  parar := 1;
end;

//---------------------------------------------------------------------------
//
//
procedure TForm_Kohonen.BtResetClick (Sender : TObject);
Var i : integer;
begin
  InicializaRede;
  PlotaRede;
  PlotaPontos (1000);
  Form_Kohonen.ImageCurva.Canvas.Brush.Color := clBtnFace;
  Form_Kohonen.ImageCurva.Canvas.FillRect (Rect (0, 0, 300, 145));
  indicecurva := 0;

  for i := 0 to 94 do begin
    CurvaAprendizagem [i] := 0;
  end;
end;

//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
procedure TForm_Kohonen.FormCreate (Sender : TObject);
Var
  x, y : real;
  i : integer;
begin
  decimalseparator := '.';
  indicecurva := 0;
  // Setando o número de neurônios
  NumeroNeuroniosL := StrToInt(Edit7.Text);
  NumeroNeuroniosC := StrToInt(Edit6.Text);
  if (NumeroNeuroniosL > 10) then NumeroNeuroniosL := 10;
  if (NumeroNeuroniosC > 10) then NumeroNeuroniosC := 10;
  // Setando os brushes
  Form_Kohonen.ImagePontos.Canvas.Brush.Color := clWhite;
  Form_Kohonen.ImageRede.Canvas.Brush.Color := clWhite;
  // Limpando as imagens
  ImagePontos.Canvas.FillRect (Rect (0, 0, 300, 300));
  ImageRede.Canvas.FillRect (Rect (0, 0, 300, 300));
  // Inicializando o domínio com uma distribuição uniforme

  for i:=0 to 999 do
  begin
    Randomize();
    x := random (300);
    Randomize();
    y := random (300);
    EspacoDominio [i].x := x;
    EspacoDominio [i].y := y;
    if (random (2) = 0) then begin  //retorna valor 0 ou 1
      EspacoDominio [i].classe := 'B';
      PintaPixel (x, y, ImagePontos, clBlue);
    end
    else begin
      EspacoDominio [i].classe := 'R';
      PintaPixel (x, y, ImagePontos, clRed);
    end;
  end;
  // Inicializando a rede
  InicializaRede();
  // Plotando a rede
  PlotaRede();
  // Exibindo a taxa de aprendizagem inicial
  Form_Kohonen.edTaxaAp.Text := FloatToStr (TaxaAprendizagem (1));
  Application.ProcessMessages;
end;


//---------------------------------------------------------------------------
//Cálculo da distância entre o padrao e o neuronio
//---------------------------------------------------------------------------
function DistanciaEuclidiana(x, y, padrao : integer) : real;
begin
  result := sqrt(sqr(rede[x, y].w1 - EspacoDominio [padrao].x)+
                 sqr(rede[x, y].w2 - EspacoDominio [padrao].y));
end;

//---------------------------------------------------------------------------
//
//
function TaxaAprendizagem (n : real) : real;
Var n0, t2 : real;
begin
  n0 := (1.0 / 10.0);   //10%
  t2 := 1000;
  result := (n0 * exp (-n / t2));  //sigmoide
end;

//---------------------------------------------------------------------------
//Cálculo da Funcao de vizinhança, para atualização dos neuronios
//---------------------------------------------------------------------------
function Vizinhanca (n, VencedorI, VencedorJ, AtualI, AtualJ : integer) : real;
Var lambda0, lambda, t1, d2, aux, sigma : real;
begin
  sigma := StrToFloat (Form_Kohonen.edSigma.Text);
  lambda0 := StrToFloat (Form_Kohonen.edLambda0.Text);  //param 2
  t1 := (1000 / ln (lambda0));
  //distancia quadratica entre vencedor e neuronio da vizinhança
  d2 := sqr(AtualI - VencedorI) + sqr(AtualJ - VencedorJ);
  lambda := lambda0 * exp (-n / t1);

  aux := exp (-d2 * (n / sigma * 2 * sqr(lambda)));
  if (aux < StrToFloat(Form_Kohonen.edVizMin.Text)) then
  begin
    //se os atuais são vizinhos minimos
    //       n
    //     n v n
    //       n
    if(AtualI-1=VencedorI)and(AtualJ=VencedorJ)then aux:=StrToFloat(Form_Kohonen.edVizMin.Text);
    if(AtualI+1=VencedorI)and(AtualJ=VencedorJ)then aux:=StrToFloat(Form_Kohonen.edVizMin.Text);
    if(AtualI=VencedorI)and(AtualJ-1=VencedorJ)then aux:=StrToFloat(Form_Kohonen.edVizMin.Text);
    if(AtualI=VencedorI)and(AtualJ+1=VencedorJ)then aux:=StrToFloat(Form_Kohonen.edVizMin.Text);
  end;
  result := (aux);
end;

//---------------------------------------------------------------------------
//
//
procedure TForm_Kohonen.RotularTestarRede (ConjTreinamento : integer);
Var
  aux, MenorDistanciaEuclidianaAtual : real;
  vencedori, vencedorj, acertos, i, j, treino, teste : integer;
begin
  // Rotulando
  for treino := 0 to ConjTreinamento - 1 do begin

    // Procurando na rede o melhor neuronio para o padrao
    Vencedor(vencedori,vencedorj,treino);

    // Ajusta o rotulo do melhor neuronio para o padrao de treino
    if (EspacoDominio [treino].classe = 'B') then begin
      if (rede [vencedori, vencedorj].rotulou = 0) then begin
        rede [vencedori, vencedorj].rotulou := 1;
      end;
      inc (rede [vencedori, vencedorj].rotulo);
    end
    else begin
      if (rede [vencedori, vencedorj].rotulou = 0) then begin
        rede [vencedori, vencedorj].rotulou := 1;
      end;
      dec (rede [vencedori, vencedorj].rotulo);
    end;
  end;
  acertos := 0;

  // Loop de teste
  for teste := 500 to 999 do begin //para cada ponto de teste faça
    // Procurando na rede o melhor neuronio para o padrao
    Vencedor(vencedori,vencedorj,teste);

    if (rede [vencedori, vencedorj].rotulou <> 0) then begin
      if (rede [vencedori, vencedorj].rotulo = 0) then begin
        inc (acertos);
      end
      else begin
        if (rede [vencedori, vencedorj].rotulo > 0) then begin
          if (EspacoDominio [teste].classe = 'B') then begin
            inc (acertos);
          end;
        end
        else begin
          if (EspacoDominio [teste].classe = 'R') then begin
            inc (acertos);
          end;
        end;
      end;
    end;
  end;
  CurvaAprendizagem [indicecurva] := acertos;
  inc (indicecurva);
end;
//---------------------------------------------------------------------------
procedure PlotaCurvaAprendizagem;
Var
  i, cont : integer;
  F : TextFile;
  PorcAcertos : real;
begin
  Form_Kohonen.ImageCurva.Canvas.Brush.Color := clWhite;
  Form_Kohonen.ImageCurva.Canvas.FillRect (Rect (0, 0, 300, 145));
  Form_Kohonen.ImageCurva.Canvas.Brush.Color := clRed;
  Form_Kohonen.ImageCurva.Canvas.MoveTo (0, 72);
  Form_Kohonen.ImageCurva.Canvas.LineTo (300, 72);
  Form_Kohonen.ImageCurva.Canvas.MoveTo (0, 36);
  Form_Kohonen.ImageCurva.Canvas.LineTo (300, 36);
  Form_Kohonen.ImageCurva.Canvas.MoveTo (0, 108);
  Form_Kohonen.ImageCurva.Canvas.LineTo (300, 108);
  Form_Kohonen.ImageCurva.Canvas.Brush.Color := clGreen;
  cont := 0;
  //AssignFile (F, arqporc);
  //Rewrite (F);
  for i := 0 to 94 do begin
     if cont < 50 then inc (cont) //ate 50 de 1 em 1, depois
     else cont := cont+10; //vai de 10 em 10
    // 145 é a altura do ImageCurva, a largura é 300
    // de cima para baixo
    Form_Kohonen.ImageCurva.Canvas.MoveTo (i * 3 + 7, 145);
    // CurvaAprendizagem tem o numero de acertos
    // CurvaApredizagem / 500 = % acertos
    PorcAcertos := (CurvaAprendizagem [i] / 500);
    //Pinta a barra de acertos
    Form_Kohonen.ImageCurva.Canvas.LineTo (i * 3 + 7, Round (145 - PorcAcertos * 145));
    //Writeln (F,cont,' ',PorcAcertos:2:2);
  end;
  //CloseFile (F);
end;

//---------------------------------------------------------------------------


end.
