unit ucerebro_01;

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls, ComCtrls, Grids, uneuronas, fddp, udisnormcan,
  ufechas,
  Math,
  xmatdefs, matreal, matent, matbool,
  usigmoide,
  utipos_xcf,
  uauxiliares,
  utrayectorias_xcdpcf,
  ugaussiana_multivar,
  useriestemporales,
  umixturedensitynetworks;

type

  { TForm1 }

  TForm1 = class(TForm)
    btAgregarTIpoDia: TButton;
    btCalcCovars: TButton;
    btCrearCerebro: TButton;
    btDecPaso: TButton;
    btIncPaso: TButton;
    btLoadSeries: TButton;
    btPerceptronSTEP: TButton;
    btSelSeries: TButton;
    btTest01: TButton;
    btVerosimilitud: TButton;
    btWriteTiposDeDia: TButton;
    Button1: TButton;
    btEj01: TButton;
    btEj02: TButton;
    btEj03: TButton;
    btEj04: TButton;
    btEj05_ExplicadorYX: TButton;
    btFrameTrayectoriasToSeries: TButton;
    Button2: TButton;
    btMixtureDensityNetwork: TButton;
    cbGuardar: TCheckBox;
    cbLeerParametros: TCheckBox;
    cbRandomKick: TCheckBox;
    cbAgregarUnaLinEnCapasIntermedias: TCheckBox;
    cbFiltrarRadiacion: TCheckBox;
    eArchi: TLabeledEdit;
    eAlfa_Regularizacion: TEdit;
    eSerieRadiacion: TEdit;
    ePRND: TEdit;
    ePasoIni: TEdit;
    eMomento: TEdit;
    eFrame: TEdit;
    eEstructura: TEdit;
    eN1_bias: TLabeledEdit;
    eN1_ro: TLabeledEdit;
    eN2_bias: TLabeledEdit;
    eN2_ro: TLabeledEdit;
    eN3_bias: TLabeledEdit;
    eN3_ro_1: TLabeledEdit;
    eN3_ro_2: TLabeledEdit;
    eNRetardos: TLabeledEdit;
    ePaso: TEdit;
    eUmbralFiltro: TLabeledEdit;
    eVerosimilitud: TEdit;
    Image1: TImage;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    lbSerieRadiacion: TLabel;
    OpenDialog1: TOpenDialog;
    PageControl1: TPageControl;
    PaintBox1: TPaintBox;
    rgEstructuraCerebro: TRadioGroup;
    rgTipoSaturacionSalida: TRadioGroup;
    rgTipoSaturacionPenultimaCapa: TRadioGroup;
    StaticText1: TStaticText;
    TabSheet1: TTabSheet;
    tsCerebro: TTabSheet;
    procedure btAgregarTIpoDiaClick(Sender: TObject);
    procedure btCrearCerebroClick(Sender: TObject);
    procedure btEj01Click(Sender: TObject);
    procedure btDecPasoClick(Sender: TObject);
    procedure btEj02Click(Sender: TObject);
    procedure btEj03Click(Sender: TObject);
    procedure btEj04Click(Sender: TObject);
    procedure btEj05_ExplicadorYXClick(Sender: TObject);
    procedure btIncPasoClick(Sender: TObject);
    procedure btPerceptronSTEPClick(Sender: TObject);
    procedure btSelSeriesClick(Sender: TObject);
    procedure btCalcCovarsClick(Sender: TObject);
    procedure btLoadSeriesClick(Sender: TObject);
    procedure btTest01Click(Sender: TObject);
    procedure btVerosimilitudClick(Sender: TObject);
    procedure btWriteTiposDeDiaClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure btFrameTrayectoriasToSeriesClick(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure btMixtureDensityNetworkClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    procedure CargueParametrosPrueba;
    procedure PrintParametrosPrueba;
    { private declarations }
  public
    { public declarations }

    nRetardos: integer;
    umbral_filtro: NReal;
    series: TSeriesDeDatos;
    CalcCovars: TCalculadorCovars;

    parametros_mejor: TVectR;
    cntEvaluaciones: integer;
    fMejor: NReal;
    Cerebro: TCerebro;
    aData: TDAOfRecXCF;  // Datos de entrenamiento

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }


procedure PlotXY_simple(Panel: TImage; series: TSeriesDeDatos; kSerieX, kSerieY: integer );
var
  x: TVectR;
  y: TVectR;
  k: integer;
  aRec: TRecXCF;
  kymin, kymax: integer;
  xmin, xmax, ymax, ymin: NReal;
  sindx: TDAofNInt;
  px, py: integer;
  dx, dy: NReal;
  ax, ay: NReal;
  kmin, kmax: integer;

function ypy( y: NReal ): integer;
begin
  result:= trunc(Panel.Height * max( 0, min(1, (1 - (y - ymin) / dy) ))) ;
end;

function xpx( x: NReal ): integer;
begin
  result:= trunc(Panel.width *  (x - xmin) / dx);
end;


begin
  x := series.GetSerie( kSerieX );
  y:= series.GetSerie( kSerieY );

  x.MinMax( kmin, kmax, xmin, xmax, true, -11111 );
  dx:= xmax - xmin;
  if dx < 1e-13 then
    dx := 1;

  y.MinMax( kmin, kmax, ymin, ymax, true, -11111 );
  dy := ymax - ymin;
  if dy < 1e-13 then
    dy := 1;



  Panel.Canvas.Pen.Color := CLRed;
  for k:= 1 to x.n do
  begin
    ax:= x.e( k );
    ay:= y.e( k );
    if ( ax > -11111 ) and ( ay > -11111) then
    begin
      px:= xpx( ax );
      py:= ypy( ay );
      Panel.Canvas.MoveTo(px-2, py-2);
      Panel.Canvas.LineTo(px+2, py+2);
      Panel.Canvas.MoveTo(px+2, py-2);
      Panel.Canvas.LineTo(px-2, py+2);
    end;
  end;
end;


procedure TForm1.btSelSeriesClick(Sender: TObject);
begin
  if OpenDialog1.Execute then
  begin
    if series <> nil then
    begin
      series.Free;
      series := nil;
      CalcCovars.Free;
      CalcCovars := nil;
    end;
    eArchi.Text := OpenDialog1.FileName;
  end;
end;

procedure TForm1.btCrearCerebroClick(Sender: TObject);
var
  CapasDef: TDAofNInt;
  k: integer;
  aCapa: TCapaNeuronas;
  aNeurona: TNeurona;

begin
  if Cerebro <> nil then
    Cerebro.Free;
  setlength(CapasDef, 2);
  CapasDef[0] := series.NSeriesX * 2;
  CapasDef[1] := series.NSeriesY;

  Cerebro := TCerebro.Create(series.NSeriesX * (1 + nRetardos), CapasDef,
    CTS_Tanh, CTS_Lineal);

  if parametros_mejor <> nil then
    parametros_mejor.Free;
  parametros_mejor := TVectR.Create_Init(Cerebro.DimParametros);

  randomize;
  Cerebro.RandomInit(1);



  eN1_bias.Text := FloatToStr(-12.8 * 0.386);
  eN1_ro.Text := FloatToStr(-0.386);

  eN2_bias.Text := FloatToStr(27.5 * 0.146);
  eN2_ro.Text := FloatToStr(0.146);

  eN3_bias.Text := FloatToStr(-85.7 * 4);
  eN3_ro_1.Text := FloatToStr(54.2 * 4);
  eN3_ro_2.Text := FloatToStr(184.9 * 4);

  cntEvaluaciones := 0;
  fMejor := -1E20;
end;

procedure TForm1.btEj01Click(Sender: TObject);
var
  Cerebro: TCerebro;
  CapasDef: TDAofNInt;
  k, j: integer;
  aData: TDAOfRecXCF;  // Datos de entrenamiento
  aRec: TRecXCF;
  ax, ay: NReal;
  e2: NReal;
  parametros: TVectR;

begin

  // Creamos datos con modelo y = sigmoide( x )
  setlength(aData, 100);
  for k := 1 to 100 do
  begin
    ax := (k - 50.0) / 100.0;
    ay := sigmoide(ax) + (random - 0.5) / 100.0;
    aRec := TRecXCF.Create(1, 1);
    aRec.X.pon_e(1, ax);
    aRec.Y.pon_e(1, ay);
    aData[k - 1] := aRec;
  end;

  // creamos un cerebro de una sola neurona
  setlength(CapasDef, 1);
  CapasDef[0] := 1;
  Cerebro := TCerebro.Create(1, CapasDef, CTS_Tanh, CTS_Tanh);

  parametros := TVectR.Create_Init(Cerebro.DimParametros);

  randomize;
  Cerebro.RandomInit(0.1);
  cntEvaluaciones := 0;
  fMejor := -1E20;

  Cerebro.GetParametros(parametros);
  Write(0, #9, '??');
  for j := 1 to parametros.n do
    Write(#9, parametros.e(j));
  writeln;

  for k := 1 to 1000 do
  begin
    e2 := EntrenarCerebro_EBP(Cerebro, aData, 0.1, 0.7, 0.0001 );
    Cerebro.GetParametros(parametros);

    Write(k, #9, e2);
    for j := 1 to parametros.n do
      Write(#9, parametros.e(j));
    writeln;
  end;

  free_data_xcf(aData);

  parametros.Free;
  Cerebro.Free;

end;


procedure TForm1.btAgregarTIpoDiaClick(Sender: TObject);
var
  sTemp, sE, tipoDia: TVectR;
  dt0, dt, ddt: TDateTime;
  td: NReal;
  kPunto, kHora: integer;
  sal: textfile;
  acum_e, acum_temp: NReal;

begin
  if series <> nil then
  begin
    series.Free;
  end;
  series := TSeriesDeDatos.CreateFromArchi(eArchi.Text);
  sE := series.series[0];
  sTemp := series.series[1];
  tipoDia := TVectR.Create_Init(series.NPuntos);
  dt0 := series.dtPrimeraMuestra;
  ddt := series.dtEntreMuestras;
  for kPunto := 1 to tipoDia.n do
  begin
    dt := dt0 + (kPunto - 1) * ddt;
    td := Ord(TipoDeDiaUruguay(dt));
    tipoDia.pon_e(kPunto, td);
  end;
  series.AddSerie('TipoDia', tipoDia, ENTRADA);
  series.WriteToArchi('c:\basura\serie_con_tipodia.xlt');

  assignfile(sal, 'c:\basura\dem_diaria_temp_tipodia.xlt');
  rewrite(sal);
  for kHora := 1 to 23 do
    Write(sal, #9, kHora);

  writeln(sal, #9, 'EDia_MWh', #9, 'TipoDia', #9, 'TempDia_grC');

  kHora := 0;

  for kPunto := 1 to tipoDia.n do
  begin
    dt := dt0 + (kPunto - 1) * ddt;
    if kHora = 0 then
    begin
      Write(sal, DateTimeToIsoStr(dt));
      acum_temp := 0;
      acum_e := 0;
      td := tipoDia.e(kPunto);
    end;
    acum_temp := acum_temp + sTemp.e(kPunto);
    acum_e := acum_e + sE.e(kPunto);
    Write(sal, #9, sE.e(kPunto));
    Inc(kHora);
    if kHora = 24 then
    begin
      writeln(sal, #9, acum_e, #9, td, #9, acum_temp / 24);
      kHora := 0;
    end;
  end;
  closefile(sal);


  series.Free;
  series := nil;
end;


procedure TForm1.CargueParametrosPrueba;
var
  aNeurona: TNeuronaConEntradas;

begin
  aNeurona := Cerebro.capas[0].Neuronas[0] as TNeuronaConEntradas;
  aNeurona.bias := strToFloat(eN1_bias.Text);
  aNeurona.ro[0] := StrToFloat(eN1_ro.Text);

  aNeurona := Cerebro.capas[0].Neuronas[1] as TNeuronaConEntradas;
  aNeurona.bias := StrToFloat(eN2_bias.Text);
  aNeurona.ro[0] := StrToFloat(eN2_ro.Text);

  aNeurona := Cerebro.capas[1].Neuronas[0] as TNeuronaConEntradas;
  aNeurona.bias := StrToFloat(eN3_bias.Text);
  aNeurona.ro[0] := StrToFloat(eN3_ro_1.Text);
  aNeurona.ro[1] := StrToFloat(eN3_ro_2.Text);

end;


procedure TForm1.PrintParametrosPrueba;
var
  aNeurona: TNeuronaConEntradas;

begin
  aNeurona := Cerebro.capas[0].Neuronas[0] as TNeuronaConEntradas;
  eN1_bias.Text := FloatToStr(aNeurona.bias);
  eN1_ro.Text := FloatToStr(aNeurona.ro[0]);

  aNeurona := Cerebro.capas[0].Neuronas[1] as TNeuronaConEntradas;
  eN2_bias.Text := FloatToStr(aNeurona.bias);
  eN2_ro.Text := FloatToStr(aNeurona.ro[0]);

  aNeurona := Cerebro.capas[1].Neuronas[0] as TNeuronaConEntradas;
  eN3_bias.Text := FloatToStr(aNeurona.bias);
  eN3_ro_1.Text := FloatToStr(aNeurona.ro[0]);
  eN3_ro_2.Text := FloatToStr(aNeurona.ro[1]);

end;


procedure TForm1.btDecPasoClick(Sender: TObject);
begin
  ePaso.Text := FloatToStr(StrToFloat(epaso.Text) / 3);
end;

procedure TForm1.btEj02Click(Sender: TObject);
var
  Cerebro: TCerebro;
  CapasDef: TDAofNInt;
  k, k1, k2, j: integer;
  aData: TDAOfRecXCF;  // Datos de entrenamiento
  aRec: TRecXCF;
  ax1, ax2, ay: NReal;
  e2: NReal;
  parametros: TVectR;

begin

  // Creamos datos con modelo y = sigmoide( x1 - 3 x2 + 2  )
  setlength(aData, 100 * 100);
  k := 0;
  for k1 := 1 to 100 do
    for k2 := 1 to 100 do
    begin
      ax1 := (k1 - 50.0) / 100.0;
      ax2 := (k2 - 50.0) / 100.0;
      ay := sigmoide(ax1 - 3 * ax2 + 2);
      aRec := TRecXCF.Create(2, 1);
      aRec.X.pon_e(1, ax1);
      aRec.X.pon_e(2, ax2);
      aRec.Y.pon_e(1, ay);
      aData[k] := aRec;
      Inc(k);
    end;

  // creamos un cerebro de una sola neurona
  setlength(CapasDef, 1);
  CapasDef[0] := 1;
  Cerebro := TCerebro.Create(2, CapasDef, CTS_Tanh, CTS_Tanh);

  parametros := TVectR.Create_Init(Cerebro.DimParametros);

  randomize;
  Cerebro.RandomInit(0.1);
  cntEvaluaciones := 0;
  fMejor := -1E20;

  Cerebro.GetParametros(parametros);
  Write(0, #9, '??');
  for j := 1 to parametros.n do
    Write(#9, parametros.e(j));
  writeln;

  for k := 1 to 1000 do
  begin
    e2 := EntrenarCerebro_EBP(Cerebro, aData, 0.1, 0.7, 0.0001);
    Cerebro.GetParametros(parametros);

    Write(k, #9, e2);
    for j := 1 to parametros.n do
      Write(#9, parametros.e(j));
    writeln;
  end;

  free_data_xcf(aData);

  parametros.Free;
  Cerebro.Free;

end;

procedure TForm1.btEj03Click(Sender: TObject);
var
  Cerebro: TCerebro;
  CapasDef: TDAofNInt;
  k, k1, k2, j: integer;
  aData: TDAOfRecXCF;  // Datos de entrenamiento
  aRec: TRecXCF;
  ax1, ax2, ay1, ay2: NReal;
  e2: NReal;
  parametros: TVectR;
  kMuestra: integer;
  sal: textfile;

begin

  // Creamos datos con modelo y = sigmoide( x )
  setlength(aData, 100 * 100);
  k := 0;
  for k1 := 1 to 100 do
    for k2 := 1 to 100 do
    begin
      ax1 := (k1 - 50.0) / 100.0;
      ax2 := (k2 - 50.0) / 100.0;
      ay1 := sigmoide(ax1);
      ay2 := sigmoide(ay1 - ax2 + 3);
      aRec := TRecXCF.Create(2, 1);
      aRec.X.pon_e(1, ax1);
      aRec.X.pon_e(2, ax2);
      aRec.Y.pon_e(1, ay2);
      aData[k] := aRec;
      Inc(k);
    end;

  // creamos un cerebro de dos capas la primera con 2 neuronas y la segunada con una sola neurona
  setlength(CapasDef, 2);
  CapasDef[0] := 2;
  CapasDef[1] := 1;
  Cerebro := TCerebro.Create(2, CapasDef, CTS_Tanh, CTS_Tanh);

  parametros := TVectR.Create_Init(Cerebro.DimParametros);

  randomize;
  Cerebro.RandomInit(0.1);
  cntEvaluaciones := 0;
  fMejor := -1E20;

  Cerebro.GetParametros(parametros);
  Write(0, #9, '??');
  for j := 1 to parametros.n do
    Write(#9, parametros.e(j));
  writeln;

  for k := 1 to 1000 do
  begin
    e2 := EntrenarCerebro_EBP(Cerebro, aData, 100, 0.7, 0.0001);
    Cerebro.GetParametros(parametros);
    Write(k, #9, e2);
    for j := 1 to parametros.n do
      Write(#9, parametros.e(j));
    writeln;
  end;


  assignfile(sal, 'cerebro_ej03.xlt');
  rewrite(sal);
  for kMuestra := 0 to High(aData) do
  begin
    aRec := aData[kMuestra];
    Cerebro.SetEntradas(aRec.X);
    Cerebro.evaluar;
    ay2 := Cerebro.CapaSalida.Neuronas[0].salida;
    for j := 1 to aRec.X.n do
      Write(sal, #9, aRec.X.e(j));
    writeln(sal, #9, aRec.Y.e(1), #9, ay2);
  end;
  closefile(sal);

  free_data_xcf(aData);
  parametros.Free;
  Cerebro.Free;

end;

procedure TForm1.btEj04Click(Sender: TObject);
var
  Cerebro: TCerebro;
  CapasDef: TDAofNInt;
  k, k1, k2, j: integer;
  aData: TDAOfRecXCF;  // Datos de entrenamiento
  aRec: TRecXCF;
  ax1, ax2, ay1: NReal;
  e2: NReal;
  parametros: TVectR;
  kMuestra: integer;
  sal: textfile;
  e2_ant: NReal;
  cnt_exitos, cnt_fracasos: integer;
  paso: NReal;
  grad: TVectR;

begin

  // Creamos datos con modelo y = sigmoide( x )
  setlength(aData, 100 * 100);
  k := 0;
  for k1 := 1 to 100 do
    for k2 := 1 to 100 do
    begin
      ax1 := (k1 - 50.0) / 100.0;
      ax2 := (k2 - 50.0) / 100.0;
      ay1 := sqr(ax1) + sqr(ax2);
      aRec := TRecXCF.Create(2, 1);
      aRec.X.pon_e(1, ax1);
      aRec.X.pon_e(2, ax2);
      aRec.Y.pon_e(1, ay1);
      aData[k] := aRec;
      Inc(k);
    end;

  // creamos un cerebro de dos capas la primera con 2 neuronas y la segunada con una sola neurona
  setlength(CapasDef, 2);
  CapasDef[0] := 4;
  CapasDef[1] := 1;
  Cerebro := TCerebro.Create(2, CapasDef, CTS_Tanh, CTS_Lineal);

  parametros := TVectR.Create_Init(Cerebro.DimParametros);

  randomize;
  Cerebro.RandomInit(0.01);
  cntEvaluaciones := 0;
  fMejor := -1E20;

  Cerebro.GetParametros(parametros);
  Write(0, #9, '??');
  for j := 1 to parametros.n do
    Write(#9, parametros.e(j));
  writeln;

  e2_ant := 1e30;
  paso := 1;
  cnt_exitos := 0;
  cnt_fracasos := 0;


  grad := TVectR.Create_Init(Cerebro.DimParametros);
  grad.Ceros;

  for k := 1 to 1000 do
  begin
    e2 := EntrenarCerebro_EBP(Cerebro, aData, paso, 0.7, 0.0001 );
    //e2 := EntrenarCerebro_EBP_minibatch( grad, Cerebro, aData, paso, 100, k+31 );


    if e2 <= e2_ant then
    begin
      Cerebro.GetParametros(parametros);
      e2_ant := e2;
      cnt_fracasos := 0;
      Inc(cnt_exitos);
      if cnt_exitos > 3 then
      begin
        cnt_exitos := 0;
        paso := paso * 1.03;
      end;
    end
    else
    begin
      //      Cerebro.SetParametros(parametros);
      cnt_exitos := 0;
      Inc(cnt_fracasos);
      if cnt_fracasos > 30 then
      begin
        cnt_fracasos := 0;
        paso := paso * 0.97;
      end;
    end;
    Write(k, #9, e2, #9, paso);
    (*
    Cerebro.GetParametros(parametros);
    for j := 1 to parametros.n do
      Write(#9, parametros.e(j));
      *)
    writeln;
  end;



  assignfile(sal, 'cerebro_ej04.xlt');
  rewrite(sal);
  for kMuestra := 0 to High(aData) do
  begin
    aRec := aData[kMuestra];
    Cerebro.SetEntradas(aRec.X);
    Cerebro.evaluar;
    ay1 := Cerebro.CapaSalida.Neuronas[0].salida;
    for j := 1 to aRec.X.n do
      Write(sal, #9, aRec.X.e(j));
    writeln(sal, #9, aRec.Y.e(1), #9, ay1);
  end;
  closefile(sal);

  free_data_xcf(aData);
  parametros.Free;
  Cerebro.Free;

  grad.Free;
end;



procedure Plot( Panel: TImage; Cerebro: TCerebro; aData: TDAOfRecXCF; kPaso: integer );
// Datos de entrenamiento

var
  ydata: TVectR;
  ysal: TVectR;
  k: integer;
  aRec: TRecXCF;
  kymin, kymax: integer;
  ymed, ymax, ymin: NReal;
  sindx: TDAofNInt;
  px, py: integer;
  dy: NReal;

function pyofy( y: NReal ): integer;
begin
  result:= trunc( Panel.Height * max( 0, min(1, (1 - (y - ymin) / dy) ))) ;
end;

procedure DrawPoint( px, py: integer );
begin
  panel.canvas.moveto( px-2, py-2 );
  panel.canvas.lineto( px+2, py+2 );
  panel.canvas.moveto( px-2, py+2 );
  panel.canvas.lineto( px+2, py-2 );
end;

begin

  Panel.Canvas.Brush.Color := clblack;
  Panel.Canvas.FillRect(0, 0, Panel.width, panel.height );

  ydata := TVectR.Create_init(length(aData));
  ysal := TVectR.Create_init(length(aData));
  setlength(sindx, ySal.n + 1);
  for k := 0 to high(aData) do
  begin
    aRec := aData[k];
    Cerebro.SetEntradas(aRec.X);
    Cerebro.evaluar;
    ydata.pon_e(k + 1, aRec.Y.e(1));
    ysal.pon_e(k + 1, Cerebro.GetSalida(0));
    sindx[k + 1] := k + 1;
  end;

  ydata.Sort_idx(True, sindx);
  ysal.SortByIdx(sindx);

  ydata.MinMax(kymin, kymax, ymin, ymax);

  dy := ymax - ymin;
  if dy < 1e-3 then
    dy := 1;
  ymed:= ( ymax + ymin ) / 2.0;
  ymax:= ymed + 1.1/2.0 * dy;
  ymin:= ymed - 1.1/2.0 * dy;
  dy := ymax - ymin;


  Panel.Canvas.Pen.Color := CLRed;
  for k := 1 to ydata.n do
  begin
    px := trunc((k - 1) / ydata.n * Panel.Width);
    py := pyofy(ydata.e(k));
    DrawPoint( px, py );
  end;

  Panel.Canvas.Pen.Color := ClGreen;
  for k := 1 to ydata.n do
  begin
    px := trunc((k - 1) / ydata.n * Panel.Width);
    py := pyofy(ysal.e(k));
    DrawPoint( px, py );
  end;

  ydata.Free;
  ysal.Free;
end;




procedure PlotMDN( Panel: TImage; MDN: TMixtureDensityNetwork; aData: TDAOfRecXCF; kPaso: integer );

var
  ydata: TVectR;
  yPE30, yPE50, yPE70: TVectR;
  k: integer;
  aRec: TRecXCF;
  kymin, kymax: integer;
  ymed, ymax, ymin: NReal;
  sindx: TDAofNInt;
  px, py: integer;
  dy: NReal;
  color: TColor;

function pyofy( y: NReal ): integer;
begin
  result:= trunc(Panel.Height * max( 0, min(1, (1 - (y - ymin) / dy) ))) ;
end;




procedure DrawPoint( px, py: integer );
begin
  panel.canvas.moveto( px-2, py-2 );
  panel.canvas.lineto( px+2, py+2 );
  panel.canvas.moveto( px-2, py+2 );
  panel.canvas.lineto( px+2, py-2 );
end;

procedure DrawSerie( y: TVectR; color: TColor );
var
  k: integer;
  px, py: integer;
begin
  Panel.Canvas.Pen.Color := color;
  for k := 1 to y.n do
  begin
    px := trunc((k - 1) / y.n * Panel.Width);
    py := pyofy(y.e(k));
    DrawPoint(px, py);
  end;
end;


begin
  Panel.Canvas.Brush.Color := clblack;
  Panel.Canvas.FillRect(0, 0, Panel.width, panel.height );

  ydata := TVectR.Create_init(length(aData));
  yPE30 := TVectR.Create_init(length(aData));
  yPE50 := TVectR.Create_init(length(aData));
  yPE70 := TVectR.Create_init(length(aData));

  setlength(sindx, yPE50.n + 1);

  for k := 0 to high(aData) do
  begin
    aRec := aData[k];
    MDN.SetEntradas( aRec.X );
    MDN.evaluar;
    ydata.pon_e(k + 1, aRec.Y.e(1));
    yPE30.pon_e(k + 1, MDN.yOfPE( 0.3, 0 ) );
    yPE50.pon_e(k + 1, MDN.yOfPE( 0.5, 0 ) );
    yPE70.pon_e(k + 1, MDN.yOfPE( 0.7, 0 ) );
    sindx[k + 1] := k + 1;
  end;

  yPE50.Sort_idx(True, sindx);
  ydata.SortByIdx( sindx );
  yPE30.SortByIdx( sindx );
  yPE70.SortByIdx( sindx );

  ydata.MinMax(kymin, kymax, ymin, ymax);

  dy := ymax - ymin;
  if dy < 1e-3 then
    dy := 1;
  ymed:= ( ymax + ymin ) / 2.0;
  ymax:= ymed + 1.1/2.0 * dy;
  ymin:= ymed - 1.1/2.0 * dy;
  dy := ymax - ymin;

  DrawSerie( yPE30, clGreen );
  DrawSerie( yPE50, clBlue );
  DrawSerie( yPE70, clYellow );
  DrawSerie( ydata, ClRed );

  ydata.Free;
  yPE30.Free;
  yPE50.Free;
  yPE70.Free;
end;





procedure TForm1.btEj05_ExplicadorYXClick(Sender: TObject);
var
  CapasDef: TDAofNInt;
  TiposSat: TDaOfTipoSaturacion;
  k, k1, k2, j: integer;
  aRec: TRecXCF;
  ax1, ax2, ay1: NReal;
  e2: NReal;
  parametros: TVectR;
  kMuestra: integer;
  sal: textfile;
  e2_ant: NReal;
  cnt_exitos, cnt_fracasos: integer;
  grad, verr: TVectR;
  archi: string;
  series: TSeriesDeDatos;
  ny, nx: integer;

  kCapa, kNeurona: integer;
  flgConvergio: boolean;
  cntIters: integer;
  cntPuntosValidos: integer;
  sdat: string;
  pal, capas: string;
  tipoSaturacionPenultimaCapa, tipoSaturacionSalida: TTipoSaturacion;
  cnt_Exitos_rnd: integer;
  aNeurona: TNeuronaEntrada;

  momento, paso, prnd: NReal;

  pesosPorRango: TDAOfNREal;
  cuentasPorRango: TDAOfNInt;
  suma, ymin, ymax, dy: NReal;
  alfa_Regularizacion: NReal;
  jRadiacion: integer;

begin
  if aData = nil then
  begin
    if OpenDialog1.Execute then
      archi := OpenDialog1.FileName
    else
      exit;

    series := TSeriesDeDatos.CreateFromArchi(archi);
    nx := series.NSeriesX;
    ny := series.NSeriesY;

    if rgEstructuraCerebro.ItemIndex < 2 then
    begin
         case rgEstructuraCerebro.ItemIndex of
         0: begin
            pal := eEstructura.Text;
            tipoSaturacionSalida := TTipoSaturacion(rgTipoSaturacionSalida.ItemIndex);
           end;
        1:
        begin
          sdat := series.comentario;
          pal := getNextPalSep(sdat, '{');
          pal := getNextPalSep(sdat, '}');
          tipoSaturacionPenultimaCapa := TTipoSaturacion(StrToInt(trim(sdat)));
          tipoSaturacionSalida := TTipoSaturacion(StrToInt(trim(sdat)));
          rgTipoSaturacionSalida.ItemIndex := Ord(tipoSaturacionSalida);
        end;
        end;
         setlength(CapasDef, 2000);
         setlength(TiposSat, 2000);
         k := 0;
         sdat := pal;
         pal := getNextPalSep(sdat, ',');
         while pal <> '' do
         begin
           capas := getNextPalSep(pal, ';');
           CapasDef[k] := StrToInt(capas);
           TiposSat[k] := StrToTipoSaturacion(pal);
           Inc(k);
           pal := getNextPalSep(sdat, ',');
         end;

         setlength(CapasDef, k + 1);
         setlength(TiposSat, k + 1);

         CapasDef[k] := ny;
         TiposSat[k] := tipoSaturacionSalida;
         if k > 0 then
           tipoSaturacionPenultimaCapa := TiposSat[k - 1];

   end
   else
   begin
     if Cerebro = nil then
     begin
        if OpenDialog1.Execute then
          Cerebro:= TCerebro.CreateFromArchi( OpenDialog1.FileName );
     end
     else
       exit;
   end;


 //   series.invertir_orden;

    jRadiacion:= StrToInt( eSerieRadiacion.text );

    setlength(aData, series.NPuntos);
    cntPuntosValidos := 0;
    for k := 1 to series.NPuntos do
    begin
      aRec := TRecXCF.Create(nx, ny);
      for j := 1 to nx do
        aRec.X.pon_e(j, series.seriesX[j - 1].e(k));
      for j := 1 to ny do
        aRec.Y.pon_e(j, series.seriesY[j - 1].e(k));
      if ( not aRec.filtrarMenorQue(-11111) )
          and ( ( not cbFiltrarRadiacion.Checked ) or ( aRec.X.e( jRadiacion) > 10 )) then
            // or  aRec.filtrarYEnRango( 1, -1, 1.5 ) ) then
      begin
  //      aRec.SaturarYEnRango( 1, 0, 1 );
        aData[cntPuntosValidos] := aRec;
        Inc(cntPuntosValidos);
      end
      else
        aRec.Free;
    end;
    series.Free;
    setlength(aData, cntPuntosValidos);
   end;

  cuentasPorRango:= CuentaPorRango( ymin, ymax, aData, 5, 1 );
  dy:= (ymax - ymin)/length( cuentasPorRango );
  setlength( pesosPorRango, length( cuentasPorRango ) );
  for k:= 0 to high( cuentasPorRango ) do
  begin
    if cuentasPorRango[k] > 0 then
      pesosPorRango[k]:= 1/cuentasPorRango[k]
    else
      pesosPorRango[k]:= 0;
  end;
  setlength( cuentasPorRango, 0 );


  suma:= vsum( pesosPorRango );
  vmultr( pesosPorRango, 1/suma );

  pesosPorRango[ 0 ]:= 10/length( pesosPorRango );
  pesosPorRango[ high( pesosPorRango ) ]:= 10/length( pesosPorRango );

  suma:= vsum( pesosPorRango );
  vmultr( pesosPorRango, 1/suma );


  pesosPorRango:= nil;


  nx := aData[0].X.n;
  ny := aData[0].Y.n;

  if Cerebro = nil then
  begin
    // creamos un cerebro de dos capas la primera con 2 neuronas y la segunada con una sola neurona
    Cerebro := TCerebro.Create(nx, CapasDef, TiposSat, cbAgregarUnaLinEnCapasIntermedias.checked );
    randomize;
    randseed := 31;
    Cerebro.RandomInit(0.1);
    Cerebro.EscalarEntradas(aData);
    Cerebro.EscalarCapaSalida(aData);
//    Cerebro.SetMinSalida(0,0);
//    Cerebro.SetMaxSalida(0,1);
  end;

  momento:= StrToFloat( eMomento.Text );
  paso:= StrToFloat( ePasoIni.Text );

  parametros := TVectR.Create_Init(Cerebro.DimParametros);

  cntEvaluaciones := 0;
  fMejor := -1E20;

  Cerebro.GetParametros(parametros);

  e2_ant := 1e30;
  cnt_exitos := 0;
  cnt_fracasos := 0;

  grad := TVectR.Create_Init(Cerebro.DimParametros);
  grad.Ceros;
  verr := TVectR.Create_Init(ny);

//  EntrenarCerebro(Cerebro, aData, 10000, flgConvergio, cntIters, -1, -1);

  for k := 1 to 10000 do
  begin

    momento:= StrToFloat( eMomento.Text );
    prnd:=  StrToFloat( ePRND.Text );
    alfa_regularizacion:=  StrToFloat( eAlfa_Regularizacion.Text );

    if cbRandomKick.checked then
    begin
      randomize;
      Cerebro.RandomInit(0.1);
      Cerebro.EscalarEntradas(aData);
      Cerebro.EscalarCapaSalida(aData);
      cbRandomKick.Checked:= false;
    end;

    for j := 1 to 400 do
    begin
      e2 := EntrenarCerebro_EBP_minibatch(
        Cerebro, aData, paso,
        momento,
        alfa_regularizacion,
       //-1,
        min( 500, max( trunc(0.5 * length(aData)), 300 ) ),
        trunc( random *100000 ), prnd,
        1, pesosPorRango, ymin, dy );
    end;

    Plot( Image1, Cerebro, aData, k);
    application.ProcessMessages;

    if e2 < -1 then
      e2 := 2 * e2_ant;

    if e2 < e2_ant then
    begin
      Cerebro.GetParametros(parametros);
      cnt_fracasos := 0;
      Inc(cnt_exitos);
      if cnt_exitos > 3 then
      begin
        cnt_exitos := 0;
        paso := paso * GoldenRatio;
      end;
    end
    else
    begin
      //      Cerebro.SetParametros(parametros);
      cnt_exitos := 0;
      Inc(cnt_fracasos);
      if cnt_fracasos > 0 then
      begin
        cnt_fracasos := 0;
        paso := paso * invGoldenRatio;
      end;
    end;
    e2_ant := e2;

    Writeln(k, #9, e2, #9, paso);

    if abs( paso ) < 1e-12 then
      break;
  end;
  grad.Free;

  Cerebro.SetParametros(parametros);

  Cerebro.WriteToArchi('cerebro_DVLP.xlt');
  assignfile(sal, 'cerebro_ej05.xlt');
  rewrite(sal);

  writeln(sal, 'Parametros:', #9, parametros.serialize_data(#9));
  writeln(sal, 'bias', #9, 'ro');
  for k := 0 to Cerebro.CapaEntrada.NNeuronas - 1 do
  begin
    aNeurona := Cerebro.CapaEntrada.Neuronas[k] as TNeuronaEntrada;
    writeln(sal, aNeurona.bias, #9, aNeurona.ro);
  end;

  grad := TVectR.Create_Init(Cerebro.DimParametros);
  for kMuestra := 0 to High(aData) do
  begin
    if kMuestra = 4 then
      writeln('hola');
    aRec := aData[kMuestra];
    Cerebro.SetEntradas(aRec.X);
    Cerebro.BackPropagation_init;
    Cerebro.evaluar;

    Cerebro.calc_err2(verr, aRec.Y);
    Cerebro.BackPropagation_addMuestra(verr);
    for j := 1 to aRec.X.n do
      Write(sal, #9, aRec.X.e(j));
    for j := 1 to aRec.Y.n do
    begin
      ay1 := Cerebro.GetSalida( j-1 );
      Write(sal, #9, aRec.Y.e(j), #9, ay1, #9, verr.e(j));
    end;

    grad.Ceros;
    Cerebro.AcumGradParametros(grad);
    Write(sal, #9, #9, grad.serialize_data(#9));

    writeln(sal);
  end;
  closefile(sal);
  grad.Free;
  parametros.Free;
end;



procedure TForm1.btIncPasoClick(Sender: TObject);
begin
  ePaso.Text := FloatToStr(StrToFloat(epaso.Text) * 2);
end;



procedure CargueX(var crb: TCerebro; series: TSeriesDedatos; kPaso: integer);
var
  j: integer;
begin
  for j := 0 to series.NSeriesX - 1 do
    crb.SetEntrada(j, series.seriesX[j].pv[kPaso]);
end;

function sin_huecos(const X: TDAofNReal; umbral_filtro: NReal): boolean; overload;
var
  k: integer;
begin
  Result := True;
  for k := 0 to high(X) do
    if x[k] <= umbral_filtro then
    begin
      Result := False;
      break;
    end;
end;


function sin_huecos(const X: TCapaNeuronasEntrada; umbral_filtro: NReal): boolean;
  overload;
var
  k: integer;
begin
  Result := True;
  for k := 0 to X.NNeuronas - 1 do
    if x.Neuronas[k].salida <= umbral_filtro then
    begin
      Result := False;
      break;
    end;
end;


procedure encajone(var xmin, xmax: NReal; x: NReal);
begin
  if x < xmin then
    xmin := x
  else if x > xmax then
    xmax := x;
end;

procedure cruz(canvas: TCanvas; x, y, h: integer);
begin
  canvas.MoveTo(x - h, y);
  canvas.lineTo(x + h, y);
  canvas.MoveTo(x, y - h);
  canvas.LineTo(x, y + h);
end;

procedure Rombo(canvas: TCanvas; x, y, h: integer);
begin
  canvas.MoveTo(x, y - h);
  canvas.LineTo(x - h, y);
  canvas.LineTo(x, y + h);
  canvas.LineTo(x + h, y);
  canvas.LineTo(x, y - h);
end;


procedure PlotXY(Canvas: TCanvas; W, H: integer; x, y, z: TVectR; huecos: TVectBool);
var
  k: integer;
  xmin, xmax, ymin, ymax, zmin, zmax: NReal;
  mx, my: NReal;
  a: NReal;
  px, py: integer;
begin
  xmin := x.e(1);
  xmax := xmin;
  ymin := y.e(1);
  ymax := ymin;
  zmin := z.e(1);
  zmax := zmin;
  for k := 1 to huecos.N do
    if not huecos.e(k) then
    begin
      encajone(xmin, xmax, x.e(k));
      encajone(ymin, ymax, y.e(k));
      encajone(zmin, zmax, z.e(k));
    end;
  ymin := min(ymin, zmin);
  ymax := max(ymax, zmax);
  mx := W / (xmax - xmin);
  my := H / (ymax - ymin);

  Canvas.Brush.Color := CLWhite;
  Canvas.Rectangle(0, 0, W - 1, H - 1);

  for k := 1 to huecos.N do
    if not huecos.e(k) then
    begin
      px := trunc((x.e(k) - xmin) * mx);

      py := trunc(H - (y.e(k) - ymin) * my);
      canvas.Pen.Color := clBlue;
      cruz(canvas, px, py, 5);

      py := trunc(H - (z.e(k) - ymin) * my);
      canvas.Pen.Color := clRed;
      rombo(canvas, px, py, 5);
    end;

end;


procedure TForm1.btPerceptronSTEPClick(Sender: TObject);
var
  Z: TSeriesDeDatos;
  kSerie, kPaso: integer;
  nombreSerie: string;
  verosimilitud: NReal;
  i: integer;
  parametros_x: TVectR;
  acum: NReal;
  huecos: TVectBool;
begin

  parametros_x := parametros_mejor.clonar;

  NRetardos := StrToInt(eNRetardos.Text);
  umbral_filtro := StrToFloat(eUmbralFiltro.Text);

  huecos := TVectBool.Create_Init(series.NPuntos - nRetardos);
  cntEvaluaciones := 0;


  while (cntEvaluaciones < 1000000) do
  begin

  (*
    for i:= 0 to high( parametros_x ) do
      parametros_x[i]:= parametros_mejor[i];
    i:= trunc( length( parametros_mejor ) * random );
    parametros_x[i]:=  parametros_mejor[i] + ( 1 - 2 * random ) *StrToFloat( ePaso.Text );
    Perceptron.SetParametros( parametros_x );
    *)

    if cbLeerParametros.Checked then
      CargueParametrosPrueba
    else
    if cntEvaluaciones > 0 then
      Cerebro.RandomInit(StrToFloat(ePaso.Text));


    Z := TSeriesDeDatos.CreateVacia(series.dtPrimeraMuestra,
      series.PeriodoDeMuestreo_horas, series.NPuntos - nRetardos);

    for kSerie := 0 to series.NSeriesY - 1 do
    begin
      nombreSerie := series.nombresSeries[kSerie];
      Z.AddSerie(nombreSerie);
    end;

    for kPaso := 1 to NRetardos do
      CargueX(Cerebro, series, kPaso);

    for kPaso := NRetardos + 1 to series.NPuntos do
    begin
      CargueX(Cerebro, series, kPaso);
      if sin_huecos(Cerebro.Entrada_Capa0, umbral_filtro) then
      begin
        Cerebro.evaluar;
        for kSerie := 0 to Z.NSeries - 1 do
          Z.series[kSerie].pon_e(kPaso - NRetardos, Cerebro.GetSalida(kserie));
        huecos.pon_e(kPaso - NRetardos, False);
      end
      else
      begin
        for kSerie := 0 to Z.NSeries - 1 do
          Z.series[kSerie].pon_e(kPaso - NRetardos, umbral_filtro);
        huecos.pon_e(kPaso - NRetardos, True);
      end;
    end;

    // Medimos el error de pronóstico
    acum := 0;
    for kPaso := NRetardos + 1 to series.NPuntos do
      if not huecos.e(kPaso) then
        for kSerie := 0 to Z.NSeries - 1 do
          acum := acum + sqr(Z.series[kSerie].e(kPaso) -
            series.seriesY[kSerie].e(kPaso));


    verosimilitud := -acum / (Z.NSeries * series.NPuntos);
  {
  acum:= 0;
  for kSerie:= 0 to Z.NSeries-1 do
   acum:= acum + abs( z.series[kSerie].Promedio_filtrando( umbral_filtro ) );
  verosimilitud := MaxDiff_CDF_N_I(  z.series, huecos, 31, 100 );

  writeln( 'v: ', verosimilitud, ', acum: ', acum );
  verosimilitud:= - ( verosimilitud+ acum);
   }

{
  CalcCovars.Calc( Z.series );
  verosimilitud:= CalcCovars.Versimilitud_gaussiana( Z.series );
  }
    //  verosimilitud:= CalcCovars.Versimilitud_gaussianaNormal( Z.series );


    Inc(cntEvaluaciones);
    if cntEvaluaciones = 1 then
    begin
      Cerebro.GetParametros(parametros_mejor);
      fMejor := verosimilitud;
      if (Z.NSeries = 1) and (series.NseriesX = 1) then
        plotXY(PaintBox1.Canvas, PaintBox1.Width, PaintBox1.Height,
          series.seriesX[0], series.seriesY[0], Z.series[0], huecos);
    end
    else
    begin
      if verosimilitud > fMejor then
      begin
        Cerebro.GetParametros(parametros_mejor);
        fMejor := verosimilitud;
        if (Z.NSeries = 1) and (series.NseriesX = 1) then
          plotXY(PaintBox1.Canvas, PaintBox1.Width, PaintBox1.Height,
            series.seriesX[0], series.seriesY[0], Z.series[0], huecos);
      end
      else
        Cerebro.SetParametros(parametros_mejor);
      PrintParametrosPrueba;
    end;
    if cbGuardar.Checked then
    begin
      cbGuardar.Checked := False;
      Cerebro.WriteToArchi('cerebro.xlt');
      Z.WriteToArchi('series_Z.xlt');
    end;
    eVerosimilitud.Text := FloatToStr(fMejor);

    writeln(verosimilitud);
    Z.Free;

    Application.ProcessMessages;

  end;
end;



procedure TForm1.btCalcCovarsClick(Sender: TObject);
var
  k: integer;
begin
  for k := 0 to series.nombresSeries.Count - 1 do
    writeln(k, ': ', series.nombresSeries[k]);

  CalcCovars.Calc(series.get_series_cronActiva);
  CalcCovars.PrintToArchi('covars.xlt', series.nombresSeries);
end;

procedure TForm1.btLoadSeriesClick(Sender: TObject);
begin
  if series <> nil then
  begin
    series.Free;
    CalcCovars.Free;
  end;

  series := TSeriesDeDatos.CreateFromArchi(eArchi.Text);
  nRetardos := StrToInt(eNRetardos.Text);
  umbral_filtro := StrToFloat(eUmbralFiltro.Text);
  CalcCovars := TCalculadorCovars.Create(series.NSeries, nRetardos, umbral_filtro);

end;

procedure TForm1.btTest01Click(Sender: TObject);
var
  NPuntos, k: integer;
  x, y, z: TVectR;
  fg: Tf_ddp;
begin

  if series <> nil then
  begin
    series.Free;
    CalcCovars.Free;
  end;

  NPuntos := 100000;

  fg := Tf_ddp_GaussianaNormal.Create(nil, 31);
  // fg:= Tf_ddpUniformeRand3.Create(nil, 31);

  series := TSeriesDeDatos.CreateVacia(now, 1, NPuntos);
  x := TVectR.Create_Init(NPuntos);
  y := TVectR.Create_Init(NPuntos);
  z := TVectR.Create_Init(NPuntos);

  for k := 1 to series.NPuntos do
  begin
    x.pv[k] := fg.rnd;
    y.pv[k] := fg.rnd;
    z.pv[k] := fg.rnd;
    //    y.pv[k]:= 0.3 * x.pv[k] + fg.rnd;
    //    z.pv[k]:= 0.1 * y.pv[k] + 0.5* x.pv[k] + fg.rnd;
  end;

  series.AddSerie('x', x);
  series.AddSerie('y', y);
  series.AddSerie('z', z);

  fg.Free;

  nRetardos := StrToInt(eNRetardos.Text);
  umbral_filtro := StrToFloat(eUmbralFiltro.Text);
  CalcCovars := TCalculadorCovars.Create(series.NSeries, nRetardos, umbral_filtro);
end;

procedure TForm1.btVerosimilitudClick(Sender: TObject);
var
  verosimilitud: NReal;
begin
  verosimilitud := CalcCovars.Versimilitud_gaussiana(series.get_series_cronActiva);
  eVerosimilitud.Text := FloatToStr(verosimilitud);
end;

procedure TForm1.btWriteTiposDeDiaClick(Sender: TObject);
var
  f: textfile;
  dt, dtFin: TDateTime;
  //j: integer;

begin
  assignfile(f, 'tiposdedia_from2000.txt');
  rewrite(f);
  dt := IsoStrToDateTime('2019-01-01');
  //  dtFin := IsoStrToDateTime('2019-03-18');
  dtFin := now + 365 * 5;
  while dt < dtFin do
  begin
    (*
    for j:= 0 to 23 do
      writeln(f, DateTimeToIsoStr(dt+j/24.0), #9, Ord(TipoDeDiaUruguay(dt)));
      *)
    writeln(f, DateTimeToIsoStr(dt), #9, Ord(TipoDeDiaUruguay(dt)));

    dt := dt + 1.0;
  end;
  closefile(f);

end;

procedure TForm1.Button1Click(Sender: TObject);
var
  CapasDef: TDAofNInt;
  k: integer;
  aCapa: TCapaNeuronas;
  aNeurona: TNeurona;
  aData: TDAOfRecXCF;  // Datos de entrenamiento
  aRec: TRecXCF;

  kDato: integer;
  resEntrenamiento: NReal;
  paso: NReal;

  sTmin, sTMax, sP: TVectR;
  X, Xs: TVectR;
  nParams: integer;
  f, fs, f_mejor: NReal;

begin
  if Cerebro <> nil then
    Cerebro.Free;
  setlength(CapasDef, 2);
  CapasDef[0] := 2 * 2; // 2 para TMin y 2 para TMax
  CapasDef[1] := 1; // Para la potencia P, L o V

  Cerebro := TCerebro.Create(2, CapasDef, CTS_Tanh, CTS_Lineal);

  if parametros_mejor <> nil then
    parametros_mejor.Free;
  parametros_mejor := TVectR.Create_Init(Cerebro.DimParametros);


  if Series <> nil then
    Series.Free;
  Series := TSeriesDeDatos.CreateFromArchi(
    '/home/rchaer/SimSEE/SimSEE_src/src/trunk/rchlib/neuronales/dem_temp_habil_PLV_.xlt');

  setlength(aData, Series.NPuntos);
  // la serie 0 tiene los delta días entre muestras
  sTmin := series.series[1];
  sTmax := series.series[2];
  sP := series.series[3]; // 3  = Valle, 4 = Llano, 5 = Pico
  for kDato := 0 to high(aData) do
  begin
    aRec := TRecXCF.Create(2, 1);
    aRec.X.pon_e(1, sTmin.e(kDato + 1));
    aRec.X.pon_e(2, sTMax.e(kDato + 1));
    aRec.Y.pon_e(1, sP.e(kDato + 1));
    aData[kDato] := aRec;
  end;
  series.Free;
  series := nil;


  nParams := Cerebro.DimParametros;
  X := TVectR.Create_Init(nParams);
  Xs := TVectR.Create_Init(nParams);


  randomize;

  Cerebro.RandomInit(0.01 * random);
  paso := random;

  f_mejor := EntrenarCerebro_EBP(Cerebro, aData, paso, 0.7, 0.0001);

  while True do
  begin

    Cerebro.RandomInit(1000 * random);
    paso := random;

    Cerebro.GetParametros(X);
    f := EntrenarCerebro_EBP(Cerebro, aData, paso, 0.7, 0.0001);
    Cerebro.GetParametros(Xs);

    fs := EntrenarCerebro_EBP(Cerebro, aData, paso, 0.7, 0.0001);
    repeat
      if fs > f then
      begin
        paso := paso * 0.8;
        Cerebro.SetParametros(X);
        fs := EntrenarCerebro_EBP(Cerebro, aData, paso, 0.7, 0.0001);
      end
      else
      begin
        paso := paso * 1.01;
        vswap(X, Xs);
        f := fs;
        fs := EntrenarCerebro_EBP(Cerebro, aData, paso, 0.7, 0.0001);
      end;
    until paso < 1e-18;

    if f <= f_mejor then
    begin
      f_mejor := f;
      writeln('f_mejor: ', f: 12: 4);
      Cerebro.WriteToArchi('cerebro.xlt');

      CalcularYGuardar('xygrad.xlt', Cerebro, aData);

    end;

  end;
end;

procedure TForm1.btFrameTrayectoriasToSeriesClick(Sender: TObject);
var
  trayectorias_XCF: TTrayectorias;
  archi: string;
  puntos: TPuntosTrayectoria;
  aPunto: TPuntoTrayectoria;
  nSeries: integer;
  kSerie: integer;
  kPunto: integer;
  Frame: longint;
begin
  if OpenDialog1.Execute then
  begin
    archi := OpenDialog1.FileName;
    trayectorias_XCF := TTrayectorias.CreateFromArchi(archi);
    if series <> nil then
      series.Free;
    Frame := StrToInt(eFrame.Text);
    puntos := trayectorias_XCF.GetPuntosOfkPaso(Frame);
    aPunto := Puntos[0];
    nSeries := aPunto.X.dim;
    series := TSeriesDeDatos.CreateVacia(now, 1.0, length(puntos));
    for kSerie := 1 to nSeries do
      series.AddSerie('x' + IntToStr(kSerie), nil, ENTRADA);
    series.AddSerie('CF', nil, SALIDA);
    for kPunto := 0 to high(puntos) do
    begin
      aPunto := puntos[kPunto];
      for kSerie := 0 to nSeries - 1 do
        series.series[kSerie].pon_e(kPunto + 1, aPunto[kSerie + 1]);
      series.series[nSeries].pon_e(kPunto + 1, aPunto.CF);
    end;
    series.WriteToArchi('series_XCF' + eFrame.Text + '.xlt');
    series.Free;
    FreePuntosTrayectorias(Puntos);
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);

var
  archi: string;
  nx, ny: integer;

begin
  if aData = nil then
  begin
    if OpenDialog1.Execute then
      archi := OpenDialog1.FileName
    else
      exit;


    series := TSeriesDeDatos.CreateFromArchi(archi);
  end;

  PlotXY_simple( Image1, series, 0, 6 );
    nx := series.NSeriesX;
    ny := series.NSeriesY;
end;

procedure TForm1.btMixtureDensityNetworkClick(Sender: TObject);
var
  k, k1, k2, j: integer;
  aRec: TRecXCF;
  ax1, ax2, ay1: NReal;
  e2: NReal;
  parametros: TVectR;
  kMuestra: integer;
  sal: textfile;
  e2_ant: NReal;
  cnt_exitos, cnt_fracasos: integer;
  grad, verr: TVectR;
  archi: string;
  series: TSeriesDeDatos;
  ny, nx: integer;

  kCapa, kNeurona: integer;
  flgConvergio: boolean;
  cntIters: integer;
  cntPuntosValidos: integer;
  sdat: string;
  pal, capas: string;
  tipoSaturacionPenultimaCapa, tipoSaturacionSalida: TTipoSaturacion;
  cnt_Exitos_rnd: integer;
  momento, paso, prnd: NReal;
  suma, ymin, ymax, dy: NReal;
  alfa_Regularizacion: NReal;

  aMDN: TMixtureDensityNetwork;
  yPE: NReal;
  jRadiacion: integer;
begin
  jRadiacion:= StrToInt( eSerieRadiacion.Text );

  if aData = nil then
  begin
    if OpenDialog1.Execute then
      archi := OpenDialog1.FileName
    else
      exit;

    series := TSeriesDeDatos.CreateFromArchi(archi);
    nx := series.NSeriesX;
    ny := series.NSeriesY;

    setlength(aData, series.NPuntos);
    cntPuntosValidos := 0;
    for k := 1 to series.NPuntos do
    begin
      aRec := TRecXCF.Create(nx, ny);
      for j := 1 to nx do
        aRec.X.pon_e(j, series.seriesX[j - 1].e(k));
      for j := 1 to ny do
        aRec.Y.pon_e(j, series.seriesY[j - 1].e(k));
      if ( not aRec.filtrarMenorQue(-11111) )
        and ( ( not cbFiltrarRadiacion.Checked ) or ( aRec.X.e( jRadiacion) > 10 )) then
        // or  aRec.filtrarYEnRango( 1, -1, 1.5 ) ) then
      begin
        aRec.SaturarYEnRango( 1, 0, 1 );
        aData[cntPuntosValidos] := aRec;
        Inc(cntPuntosValidos);
      end
      else
        aRec.Free;
    end;
    series.Free;
    setlength(aData, cntPuntosValidos);
  end;


  nx := aData[0].X.n;
  ny := aData[0].Y.n;


  aMDN:= TMixtureDensityNetwork.Create( aData, 1, 4 );

  momento:= StrToFloat( eMomento.Text );
  paso:= StrToFloat( ePasoIni.Text );

  parametros := TVectR.Create_Init( aMDN.Cerebro.DimParametros );

  cntEvaluaciones := 0;
  fMejor := -1E20;

  aMDN.Cerebro.GetParametros(parametros);

  e2_ant := 1e30;
  cnt_exitos := 0;
  cnt_fracasos := 0;

  grad := TVectR.Create_Init( aMDN.Cerebro.DimParametros);
  grad.Ceros;
  verr := TVectR.Create_Init(ny);

//  EntrenarCerebro(Cerebro, aData, 10000, flgConvergio, cntIters, -1, -1);

  for k := 1 to 10000 do
  begin

    momento:= StrToFloat( eMomento.Text );
    prnd:=  StrToFloat( ePRND.Text );
    alfa_regularizacion:=  StrToFloat( eAlfa_Regularizacion.Text );

    if cbRandomKick.checked then
    begin
      randomize;
      aMDN.Cerebro.RandomInit(0.1);
      aMDN.Cerebro.EscalarEntradas(aData);
      cbRandomKick.Checked:= false;
    end;

    for j := 1 to 400 do
    begin
       e2:= aMDN.EntrenarCerebro_EBP_minibatch(
        grad,
        //aData,
        paso,
        momento,
        alfa_regularizacion,
        min( max( trunc(0.7 * length(aData)), 300 ), 500  ),
        trunc( random *100000 ), 0.0 );
    end;

    PlotMDN( Image1, aMDN, aData, k);
    application.ProcessMessages;

    if e2 < -1 then
      e2 := 2 * e2_ant;

    if e2 < e2_ant then
    begin
      aMDN.Cerebro.GetParametros(parametros);
      cnt_fracasos := 0;
      Inc(cnt_exitos);
      if cnt_exitos > 3 then
      begin
        cnt_exitos := 0;
        paso := paso * GoldenRatio;
      end;
    end
    else
    begin
      //      Cerebro.SetParametros(parametros);
      cnt_exitos := 0;
      Inc(cnt_fracasos);
      if cnt_fracasos > 0 then
      begin
        cnt_fracasos := 0;
        paso := paso * invGoldenRatio;
      end;
    end;
    e2_ant := e2;

    Writeln(k, #9, e2, #9, paso);

    if abs( paso ) < 1e-12 then
      break;
  end;
  grad.Free;

  aMDN.Cerebro.SetParametros(parametros);

  aMDN.Cerebro.WriteToArchi('MDN_Cerebro.xlt');
  assignfile(sal, 'MDN_eval.xlt');
  rewrite(sal);

  writeln( sal, 'X , ( y, yPE30, yPE50, yPE70 )*NSalidas ' );
  for kMuestra := 0 to High(aData) do
  begin
    aRec := aData[kMuestra];

    aMDN.SetEntradas( aRec.X );
    aMDN.evaluar;
    for j := 1 to aRec.X.n do
      Write(sal, #9, aRec.X.e(j));

    for j := 1 to aRec.Y.n do
    begin
      Write(sal, #9, aRec.Y.e(j) );

      yPE := aMDN.yOfPE( 0.3, j-1 );
      write( sal, #9, yPE );

      yPE := aMDN.yOfPE( 0.5, j-1 );
      write( sal, #9, yPE );

      yPE := aMDN.yOfPE( 0.7, j-1 );
      write( sal, #9, yPE );
    end;



    writeln(sal);
  end;
  closefile(sal);
  grad.Free;
  parametros.Free;
end;



procedure TForm1.FormCreate(Sender: TObject);
begin
  series := nil;
  CalcCovars := nil;
  Cerebro := nil;
end;



end.



