unit utractorcito;

{$mode delphi}

interface

uses
  Classes, SysUtils, usalasdejuego,
  uInicioYFinal,
  Math,
  uauxiliares, xmatdefs, matreal,
  umh_distribuidor_optsim, uConstantesSimSEE,
  uestados,
  ufechas,
  uAdministradorDeEstadosMultiPlano,
  ulearningcfmultiplano,
  utrayectorias_xcdpcf, uhiperplanos;





type

  { TTractorcito }

  TTractorcito = class
    archiSemilla,rundir:String;
    semillasIniSim: TDAofNInt;
    nSemillas:Integer;
    Trayectorias:TTrayectorias;
    //CF: TAdminEstadosMultiPlano;
    archiSala, archiEstrellas, CF_str, archiNew, archiOld,
      nombreArchiDistancias, subCarpetaResultadosCF, subCarpetaTrayectorias,
      subCarpetaResultadosXLS: string;

    constructor Create(archiSala,archiEstrellas,archiSemilla,
      CF_str:String);

    (*
     Lee el archivo de semillas "archiSemilla". Este archivo tiene que tener el formato que
     se muestra en el comentario anterior.
     Carga en seillasIniSin el array de semillas y en nSemillas la cantidad
     de semillas. (length( semillasIniSim) ).
    *)
    procedure CargarSemillas;

    // Genera un array de semillas en base a la SemillaMadre
    // iCronicaIni e iCronicaFin van de 1 .. NCronicas (globales de simulación)
    // En semillasIniSim se retorna el array de las semillas y en el resultado
    // de la función se retorna la cantidad de semillas (el largo del array).
    procedure GenSemillas(SemillaMadre, iCronicaIni, iCronicaFin: integer);

    procedure TratorcitoRunSimular(
      // Entradas
      sala: TSalaDeJuego; dtIni, dtFin: TDateTime;
      EstadosIniciales: TNubeDePuntos_XEstado; // Dejar EstadosIniciales como entrada
      CF, CF_Enganche: TAdminEstados;
      nHilos: integer; // -1 es nHilos = núcleos
      // Salida
      Trayectorias: TTrayectorias );

    function CrearCFMultiPlano_NULO(sala: TSalaDeJuego; dtIni, dtFin: TDateTime;
      nHiperplanos: integer): TAdminEstadosMultiPlano;

    procedure TratorcitoRunOptimizar(sala: TSalaDeJuego; dtIni, dtFin: TDateTime;
      EstadosIniciales: TNubeDePuntos_XEstado; CF, CF_Enganche: TAdminEstados;
  nHilos: integer; Trayectorias: TTrayectorias);


    procedure getHiperplanos(kIteracion: Integer; CF: TAdminEstadosMultiPlano);

    destructor Destroy;

  end;

  // Limpia carpeta que tenga solo archivos adentro (no subcarpetas)
  procedure limpiarCarpeta(carpeta: string);

  // lisa y llanamente calcula (a1-a2)^2 para todos los elementos y suma todo eso
  function getDistanciaEntreConjuntosDeHiperplanos(archiConjunto1,
    archiConjunto2: string): NReal;





implementation

procedure limpiarCarpeta(carpeta: string);
var
  xmascara: string;
  Err: integer;
  FileSearch: TSearchRec;
begin
  xmascara := '*.*';
  Err := FindFirst(carpeta + xmascara, faAnyFile, FileSearch);
  try
    while (Err = 0) do
    begin
      if (FileSearch.Name <> '.') and (FileSearch.Name <> '..') then
        SysUtils.DeleteFile(carpeta + FileSearch.Name);
      Err := FindNext(FileSearch);
    end;
  finally
    SysUtils.FindClose(FileSearch);
  end;
end;

function getDistanciaEntreConjuntosDeHiperplanos(archiConjunto1,
  archiConjunto2: string): NReal;
var
  conjunto1, conjunto2: TAdminEstadosMultiPlano;
  kFecha, NFechas, kHiperplano: integer;
  distancia2: NReal;
  cnj1, cnj2: TConjuntoDeHiperplanos;
  hp1, hp2: THiperplano;
  k, NHiperplanosPorFecha1, NHiperplanosPorFecha2: integer;

begin

  conjunto1 := TAdminEstadosMultiPlano.CreateLoadCFMPFromArchi(archiConjunto1);
  conjunto2 := TAdminEstadosMultiPlano.CreateLoadCFMPFromArchi(archiConjunto2);

  NFechas := conjunto1.nPuntosT;
  NHiperplanosPorFecha1 :=Length(conjunto1.conjuntosDeHiperPlanos[1].hiperPlanos); //conjunto1.conjuntosDeHiperPlanos[0].NHiperplanos;
  NHiperplanosPorFecha2 :=Length(conjunto2.conjuntosDeHiperPlanos[1].hiperPlanos);

  if ((NFechas <> conjunto2.nPuntosT)
    or (NHiperplanosPorFecha1 <> NHiperplanosPorFecha2)
    or (conjunto1.nVarsContinuas <> conjunto2.nVarsContinuas )
    or (conjunto1.nVarsDiscretas <> conjunto2.nVarsDiscretas )
    ) then
  begin
    Result := 1e39;
    exit;
  end;

  distancia2 := 0;

  for kFecha := 1 to NFechas  do
  begin
    cnj1:= conjunto1.conjuntosDeHiperPlanos[kFecha];
    cnj2:= conjunto2.conjuntosDeHiperPlanos[kFecha];
    for kHiperplano := 0 to NHiperplanosPorFecha1 - 1 do
    begin
      hp1:= cnj1.hiperPlanos[kHiperplano];
      hp2:= cnj2.hiperPlanos[kHiperplano];
      distancia2 := distancia2 + DistEuclidea2(hp1, hp2);
    end;
  end;

  conjunto2.Free;
  conjunto1.Free;

  Result := sqrt(distancia2);
end;


{ ArchiSemilla:
 NSemillas: 3
 Semillas: 31, 41, 61
}


{ TTractorcito }

constructor TTractorcito.Create(archiSala, archiEstrellas, archiSemilla,
  CF_str: String);
begin
  self.archiSala := archiSala;
  self.archiEstrellas:=archiEstrellas;
  self.archiSemilla:=archiSemilla;
  self.CF_str:=CF_str;
end;

procedure TTractorcito.CargarSemillas;
var
  f: TextFile;
  s: string;
  kSemilla: integer;
begin
  AssignFile(f, archiSemilla);
  Reset(f);

  ReadLn(f, s); //NSemillas: 3
  NextPal(s); //NSemillas
  nSemillas := StrToInt(NextPal(s));

  SetLength(semillasIniSim, nSemillas);

  ReadLn(f, s); //Semillas: 31, 41, 61
  NextPal(s); //Semillas
  for kSemilla := 0 to nSemillas - 1 do
  begin
    semillasIniSim[kSemilla] := StrToInt(NextPal(s));
  end;

end;

procedure TTractorcito.GenSemillas(SemillaMadre, iCronicaIni,
  iCronicaFin: integer);
var
  k: integer;
begin
  NSemillas := iCronicaFin - iCronicaIni + 1;
  setlength(semillasIniSim, NSemillas);
  for k := iCronicaIni to iCronicaFin do
    semillasIniSim[k - iCronicaIni] := SemillaMadre + k;
end;


procedure TTractorcito.TratorcitoRunSimular(sala: TSalaDeJuego; dtIni,
  dtFin: TDateTime; EstadosIniciales: TNubeDePuntos_XEstado; CF,
  CF_Enganche: TAdminEstados; nHilos: integer; Trayectorias: TTrayectorias);
var
  nTareas: integer;
  GestorMT: TGestorSalaMH;

begin
  sala.globs.CF_Enganche := CF_Enganche;

  if dtIni <> 1 then
  begin
    sala.globs.fechaIniSim.dt := dtIni;
    sala.globs.fechaFinSim.dt := dtFin;
    sala.globs.fechaIniOpt.dt := dtIni;
    sala.globs.fechaFinOpt.dt := dtFin;
  end;

  sala.globs.semillasIniSim := semillasIniSim;
  sala.globs.NCronicasSim_global_ := length(semillasIniSim);
  sala.globs.nubeDePuntos_XEstado := EstadosIniciales;
  if EstadosIniciales <> nil then
  begin
    sala.globs.NEstadosIniciales_global :=
      sala.globs.nubeDePuntos_XEstado.NEstadosIniciales;
    sala.globs.NTrayectorias_global :=
      sala.globs.NEstadosIniciales_global * sala.globs.NCronicasSim_global_;
  end
  else
  begin
    sala.globs.NEstadosIniciales_global := 1;
    sala.globs.NTrayectorias_global := sala.globs.NCronicasSim_global_;
  end;

  sala.globs.CF := CF;
  sala.globs.CF_Enganche := CF_Enganche;

  // revisar, me parece inecesario
  if EstadosIniciales <> nil then
    sala.globs.nubeDePuntos_XEstado.indexarVariables(sala.globs.CF);

  sala.globs.Trayectorias := Trayectorias;


  {$IFDEF WINDOWS}
  LimpiarCarpeta(sala.dirResultadosCorrida);
  {$ELSE}
  LimpiarCarpeta(sala.dirResultadosCorrida);
  {$ENDIF}

  chdir(sala.dirSala);
  if nHilos <> 0 then
  begin
    nTareas := nHilos;
    GestorMT := TGestorSalaMH.Create(sala);
    GestorMT.nHilosForzados := nHilos;
    GestorMT.nTareasForzadas := nTareas;
    GestorMT.sim_SimularMultiCore(nHilos);
    GestorMT.Free;
  end
  else
    sala.Simular(0, True);

  // desconecto los CFs de la sala para que cuando se hga Free de la sala
  // no los mate
  sala.globs.CF := nil;
  sala.globs.CF_Enganche := nil;

end;

function TTractorcito.CrearCFMultiPlano_NULO(sala: TSalaDeJuego; dtIni, dtFin: TDateTime;
  nHiperplanos: integer): TAdminEstadosMultiPlano;
var
  CF: TAdminEstadosMultiPlano;
  nPasosT: integer;
  fechaIni, fechaFin: TFecha;
begin
  sala.PrepararMemoriaYListados(True);
  sala.PrepararActualizadorFichasLPD(True);
  sala.optx_nvxs;
  if dtIni <= 0 then
    dtIni := sala.globs.fechaIniSim.dt;
  if dtFin <= 0 then
    dtFin := sala.globs.fechaFinSim.dt;

  fechaIni := TFecha.Create_Dt(dtIni);
  fechaFin := TFecha.Create_Dt(dtFin);
  nPasosT := trunc((dtFin - dtIni) * 24.0 / sala.globs.HorasDelPaso + 0.9);
  CF := TAdminEstadosMultiPlano.Create(sala.ivar_xr, sala.ivar_xd, nPasosT);
  CF.nHiperplanosPorPasoT := nHiperplanos;
  CF.CrearElEspacioTiempo(fechaIni, FechaFin, sala.globs.HorasDelPaso, nil, False, sala.globs.fActPaso );
  fechaIni.Free;
  fechaFin.Free;
  sala.RegistrarVariablesDeEstado(CF);
  Result := CF;
end;

procedure TTractorcito.TratorcitoRunOptimizar(sala: TSalaDeJuego; dtIni, dtFin: TDateTime;
  EstadosIniciales: TNubeDePuntos_XEstado;
  CF, CF_Enganche: TAdminEstados; nHilos: integer; Trayectorias: TTrayectorias);
var
  pesosForward: TVectR;
  e2,distanciaEntreArchivos, q, tolerancia: NReal;
  contador, kIteracion: integer;
  tam0, tamCNT: cardinal;
  maxContador:integer;
  salir: Boolean;


begin
  q := power(1.0 / 1.1, (7.0 / 365.0));
  pesosForward := TVectR.Create_init(1);
  pesosForward.pon_e(1, 1.0);

  tolerancia:=0.1;
  distanciaEntreArchivos:=1e30;
  contador := 0;
  maxContador := 10;
  salir := False;
  kIteracion := 0;

  {$IFDEF CHEQUEOMEM}
  tam0 := GetHeapStatus.TotalAllocated;
  {$ENDIF}

  repeat


    CF.WriteToArchi(subCarpetaResultadosCF + 'CF_'+IntToStr(kIteracion)+'.xlt' );
    Trayectorias.WriteToXLTArchi( subCarpetaTrayectorias + 'trys_'+IntToStr(kIteracion)+'.xlt');

    Inc(kIteracion);

    TratorcitoRunSimular(sala, dtIni, dtFin, EstadosIniciales,
      CF, CF_Enganche, nHilos, Trayectorias);

    if archiOld <> '' then
      distanciaEntreArchivos :=
        getDistanciaEntreConjuntosDeHiperplanos( archiNew, archiOld ); // ojo que es absoluta
    WriteLn('Distancia entre Archivos: ', distanciaEntreArchivos);

    WriteLn(nombreArchiDistancias, distanciaEntreArchivos);
      // Sale si la distancia es menor a la tolerancia durante 5 iteraciones consecutivas
    if distanciaEntreArchivos > tolerancia then
      contador := 0
    else
      Inc(contador);
    if contador >= maxContador then
      salir := True;

    e2:= Trayectorias.Recalcular( pesosForward, q  );

    getHiperplanos(kIteracion, CF as TAdminEstadosMultiPlano);

    writeln('e2: ', e2);

    AjusteCFMultiplanos_1PLano_( CF as TAdminEstadosMultiPlano, Trayectorias, 1 );

    {$IFDEF CHEQUEOMEM}
    tamCNT := GetHeapStatus.TotalAllocated;
    writeln('CNT: ', cnt, ' TotalAllocated: ', tamCNT, ' TAM-0: ', tamCNT - Tam0);
    {$ENDIF}

  until salir;

  pesosForward.Free;
end;

procedure TTractorcito.getHiperplanos(kIteracion: Integer;CF:TAdminEstadosMultiPlano);
var
  learningRate: NReal;
  ext: String;
  CoeficientesHiperplanosMat: TDAofMatR;
  kPaso, NPasos: Integer;
begin
  learningRate:=1; /// ver que poner acaaaaa
  AjusteCFMultiplanos_1Plano_(CF, Trayectorias,learningRate);

  //Renombrar archivos de CF para la proxima iteración y guarda el viejo
  ext := ExtractFileExt(CF.archiCFMP);

  archiOld := ChangeFileExt(CF.archiCFMP, '');

  archiOld := ExtractFileName(archiOld);

  // Para calcular la distancia entre los conjuntos después
  archiNew := subCarpetaResultadosCF + archiOld + '_' + IntToStr(kIteracion) + ext;

  if kIteracion > 0 then
    archiOld := subCarpetaResultadosCF + archiOld + '_' +
      IntToStr(kIteracion - 1) + ext
  else
    archiOld := ''; // esto es para no calcularla al principio

  // Guarda el archivo viejo
  RenameFile(CF.archiCFMP, archiNew);


  // Escribe el CF nuevo en C:\basura\archivosTractorcito\CF_pruebas.txt
  CF.WriteToArchi(CF.archiCFMP);


  NPasos:=length(CoeficientesHiperplanosMat);
  for kPaso:=0 to NPasos - 1 do
    CoeficientesHiperplanosMat[kPaso].Free;
  SetLength(CoeficientesHiperplanosMat,0);

end;









destructor TTractorcito.Destroy;
begin

end;

end.

