unit uoddface_individuos;
interface

uses
  Classes, SysUtils, ubtree, uoddface_table_nid;

  (**
  CREATE TABLE `ofe_individuos_235` (
      `nid` int(11) NOT NULL,
      `adn` varbinary(750) NOT NULL,
      `dtc` datetime NOT NULL,
      `dtu` datetime NOT NULL,
      `f_VE` double NOT NULL,
      `f_CVaR` double NOT NULL,
      `f_VaR` double NOT NULL,
      `f_Objetivo` double NOT NULL,
      `f_MIN` double NOT NULL,
      `f_MAX` double NOT NULL,
      `cnt_evaluaciones` int(11) NOT NULL,
      `detalle` blob NOT NULL, PRIMARY KEY (`nid`),
      UNIQUE KEY `iadn` (`adn`),
      KEY `ifo` (`f_Objetivo`)
   ) ENGINE=InnoDB DEFAULT CHARSET=latin1


   El mecanismo es se genera un ADN, se pregunta si existe, si no existe,
   si existe se obtien el NID para una evaluación adicional

   si no existe, se evalua con nid=-1 y num_eval = 1

   luego de evaluado, se comunica el resultado
   si nid < 0 primero se pide un nid y luego se intenta el INSERT  que puede fallar si alguién más ya cargó el mismo ADN.
   si nid > 0 con los resultados de la evaluación; se consulta todo la info del individuo y si el contador de evaluaciones + 1 corresponde
   con el cnt_evaluaciones local (nadie más cargó info del individuo) entonces recalcula los valores y hace el UPDATE.

   **)

 type


  { TOddface_Individuo }
  TOddface_Individuo = class( TRec_nid )
    nid: cardinal;
    adn: string;
    dtc: TDateTime;
    dtu: TDateTime;
    f_VE: double;
    f_CVaR: double;
    f_VaR: double;
    f_Objetivo: double;
    f_MIN: double;
    f_MAX: double;
    cnt_evaluaciones: integer;
    comentarios: string;
    constructor Create( nid: cardinal; adn: string );
    destructor destroy; override;
    procedure WriteToBin( f: TStream ); override;
    constructor LoadFromBin( f: TStream ); override;

    procedure CopyRec( a: TRec_key ); override;
  end;

  { T_fObjetivo_idx }
  T_fObjetivo_idx = class( TBTree )
    constructor Create;
    function compare(a, b: TItemBTree ): integer; override;
  end;

  { T_ADN_idx }
  T_ADN_idx = class( TBTree)
    constructor Create;
    function Compare( a, b: TItemBTree ): integer; override;
  end;


  { TOddFace_Individuos }
  TOddFace_Individuos = class( TTable_nid )
    nidProblema: integer;
    idx_fObjetivo: T_fObjetivo_idx;
    idx_ADN: T_ADN_idx;
    LongADN: cardinal;
    MaxPoblacion: integer;

    constructor Create( nidProblema: integer; LongADN: cardinal; MaxPoblacion: integer );
    constructor LoadFromBin( f: TStream );

    procedure ReadHeader( f: TStream ); override;
    procedure WriteHeader(f: TStream); override;
    procedure ReadFooter( f : TStream ); override;

    destructor destroy; override;
    procedure reindexar;

    // si lo logra insertar (no existía ni el nid ni el ADN) retorna TRUE
    // si ya existía el individuo, retorna FALSE y no lo inserta
    function AddRec( aIndividuo: TRec_key ): TNodoBtree; override;

    // busca el individuo y lo retorna, si no lo encuentra retorna NIL
    function locateByADN( adn: string ): TOddface_Individuo;

  end;


implementation

{ TOddface_Individuo }

constructor TOddface_Individuo.Create(nid: cardinal; adn: string );
begin
  inherited Create( nid );
  self.adn:= adn;
  dtc:= now();
  dtu:= dtc;
  f_VE:= 0;
  f_CVaR:= 0;
  f_VaR:= 0;
  f_Objetivo:= 0;
  f_MIN:= 0;
  f_MAX:= 0;
  cnt_evaluaciones:= 0;
  comentarios:= '';
end;

destructor TOddface_Individuo.destroy;
begin
  inherited destroy;
end;

procedure TOddface_Individuo.WriteToBin(f: TStream);
begin
  inherited WriteToBin( f );
  f.WriteAnsiString( adn );
  f.Write( dtc, sizeOf( dtc ) );
  f.Write( dtu, sizeOf( dtu ) );
  f.write( f_VE, sizeOf( f_VE ) );
  f.Write( f_CVaR, sizeOf( f_CVaR ) );
  f.Write( f_VaR, sizeOf( f_VaR ));
  f.write( f_Objetivo, sizeOf( f_Objetivo ) );
  f.write( f_MIN, sizeOF( f_Min ) );
  f.write( f_MAX, sizeOf( f_Max ) );
  f.write( cnt_evaluaciones, sizeOf( cnt_evaluaciones ) );
  f.WriteAnsiString( comentarios );
end;

constructor TOddface_Individuo.LoadFromBin(f: TStream);
begin
  inherited LoadFromBin( f );
  ADN:= f.ReadAnsiString;
  f.Read( dtc, sizeOf( dtc ) );
  f.Read( dtu, sizeOf( dtu ) );
  f.Read( f_VE, sizeOf( f_VE ) );
  f.Read( f_CVaR, sizeOf( f_CVaR ) );
  f.Read( f_VaR, sizeOf( f_VaR ));
  f.Read( f_Objetivo, sizeOf( f_Objetivo ) );
  f.Read( f_MIN, sizeOF( f_Min ) );
  f.Read( f_MAX, sizeOf( f_Max ) );
  f.Read( cnt_evaluaciones, sizeOf( cnt_evaluaciones ) );
  Comentarios:= f.ReadAnsiString;
end;

procedure TOddface_Individuo.CopyRec(a: TRec_key);
var
  ai: TOddface_Individuo;
begin
  inherited CopyRec( a );
  // Intencionalmente NO actualizamos el ADN.
  ai:= a as TOddface_Individuo;
  dtc:= ai.dtc;
  dtu:= ai.dtu;
  f_VE:= ai.f_VE;
  f_CVaR:= ai.f_CVaR;
  f_VaR:= ai.f_VaR;
  f_Objetivo:= ai.f_Objetivo;
  f_MIN:= ai.f_MIN;
  f_MAX:= ai.f_MAX;
  cnt_evaluaciones:= ai.cnt_evaluaciones;
  comentarios:= ai.comentarios;
end;

{ TOddFace_Individuos }

constructor TOddFace_Individuos.Create( nidProblema: integer; LongADN: cardinal;
  MaxPoblacion: integer);
begin
  inherited Create( TOddFace_Individuo );
  self.nidProblema:= nidProblema;
  self.LongADN:= LongADN;
  self.MaxPoblacion:= MaxPoblacion;
  idx_fObjetivo:= T_fObjetivo_idx.Create;
  idx_ADN:= T_ADN_idx.Create;
end;

constructor TOddFace_Individuos.LoadFromBin(f: TStream);
begin
  inherited LoadFromBin( f, TOddFace_Individuo );
end;




procedure TOddFace_Individuos.ReadHeader( f: TStream );
begin
  f.Read( nidProblema, sizeOF( nidProblema ) );
  f.Read( nextNid, sizeOf( nextNid ) );
  f.Read( LongADN, sizeOf( LongADN  ));
  f.Read( MaxPoblacion, sizeOf( MaxPoblacion ) );

  idx_fObjetivo:= T_fObjetivo_idx.Create;
  idx_ADN:= T_ADN_idx.Create;
end;

procedure TOddFace_Individuos.ReadFooter( f : TStream );
begin
  reindexar;
end;

procedure TOddFace_Individuos.WriteHeader(f: TStream);
begin
  f.Write( nidProblema, sizeOF( nidProblema ) );
  f.Write( nextNid, sizeOf( nextNid ) );
  f.Write( LongADN, sizeOf( LongADN  ));
  f.Write( MaxPoblacion, sizeOf( MaxPoblacion ) );
end;


destructor TOddFace_Individuos.destroy;
begin
  idx_fObjetivo.Free;
  idx_ADN.Free;
  inherited destroy;
end;

procedure TOddFace_Individuos.reindexar;
var
  aIndividuo: TOddface_Individuo;
  resCod: integer;
  cursor: TCursorBTree;
begin
  idx_ADN.clear;
  idx_fObjetivo.clear;
  cursor:= TCursorBTree.Create( recs );
  aIndividuo:= cursor.FirstItem;
  while not cursor.EndOfItems do
  begin
    idx_ADN.insert( aIndividuo, resCod );
    idx_fObjetivo.insert( aIndividuo, resCod );
    aIndividuo:= cursor.NextItem;
  end;
end;

function TOddFace_Individuos.AddRec(aIndividuo: TRec_key): TNodoBtree;
var
  resCod: integer;
  aNodo_Self, aNodo_idxADN: TNodoBTree;
begin
  aNodo_Self:= inherited AddRec( aIndividuo );

  if aNodo_Self = nil then
  begin     // este nid ya estaba
    result:= nil;
    exit;
  end;

  aNodo_idxADN:= idx_ADN.insert( aIndividuo, resCod );
  if aNodo_idxADN <> nil then
   result:= aNodo_Self
  else
  begin
    recs.Delete( aNodo_Self );
    result:= nil;
  end;

end;

function TOddFace_Individuos.locateByADN(adn: string): TOddface_Individuo;
var
  a: TOddface_Individuo;
  nodo: TNodoBtree;
begin
  a:= TOddface_Individuo.Create( 0, ADN );
  nodo:= idx_ADN.locate_key( a );
  a.free;
  if nodo <> nil then
    result:= nodo.item
  else
    result:= nil;
end;



{ T_ADN_idx }

constructor T_ADN_idx.Create;
begin
  inherited Create( false, nil );
end;

function T_ADN_idx.compare( a, b: TItemBTree ): integer;
var
  k: integer;
  apc, bpc: ^byte;
  res: integer;
begin
  apc:= @TOddface_Individuo(a).adn[1];
  bpc:= @TOddface_Individuo(b).adn[1];
  res:= 0;
  for k:= 1 to length( TOddface_Individuo(a).adn ) do
  begin
    if apc < bpc then
    begin
      res:= -1;
      break;
    end
    else if bpc > apc then
    begin
      res:= 1;
      break;
    end;
    inc( apc );
    inc( bpc );
  end;
  result:= res;
end;

{ T_fObjetivo_idx }

constructor T_fObjetivo_idx.Create;
begin
  inherited Create( true, nil );
end;

function T_fObjetivo_idx.compare( a, b: TItemBTree ): integer;
var
  dif: double;
begin
  dif := TOddface_Individuo(a).f_Objetivo - TOddface_Individuo(b).f_Objetivo;
  if dif < 0 then
    Result := -1
  else if dif = 0 then
    Result := 0
  else
    Result := 1;
end;

end.
