//la idea es probar el esquema de optimización genética guiada con el algoritmo de
//gradiente estimado promedio (gpa) con funciones conocidas, que se incluyen en
//los diferentes test cases.
//en general, los problemas son de optimización no lineal entera sin restricciones.
//M. Forets           @  iie    2011

unit optimizador;

{$mode objfpc}{$H+}

{$MACRO ON}
//define el plan particular
{$define uplan := uplanreductor}
{$define TPlan := TPlanReductor}
interface

uses
  Classes, SysUtils,
  xMatDefs,
  testCase1,
  uplan,
  dbPlanesPrueba,
  opt_genetico,
  opt_gpa;

var
   optimizando        :     Boolean;

//comienza la optimiación híbrida de la población
procedure             optimizarPoblacion;
//descarga todo el conjunto de planes al disco
procedure             DescargarPlanesADisco;
//agrega el plan p a la lista de planes en dbPlanesPrueba
procedure             NotificarResultado(p: TPlan);
//inicializa db y test case
procedure             Inicializar;
//inicializa la población en cierta cantidad de individuos
procedure             IniciarPoblacion;



implementation

procedure Inicializar;
begin
  SysUtils.DecimalSeparator := '.';

 { uplan.tamano_adn(testCase1.numeroDeVariables); //setea el tamano del vector x de la f a optimizar
  uplan.minimos_y_maximos_adn(0.0, 14.0);}

  dbPlanesPrueba.InicializarDb;

end;

procedure IniciarPoblacion;
var
  a: TPlan;
  narranque: integer;
begin
  SysUtils.DecimalSeparator := '.';
  narranque := 100;           //número de elementos de la población de partida
  writeln('IniciarPoblacion. . .');
  while Poblacion_Count < narranque do
  begin
    a := TPlan.CreateRND;
    writeln('   Naci, pertenezco a la raza = ', a.raza);

    a.Evaluar;
    NotificarResultado(a);
  end;
end;

procedure optimizarPoblacion;
var
   a, a_gpa                  : TPlan;
   NIndividuos               : Integer;
   cnt_loop                  : Integer;
   NGamma                    : Integer;
begin
  Inicializar;
  IniciarPoblacion;
  DescargarPlanesADisco;

  writeln('entrando al bucle de optimizacion. . .');
  optimizando := True;
  cnt_loop:=0;

  while optimizando do
  begin
    a := Aparear;
    a.Evaluar;
    NotificarResultado(a);
    //a.Free;
   (*  para debug
    NIndividuos := Poblacion_Count;
    writeln('^X^X^X^X^X^X^X');
    writeln('la cantidad de individuos es ahora: ', NIndividuos);
    if (NIndividuos = 20) then
    begin
            NIndividuos := Poblacion_Count;
       pp := dbPlanesPrueba.nextIdPlan();
       writeln('===========================================');
       writeln('HAY ',NIndividuos,' INDIVIDUOS Y LA LISTA DE PLANES ES :');
       writeln('===========================================');
       dbPlanesPrueba.imprimiListaDeIdPlanes;
       writeln('===========================================');
       writeln('===========================================');
    end;
    *)

     // UTILIZAR GRADIENTE PROMEDIO ALGORITMO
       (*
     NIndividuos:=Poblacion_Count;
     NGamma:=6;
     if (NIndividuos>2) and ((NIndividuos mod NGamma) = 0) then
     begin
       //dbPlanesPrueba.imprimiListaDeIdPlanes;
       a_gpa := nuevoPlanGPA(NIndividuos, NGamma, 0);
       a_gpa.Evaluar;
       NotificarResultado(a_gpa);

       //writeln('nacio un bebe promedio');

       //a_gpa.Free;
       //DescargarPlanesADisco;
       //dbPlanesPrueba.imprimiListaDeIdPlanes;
    end;

    *)
    if ((cnt_loop mod 100) = 99) then
    begin
       DescargarPlanesADisco;
       Writeln('descarga de plan')
    end;

    Inc(cnt_loop);
    writeln(a.idplan );
    optimizando := cnt_loop < 9000;
  end;
  writeln('optimización finalizada. . . descargando planes a disco. . .');
  DescargarPlanesADisco;
end;

procedure NotificarResultado(p: TPlan);
var
   id: Integer;
begin
  if (p.idPlan < 0) then
  begin
    //busco el plan por ADN, si ya existe, le asigno el idPlan del que ya existia
    if (Poblacion_Count > 0) then
    begin
         id:=dbPlanesPrueba.returnOneIdPlanByAdn(p.adn);
         if (id > -1) then
            p.idPlan := id;
    end;
  end;

  if (p.idPlan < 0) then //si el plan no existia
  begin
     p.idPlan := dbPlanesPrueba.nextIdPlan();

     dbPlanesPrueba.add(p);
  end
  else   //el plan ya existia...
  begin
       p.cnt_evaluaciones:=p.cnt_evaluaciones+1;
       dbPlanesPrueba.update(p.idPlan, p);
  end;

end;

procedure descargarPlanesADisco;
  var
  arrPlanes	:	TDAOfTPlanPrueba;
  plan		:	TPlan;
  fileOut	:	Text;
  i               :       Integer;
  f_x             :       NReal;
  NIndividuos     :       Integer;
  criterio        :       Integer;
begin
  NIndividuos := Poblacion_Count;
  setlength(arrPlanes, NIndividuos);

  criterio := 0;
  arrPlanes:=dbPlanesPrueba.returnOrdList(NIndividuos, criterio);

  //abrir archivo para guardar
  assign (fileOut, 'salida_optgen_gpa.txt');
  rewrite (fileOut);
  //writeln('////////////LISTA DE PLANES/////////////');
  for i := 0 to NIndividuos -1 do
  begin
  	plan	:=	arrPlanes[i];
          f_x := plan.fCriterio1;
          //writeln('idPlan = ', plan.idPlan, '  f_x = ', f_x, ' raza = ', plan.raza);
          //writeln(fileOut, plan.idPlan, '  ', plan.adn[0],'  ', plan.adn[1], '  ', f_x, '  ',plan.raza);
          writeln(fileOut, plan.idPlan, '  ',f_x,'  ',plan.raza);
  end;
  //writeln('//////////////////FIN LISTA DE PLANES//////////////////');
  //liberar
  setlength(arrPlanes, 0);

  close(fileOut);


end;

end.

