unit utrayectorias_xcdpcf;

interface

uses
  Classes, xmatdefs, matreal, matent, SysUtils,
  ufechas,
  utipos_xcf,
  uestados, uauxiliares;

type
  { TEstadoX }
  TEstadoX = class

    Xr: TVectR;
    Xd: TVectE;
    constructor Create(nr, nd: integer);
    constructor CreateUnserializeXLT(nr, nd: integer; var s: string);

    procedure UnserializeXLT(var s: string);
    function SerializeXLT: string;

    constructor CreateFromBinStream(f: TStream);
    procedure WriteToBinStream(f: TStream);

    procedure Set_xrxd(xr: TDAOfNReal; xd: TDAOfNInt);
    destructor Destroy; override;

    // copia el estado en v. El vector v se supone de dimensión correcta
    procedure CopyToVectR(v: TVectR);

    // result:= Xr.n + Xd.n
    function dim: integer;

    // i = 1 ... dim
    function getX( i: integer ): NReal;
    procedure setX( i: integer; X: NReal );
    property Items[i : Longint]: NReal Read GetX
                                      Write SetX; Default;
  end;

  TDAOfEstadoX = array of TEstadoX;

  { TPuntoTrayectoria ( X, lambdas, cdp, CF(Xs) ) }
  TPuntoTrayectoria = class
    X: TEstadoX;
    lambdas: TVectR;
    CF: NReal;
    cdp: NReal;
    valido:Boolean;
    constructor Create(nr, nd: integer);
    constructor CreateUnserializeXLT(nr, nd: integer; var s: string);

    procedure UnserializeXLT(var s: string);
    function SerializeXLT: string;

    constructor CreateFromBinStream(f: TStream);
    procedure WriteToBinStream(f: TStream);
    destructor Destroy; override;

    procedure anularPunto;
    procedure desanularPunto;

    function getX(i: integer): NReal;
    procedure SetX(i: integer; ax: NReal );
    property items[i: integer]: NReal read GetX write SetX; default;
  end;

  TPuntosTrayectoria = array of TPuntoTrayectoria;

  { TTrayectoria }

  TTrayectoria = class
    dtIni, dtFin, dtPaso: TDateTime; // dimensiones de El Tiempo
    nr, nd: integer; // dimensiones de El Estado

    puntos: TPuntosTrayectoria; // Puntos de la trayectoria
    cdp_acum, cf_final, cTotal: NReal;        //??? Implementar Write/Read y captura

    // Crear una trayectoria vacía
    constructor Create(dtIni, dtFin, dtPaso: TDateTime; nr, nd: integer);

    // Leer y escribir de un XLT
    constructor CreateFromXLT(var fxlt: textfile);
    procedure WriteToXLT(var fxlt: textfile);

    // Leer y escribir en un Stream binario
    constructor CreateFromBinStream(f: TStream);
    procedure WriteToBinStream(f: TStream);

    procedure set_XCF(kPaso: integer; xr: TDAOfNReal; xd: TDAOfNInt; CF: NReal);
    procedure set_cdp(kPaso: integer; cdp: NREal);
    procedure set_lambdas(kPaso: integer; lambdas: TVectR);
    procedure set_acumuladores(cdp_acum, cf_final, cTotal: NReal);

    destructor Destroy; override;

    // Realiza la actualización de CF de acuerdo con el vertor de pesos Forward
    // y el actualizador q.
    // El resultado es la distancia euclieda entre el CF antes y despues de actualizar
    // for k= 1 to nPasos
    //   cf_[h] = sum(j = k .. k+h-1; cdp * q^(h-1) ) + CF[k+h] * q^h
    //   NCF[k] = sum( h= 1.. nh; cf_[h] * pesosForward[h] )
    //   e2 = e2 + (CF[k]-NCF[k])^2
    function Recalcular(pesosForward: TVectR; qj: TVectR): NReal;

    function DimX: integer;
    function nPasosT: integer;


  end;


  TDAOfTrayectoria = array of TTrayectoria;


  { TTrayectorias }

  TTrayectorias = class

    Trayectorias: TDAOfTrayectoria;
    dtIni, dtFin, dtPaso: TDateTime;
    nTrayectorias, nr, nd: integer;

    // Crear una trayectoria vacía
    constructor Create(dtIni, dtFin, dtPaso: TDateTime; nTrayectorias, nr, nd: integer);

    function CreateClone:TTrayectorias;

    // Leer y escribir de un XLT
    constructor CreateFromXLT(var fxlt: textfile);
    procedure WriteToXLT(var fxlt: textfile);
    procedure WriteToXLTMultiArhi(archi:String);
    // Leer y escribir en un Stream binario
    constructor CreateFromBinStream(f: TStream);
    procedure WriteToBinStream(f: TStream);

    constructor CreateFromBinArchi(archi: string);
    constructor CreateFromXLTArchi(archi: string);

    // según la extensión .bin o .xlt llama al que corresponda de los anteriores
    constructor CreateFromArchi( archi: string );


    procedure WriteToBinArchi(archi: string);
    procedure WriteToXLTArchi(archi: string);
    // según la extesión .bin o .xlt llama al que corresponda de los anteriores
    procedure WriteToArchi( archi: string );

    destructor Destroy; override;

    procedure Capture_XCF(kPaso_Sim, kTrayectoria: integer; xr: TDAOfNReal;
      xd: TDAOfNInt; CF_AlInicioDelPaso: NReal);

    procedure Capture_cdp(kPaso_Sim, kTrayectoria: integer;
      costoDirectoDelpaso: NReal);

    procedure Capture_lambdas(kPaso_Sim, kTrayectoria: integer; lambdas: TVectR);

    procedure Capture_Acumuladores( kTrayectoria: integer; cdp_acum, cf_final, cTotal: NReal);

    // llama los recalcular de cada trayectoria.
    // El resultado es el cuadrado de la distancia euclida promedio entre los
    // valores CF antes y después de la actualización.
    function Recalcular(pesosForward: TVectR; q: NReal): NReal;


    function DimX: integer;
    function nPasosT: integer;

    // retorna un array con los puntos de todas las trayectorias correspondientes
    // al paso kPaso = 0 ... nPasosT-1.
    function GetPuntosOfkPaso( kPaso: integer ): TPuntosTrayectoria;

    // retorna un array de registros TRecXCF
    function GetDAOfRecXCFOfkPaso( kPaso: integer ): TDAOfRecXCF;
  end;



  {
  TNubeDePuntos_XEstado
  =======================

  Esta clase representa un conjunto de PUNTOS del Estado (Xr, Xd)
  que se utilizarán como estados iniciales de las trayectorias a simular.

  Cada Punto del Estado dará origen durante la simulación a NCronicas
  trayectorias.

  }

  TNubeDePuntos_XEstado = class
    NEstadosIniciales: integer;
    NContinuasAExplotar: integer;
    NDiscretasAExplotar: integer;

    // Nombre de las componentes del estado X
    nombresContinuas, nombresDiscretas: TDAofString;
    indicesContinuas, indicesDiscretas: TVectE;

    EstadosIniciales: TDAOfEstadoX;

    constructor CreateFromCF(CF: TAdminEstados; NEstrellas: integer);
    constructor CreateFromArchiXLT(archi_txt: string);
    procedure WriteToArchiXLT(archi: string);

    // Indexa las variables de estado según su posición dentro de CF.
    procedure indexarVariables(CF: TAdminEstados);

    // Carga el estado que corresponde.
    procedure cargarVectorDeEstadoEnCF(CF: TAdminEstados;
      kEstadoIniTrayectoria: integer);

    destructor Destroy; override;
  end;


// libera un array de PuntosTrayectorias.
procedure FreePuntosTrayectorias( var Puntos: TPuntosTrayectoria );


implementation

procedure FreePuntosTrayectorias( var Puntos: TPuntosTrayectoria);
var
  k: integer;

begin
  for k:= 0 to high( Puntos ) do
    Puntos[k].Free;
  setlength( Puntos, 0 );

end;

{ TTrayectorias }

constructor TTrayectorias.Create(dtIni, dtFin, dtPaso: TDateTime;
  nTrayectorias, nr, nd: integer);
var
  k: integer;
begin
  inherited Create;
  self.dtIni := dtIni;
  self.dtFin := dtFin;
  self.dtPaso := dtPaso;
  self.nTrayectorias := nTrayectorias;
  self.nr := nr;
  self.nd := nd;
  setlength(Trayectorias, nTrayectorias);
  for k := 0 to high(Trayectorias) do
    Trayectorias[k] := TTrayectoria.Create(dtIni, dtFin, dtPaso, nr, nd);
end;

function TTrayectorias.CreateClone: TTrayectorias;
var
  archiDummy:string;
  //f:TStream;
begin
  archiDummy:='archiDummyTrayectorias.xlt';
  //f:=TStream.Create;
  WriteToXLTArchi(archiDummy);
  //WriteToBinStream(f); WriteToBinArchi();
  //CreateFromBinStream(f);
  //Result:=TTrayectorias.CreateFromBinStream(f);
  //f.Free;
  Result:=TTrayectorias.CreateFromXLTArchi(archiDummy);
  DeleteFile(archiDummy);
end;

constructor TTrayectorias.CreateFromXLT(var fxlt: textfile);
var
  r, pal: string;
  k: integer;
begin
  inherited Create;
  readln(fxlt, r);
  NextStr(r);  //dtIni
  pal := getNextPalSep(r, #9);
  dtIni := IsoStrToDateTime(pal);
  readln(fxlt, r);
  NextStr(r);  //dtFin
  pal := getNextPalSep(r, #9);
  dtFin := IsoStrToDateTime(pal);
  readln(fxlt, r);
  NextStr(r);  //dtPaso
  dtPaso := NextFloat(r);
  readln(fxlt, r);
  NextStr(r);  //nTrayectorias
  nTrayectorias := NextInt(r, #9);
  readln(fxlt, r);
  NextStr(r);  //nContinuas
  nr := NextInt(r, #9);
  NextStr(r);  //nDiscretas
  nd := NextInt(r, #9);
  setlength(Trayectorias, nTrayectorias);
  for k := 0 to high(Trayectorias) do
    Trayectorias[k] := TTrayectoria.CreateFromXLT(fxlt);
end;

procedure TTrayectorias.WriteToXLT(var fxlt: textfile);
var
  k: integer;
begin
  Write(fxlt, 'dtIni');
  Writeln(fxlt, #9, DateTimeToIsoSTR(dtIni));
  Write(fxlt, 'dtFin');
  Writeln(fxlt, #9, DateTimeToIsoSTR(dtFin));
  Write(fxlt, 'dtPaso');
  Writeln(fxlt, #9, double(dtPaso));
  Write(fxlt, 'nTrayectorias');
  Writeln(fxlt, #9, nTrayectorias);
  Write(fxlt, 'NContinuas', #9);
  Write(fxlt, nr, #9);
  Write(fxlt, 'NDiscretas', #9);
  Write(fxlt, nd);
  writeln(fxlt);
  for k := 0 to high(Trayectorias) do
    Trayectorias[k].WriteToXLT(fxlt);
end;

procedure TTrayectorias.WriteToXLTMultiArhi(archi: String);
  var
  k: integer;
  ext, archi_k, path: String;
  fxlt: TextFile;
begin
  ext:= ExtractFileExt(archi);
  path:= ExtractFilePath(archi);
  archi:=ChangeFileExt(archi,'');

  for k := 0 to high(Trayectorias) do
  begin
    archi_k:= path + ExtractFileName(archi) + '_cronica_' + IntToStr(k) + ext;
    assignfile(fxlt, archi_k);
    rewrite(fxlt);
    Write(fxlt, 'dtIni');
    Writeln(fxlt, #9, DateTimeToIsoSTR(dtIni));
    Write(fxlt, 'dtFin');
    Writeln(fxlt, #9, DateTimeToIsoSTR(dtFin));
    Write(fxlt, 'dtPaso');
    Writeln(fxlt, #9, double(dtPaso));
    Write(fxlt, 'nTrayectorias');
    Writeln(fxlt, #9, nTrayectorias);
    Write(fxlt, 'NContinuas', #9);
    Write(fxlt, nr, #9);
    Write(fxlt, 'NDiscretas', #9);
    Write(fxlt, nd);
    writeln(fxlt);

    Trayectorias[k].WriteToXLT(fxlt);

    CloseFile(fxlt);
  end;
end;

constructor TTrayectorias.CreateFromBinStream(f: TStream);
var
  k: integer;

begin
  inherited Create;
  f.Read(dtini, sizeof(dtIni));
  f.Read(dtFin, sizeof(dtFin));
  f.Read(dtPaso, sizeof(dtPaso));
  f.Read(nTrayectorias, sizeof(nTrayectorias));
  f.Read(nr, sizeof(nr));
  f.Read(nd, sizeof(nd));
  setlength(Trayectorias, nTrayectorias);
  for k := 0 to high(Trayectorias) do
    Trayectorias[k] := TTrayectoria.CreateFromBinStream(f);
end;

procedure TTrayectorias.WriteToBinStream(f: TStream);
var
  k: integer;

begin
  f.Write(dtini, sizeof(dtIni));
  f.Write(dtFin, sizeof(dtFin));
  f.Write(dtPaso, sizeof(dtPaso));
  f.Write(nTrayectorias, sizeof(nTrayectorias));
  f.Write(nr, sizeof(nr));
  f.Write(nd, sizeof(nd));
  for k := 0 to high(Trayectorias) do
    Trayectorias[k].WriteToBinStream(f);
end;

constructor TTrayectorias.CreateFromBinArchi(archi: string);
var
  f: TFileStream;
begin
  f := TFileStream.Create(archi, fmOpenRead + fmShareDenyWrite);
  CreateFromBinStream(f);
  f.Free;
end;

constructor TTrayectorias.CreateFromXLTArchi(archi: string);
var
  f: textfile;
begin
  assignfile(f, archi);
  Reset(f);
  setSeparadoresGlobales;
  CreateFromXLT(f);
  closefile(f);
  setSeparadoresLocales;

end;

constructor TTrayectorias.CreateFromArchi(archi: string);
var
  ext: string;
begin
  ext:= ExtractFileExt( archi );
  if ext = '.xlt' then
    CreateFromXLTArchi( archi )
  else if ext = '.bin' then
    CreateFromBinArchi( archi )
  else
    Raise Exception.Create( 'La extensión: "'+ext+'" no es conocida como archivo de trayectorias.' );
end;

procedure TTrayectorias.WriteToBinArchi(archi: string);
var
  f: TFileStream;
begin
  f := TFileStream.Create(archi, fmCreate + fmShareExclusive);
  WriteToBinStream(f);
  f.Free;
end;

procedure TTrayectorias.WriteToXLTArchi(archi: string);
var
  f: textfile;
begin
   setSeparadoresGlobales;
  {$IFDEF CronicasEnArchsDistintos}
   WriteToXLTMultiArhi(archi);
  {$ELSE}
  assignfile(f, archi);
  rewrite(f);
  WriteToXLT(f);
  closefile(f);
  {$ENDIF}

  setSeparadoresLocales;
end;

procedure TTrayectorias.WriteToArchi(archi: string);
var
  ext: string;
begin
  ext:= ExtractFileExt( archi );
  if ext = '.xlt' then
    WriteToXLTArchi( archi )
  else if ext = '.bin' then
    WriteToBinArchi( archi )
  else
    Raise Exception.Create( 'La extensión: "'+ext+'" no es conocida como archivo de trayectorias.' );
end;

destructor TTrayectorias.Destroy;
var
  k: integer;
begin
  for k := 0 to high(Trayectorias) do
    Trayectorias[k].Free;
  inherited Destroy;
end;

procedure TTrayectorias.Capture_XCF(kPaso_Sim, kTrayectoria: integer;
  xr: TDAOfNReal; xd: TDAOfNInt; CF_AlInicioDelPaso: NReal);
begin
  Trayectorias[kTrayectoria - 1].Set_XCF(kPaso_sim, Xr, Xd, CF_AlInicioDelPaso);
end;

procedure TTrayectorias.Capture_cdp(kPaso_Sim, kTrayectoria: integer;
  costoDirectoDelpaso: NReal);
begin
  Trayectorias[kTrayectoria - 1].Set_cdp(kPaso_Sim, costoDirectoDelpaso);
end;

procedure TTrayectorias.Capture_lambdas(kPaso_Sim, kTrayectoria: integer;
  lambdas: TVectR);
begin
  Trayectorias[kTrayectoria - 1].Set_lambdas(kPaso_Sim, lambdas);
end;

procedure TTrayectorias.Capture_Acumuladores(kTrayectoria: integer; cdp_acum,
  cf_final, cTotal: NReal);
begin
  Trayectorias[kTrayectoria - 1].Set_acumuladores(cdp_acum, cf_final, cTotal);
end;

function TTrayectorias.Recalcular(pesosForward: TVectR; q: NReal): NReal;
var
  k, j: integer;
  qj: TVectR;
  e2: NReal;
  qn: NReal;
begin
  qj := TVectR.Create_Init(pesosForward.n + 1);
  qn := 1;
  for j := 1 to qj.n - 1 do
  begin
    qj.pon_e(j, qn);
    qn := qn * q;
  end;
  qj.pon_e(qj.n, qn);

  e2 := 0;
  for  k := 0 to high(Trayectorias) do
    e2 := e2 + Trayectorias[k].Recalcular(pesosForward, qj);
  qj.Free;
  Result := e2 / length(Trayectorias);
end;

function TTrayectorias.DimX: integer;
begin
  result:= Trayectorias[0].DimX;
end;

function TTrayectorias.nPasosT: integer;
begin
  result:= Trayectorias[0].nPasosT;
end;

function TTrayectorias.GetPuntosOfkPaso(kPaso: integer): TPuntosTrayectoria;
var
  res: TPuntosTrayectoria;
  k: integer;
begin
  setlength( res, nTrayectorias );
  for k:= 0 to high( res ) do
    res[k]:= Trayectorias[k].puntos[kPaso];
  result:= res;
end;

function TTrayectorias.GetDAOfRecXCFOfkPaso(kPaso: integer): TDAOfRecXCF;
var
  res: TDAOfRecXCF;
  xcf: TRecXCF;
  aTrayectoria: TTrayectoria;
  kCronica: integer;
  ix, ioffset: integer;
begin
  setlength( res, nTrayectorias );
  for kCronica := 0 to nTrayectorias - 1 do
  begin
    xcf := TRecXCF.Create( DimX, 1 );
    aTrayectoria := Trayectorias[kCronica];
    for ix := 0 to aTrayectoria.nr - 1 do
      xcf.X.pon_e(ix + 1, aTrayectoria.puntos[kPaso].X.Xr.e(ix + 1));
    ioffset := aTrayectoria.nr;
    for ix := 0 to aTrayectoria.nd - 1 do
      xcf.X.pon_e(ioffset + ix + 1, aTrayectoria.puntos[kPaso].X.Xd.e(ix + 1));
    xcf.Y.pon_e(1, aTrayectoria.puntos[kPaso].CF);
    res[kCronica]:= xcf;
  end;

  result:= res;
end;


{ TTrayectoria }

constructor TTrayectoria.Create(dtIni, dtFin, dtPaso: TDateTime; nr, nd: integer);
var
  nPuntos, k: integer;

begin
  Self.dtIni := dtIni;
  Self.dtFin := dtFin;
  Self.dtPaso := dtPaso;
  Self.NR := nr;
  self.ND := nd;
  nPuntos := trunc((dtFin - dtIni + dt_100ms) / dtPaso) + 1;
  setlength(puntos, nPuntos);
  for k := 0 to high(puntos) do
    puntos[k] := TPuntoTrayectoria.Create(nr, nd);
end;



constructor TTrayectoria.CreateFromXLT(var fxlt: textfile);
var
  NPuntos: integer;
  s: string;
  pal: string;
  k: integer;
begin
  readln(fxlt, s);
  NextStr(s);  //dtIni
  pal := getNextPalSep(s, #9);
  dtIni := IsoStrToDateTime(pal);
  NextStr(s);  //dtFin
  pal := getNextPalSep(s, #9);
  dtFin := IsoStrToDateTime(pal);
  readln(fxlt, s);
  NextStr(s); //nContinuas
  nr := NextInt(s, #9);
  NextStr(s); //nDiscretas
  nd := NextInt(s, #9);
  readln(fxlt, s);
  NextStr(s); //nPuntos
  NPuntos := NextInt(s, #9);
  dtPaso := (dtFin - dtINi) / NPuntos;
  setlength(puntos, nPuntos);

  readln(fxlt, s);
  if pos( 'Xr1', s ) = 0 then
  begin
   // NextStr(s); //valor_presente_del_cdp_[MUSD]:
    cdp_Acum:=NextFloat(s, #9)*1E6;
    readln(fxlt, s);
   // NextStr(s); //valor_presente_del_CF_al_final_de_la_crónica_[MUSD]:
    cf_final:=NextFloat(s, #9)*1E6;
    readln(fxlt, s);
   // NextStr(s); //valor_presente_del_Ctotal_(cdp+CF)_[MUSD]:
    cTotal:=NextFloat(s, #9)*1E6;
    readln(fxlt, s); // Xr1..  Xd1..  Lambda_r1..  Lambda_d1..  cdp  CF
  end
  else
  begin
    cdp_acum:= 0;
    cf_final:= 0;
    cTotal:= 0;
  end;

  for k := 0 to high(puntos) do
  begin
    readln(fxlt, s);
    puntos[k] := TPuntoTrayectoria.CreateUnserializeXLT(nr, nd, s);
  end;
end;

procedure TTrayectoria.WriteToXLT(var fxlt: textfile);
var
  k: integer;
begin
  writeln(fxlt, 'dtIni', #9, DateTimeToIsoSTR(self.dtINi, 2), #9, 'dtFin',
    #9, DateTimeToIsoSTR(self.dtFin));
  writeln(fxlt, 'nContinuas', #9, nr, #9, 'nDiscretas', #9, nd);
  Write(fxlt, 'nPuntos');
  writeln(fxlt, #9, length(puntos));

  Writeln(fxlt, FloatToStr(cdp_Acum/ 1E6),#9 , 'valor_presente_del_cdp_por_cronica[MUSD]:');
  Writeln(fxlt, FloatToStr(cf_final/ 1E6),#9, 'valor_presente_del_CF_al_final_de_la_cronica_[MUSD]:' );
  Writeln(fxlt, FloatToStr(cTotal/ 1E6),#9, 'valor_presente_del_Ctotal_(cdp+CF)_por_cronica[MUSD]:' );

  for k := 0 to nr - 1 do
    Write(fxlt, 'Xr' + IntToStr(k + 1), #9);
  for k := 0 to nd - 1 do
    Write(fxlt, 'Xd' + IntToStr(k + 1), #9);
  for k := 0 to nr - 1 do
    Write(fxlt, 'Lambda_r' + IntToStr(k + 1), #9);
  for k := 0 to nd - 1 do
    Write(fxlt, 'Lambda_d' + IntToStr(k + 1), #9);

  Write(fxlt, 'cdp', #9);
  Write(fxlt, 'CF', #9);
  writeln(fxlt);

  for k := 0 to high(puntos) do
    writeln(fxlt, Puntos[k].SerializeXLT);
end;



constructor TTrayectoria.CreateFromBinStream(f: TStream);
var
  NPuntos: integer;
  k: integer;
begin
  f.Read(dtIni, sizeof(dtINi));
  f.Read(dtFin, sizeof(dtFin));
  f.Read(nr, sizeOf(nr));
  f.Read(nd, sizeOf(nd));
  f.Read(NPuntos, sizeOf(NPuntos));

  f.Read(cdp_Acum, sizeOf(cdp_Acum));
  f.Read(cf_final, sizeOf(cf_final));
  f.Read(cTotal, sizeOf(cTotal));
  cdp_Acum:=cdp_Acum*1E6;
  cf_final:=cf_final*1E6;
  cTotal:=cTotal*1E6;

  dtPaso := (dtFin - dtIni) / NPuntos;
  setlength(puntos, nPuntos);
  for k := 0 to high(puntos) do
    puntos[k] := TPuntoTrayectoria.CreateFromBinStream(f);
end;

procedure TTrayectoria.WriteToBinStream(f: TStream);
var
  NPuntos: integer;
  k: integer;
  cdpAcum_aux, cf_final_aux, cTotal_aux: NReal;
begin
  f.Write(dtIni, sizeof(dtINi));
  f.Write(dtFin, sizeof(dtFin));
  f.Write(nr, sizeOf(nr));
  f.Write(nd, sizeOf(nd));
  NPuntos := length(puntos);
  f.Write(NPuntos, sizeOf(NPuntos));

  cdpAcum_aux:=cdp_Acum/1E6;
  cf_final_aux:=cf_final/1E6;
  cTotal_aux:=cTotal/1E6;

  f.Write(cdpAcum_aux, sizeOf(cdp_Acum));
  f.Write(cf_final_aux, sizeOf(cf_final));
  f.Write(cTotal_aux, sizeOf(cTotal));


  for k := 0 to high(puntos) do
    puntos[k].WriteToBinStream(f);
end;

procedure TTrayectoria.set_XCF(kPaso: integer; xr: TDAOfNReal;
  xd: TDAOfNInt; CF: NReal);
begin
  puntos[kPaso - 1].X.set_xrxd(xr, xd);
  puntos[kPaso - 1].CF := CF;
end;

procedure TTrayectoria.set_cdp(kPaso: integer; cdp: NREal);
begin
  puntos[kPaso - 1].cdp := cdp;
end;

procedure TTrayectoria.set_lambdas(kPaso: integer; lambdas: TVectR);
begin
  lambdas.CopyTo(puntos[kPaso - 1].lambdas);
end;

procedure TTrayectoria.set_acumuladores(cdp_acum, cf_final, cTotal: NReal);
begin
  self.cdp_acum:=cdp_acum;
  self.cf_final:=cf_final;
  self.cTotal:=cTotal;
end;

destructor TTrayectoria.Destroy;
var
  k: integer;
begin
  for k := 0 to high(puntos) do
    puntos[k].Free;
  setlength(puntos, 0);
  inherited Destroy;
end;


// Realiza la actualización de CF de acuerdo con el vertor de pesos Forward
// y el actualizador q.
// El resultado es la distancia euclieda entre el CF antes y despues de actualizar
// e2 = 0

// for k= 1 to nPasos
//   NCF[k] = 0
//   for h = 1 to nh
//     cf_[h] = sum(j = k .. k+h-1; cdp * q^(h-1) ) + CF[k+h] * q^h
//     NCF[k] = NFC[k] + cf_[h] * pesosForward[h]
//   e2 = e2 + (CF[k]-NCF[k])^2
function TTrayectoria.Recalcular(pesosForward: TVectR; qj: TVectR): NReal;
var
  k, j: integer;
  nPasosPuros: integer;
  ncf: NReal;
  e2: NReal;
  acdp: NReal;
  ncfj: NReal;
  acPesosPerdidos: NReal;
  jPesoHasta: integer;
  relPeso: NReal;
  pesoFwd: NReal;

begin
  nPasosPuros := length(puntos) - pesosForward.n;

  e2 := 0;

  for k := 0 to nPasosPuros - 1 do
  begin
    ncf := 0;
    acdp := 0;
    for j := 1 to pesosForward.n do
    begin
      acdp := acdp + qj.e(j) * Puntos[k + j - 1].cdp;
      pesoFwd := pesosForward.e(j);
      if pesoFwd > 0 then
      begin
        ncfj := acdp + qj.e(j + 1) * Puntos[k + j].CF;
        ncf := ncf + pesoFWD * ncfj;
      end;
    end;
    e2 := e2 + sqr(Puntos[k].CF - ncf);
    Puntos[k].CF := ncf;
  end;

  acPesosPerdidos := 0;
  for k := nPasosPuros to high(puntos) - 1 do
  begin
    jPesoHasta := pesosForward.n - (k - nPasosPuros + 1);
    acPesosPerdidos := acPesosPerdidos + pesosForward.e(jPesoHasta + 1);

    (*
    if acPesosPerdidos < (1 - AsumaCero) then
      relPeso := 1 / (1 - acPesosPerdidos)
    else
      relPeso := 0; // para prevenir que pongan algún peso nulo
      relPeso := acPesosPerdidos / jPesoHasta;
      *)
    acdp := 0;
    ncf := 0;

    for j := 1 to jPesoHasta - 1 do
    begin
      acdp := acdp + qj.e(j) * Puntos[k + j - 1].cdp;
      pesoFwd := pesosForward.e(j);
      if pesoFwd > 0 then
      begin
        ncfj := acdp + qj.e(j + 1) * Puntos[k + j].CF;
        ncf := ncf + pesoFWD * ncfj;
      end;
    end;

    // en elúltimo acumulo los pesos perdidos
    j := jPesoHasta;
    acdp := acdp + qj.e(j) * Puntos[k + j - 1].cdp;
    pesoFwd := pesosForward.e(j) + acPesosPerdidos;
    if pesoFwd > 0 then
    begin
      ncfj := acdp + qj.e(j + 1) * Puntos[k + j].CF;
      ncf := ncf + pesoFWD * ncfj;
    end;


    e2 := e2 + sqr(Puntos[k].CF - ncf);
    Puntos[k].CF := ncf;
  end;

  Result := e2 / (length(Puntos) - 1);
end;

function TTrayectoria.DimX: integer;
begin
  result:= nr+nd;
end;

function TTrayectoria.nPasosT: integer;
begin
  result:= length( Puntos );
end;

{ TPuntoTrayectoria }

constructor TPuntoTrayectoria.Create(nr, nd: integer);
begin
  inherited Create;
  X := TEstadoX.Create(nr, nd);
  self.cdp := 0;
  self.CF := 0;
  lambdas := TVectR.Create_Init(nd + nr);
  valido:=True;
end;

constructor TPuntoTrayectoria.CreateUnserializeXLT(nr, nd: integer; var s: string);
begin
  X := TEstadoX.Create(nr, nd);
  lambdas := TVectR.Create_Init(nd + nr);
  UnserializeXLT(s);
  valido:=True;
end;

procedure TPuntoTrayectoria.UnserializeXLT(var s: string);
begin
  X.UnserializeXLT(s);
  lambdas.unserialize_data(s, #9, #9);
  cdp := NextFloat(s, #9);
  CF := NextFloat(s, #9);
  valido:= NextBool(s);
end;

function TPuntoTrayectoria.SerializeXLT: string;
begin
  Result := X.SerializeXLT;
  if lambdas.n > 0 then
    Result := Result + #9 + lambdas.serialize_data(#9);
  Result := Result + #9 + FloatToStr(cdp) + #9 + FLoatToStr(CF);
  Result:= Result + #9 + BoolToStr(valido) ;
end;

constructor TPuntoTrayectoria.CreateFromBinStream(f: TStream);
begin
  X := TEstadoX.CreateFromBinStream(f);
  lambdas.Create_Load(f);
  f.Read(cdp, sizeOf(cdp));
  f.Read(CF, SizeOf(CF));
  f.Read(valido, SizeOf(valido));
end;

procedure TPuntoTrayectoria.WriteToBinStream(f: TStream);
begin
  X.WriteToBinStream(f);
  lambdas.Store(f);
  f.Write(cdp, sizeOf(cdp));
  f.Write(CF, SizeOf(CF));
  f.Write(valido, SizeOf(valido));
end;

destructor TPuntoTrayectoria.Destroy;
begin
  X.Free;
  lambdas.Free;
  inherited Destroy;
end;

procedure TPuntoTrayectoria.anularPunto;
begin
  valido:=False;
end;

procedure TPuntoTrayectoria.desanularPunto;
begin
  valido:=True;
end;

function TPuntoTrayectoria.getX(i: integer): NReal;
begin
  result:= X[i]
end;

procedure TPuntoTrayectoria.SetX(i: integer; ax: NReal);
begin
  X[i]:= ax;
end;


{ TEstadoX }

constructor TEstadoX.Create(nr, nd: integer);
begin
  inherited Create;
  Xr := TVectR.Create_Init(nr);
  Xd := TVectE.Create_Init(nd);
end;

constructor TEstadoX.CreateUnserializeXLT(nr, nd: integer; var s: string);
begin
  Create(nr, nd);
  UnserializeXLT(s);
end;

procedure TEstadoX.UnserializeXLT(var s: string);
begin
  Xr.unserialize_data(s, #9, #9);
  Xd.unserialize_data(s, #9, #9);
end;

function TEstadoX.SerializeXLT: string;
begin
  Result := '';
  if Xr.n > 0 then
  begin
    Result := Result + Xr.serialize_data(#9);
    if Xd.n > 0 then
      Result := Result + #9 + Xd.serialize_data(#9);
  end
  else
  if Xd.n > 0 then
    Result := Result + Xd.serialize_data(#9);
end;

constructor TEstadoX.CreateFromBinStream(f: TStream);
begin
  xr.Create_Load(f);
  xd.Create_Load(f);
end;

procedure TEstadoX.WriteToBinStream(f: TStream);
begin
  xr.Store(f);
  xd.Store(f);
end;

procedure TEstadoX.Set_xrxd(xr: TDAOfNReal; xd: TDAOfNInt);
var
  k: integer;
begin
  for k := 0 to high(xr) do
    self.xr.pon_e(k + 1, xr[k]);

  for k := 0 to high(xd) do
    self.xd.pon_e(k + 1, xd[k]);

end;


destructor TEstadoX.Destroy;
begin
  Xr.Free;
  Xd.Free;
  inherited Destroy;
end;

procedure TEstadoX.CopyToVectR(v: TVectR);
var
  k: integer;
  base: integer;
begin
  for k := 1 to xr.n do
    v.pon_e(k, xr.e(k));
  base := xr.n;
  for k := 1 to xd.n do
    v.pon_e(base + k, xd.e(k));

end;

function TEstadoX.dim: integer;
begin
  result:= Xr.n + Xd.n;
end;

function TEstadoX.getX(i: integer): NReal;
begin
  if i <= Xr.n then
    result:= Xr.e( i )
  else
    result:= Xd.e( i - Xr.n );

end;

procedure TEstadoX.setX(i: integer; x: NReal);
begin
  if i <= Xr.n then
    Xr.pon_e( i, x )
  else
    Xd.pon_e( i, round( x ) );
end;

{ TNubeDePuntos_XEstado }

constructor TNubeDePuntos_XEstado.CreateFromCF(CF: TAdminEstados; NEstrellas: integer);
var
  kVariable, kEstadoInicial: integer;

begin

  NEstadosIniciales := NEstrellas;

  NContinuasAExplotar := length(CF.xr_def);
  SetLength(nombresContinuas, NContinuasAExplotar);
  for kVariable := 0 to NcontinuasAExplotar - 1 do
    nombresContinuas[kVariable] := CF.xr_def[kVariable].nombre;

  NdiscretasAExplotar := length(CF.xd_def);
  SetLength(nombresDiscretas, NdiscretasAExplotar);
  for kVariable := 0 to NdiscretasAExplotar - 1 do
    nombresDiscretas[kVariable] := CF.xd_def[kVariable].nombre;

  setlength(EstadosIniciales, NEstadosIniciales);

  for kEstadoInicial := 1 to NEstadosIniciales do
    EstadosIniciales[kEstadoInicial - 1] :=
      TEstadoX.Create(NContinuasAExplotar, NDiscretasAExplotar);

end;

constructor TNubeDePuntos_XEstado.CreateFromArchiXLT(archi_txt: string);
var
  str: string;
  kEstadoInicial, kVariable: integer;
  archi: textfile;
  NFloat: NReal;

begin

  // Ejemplo de archivo

  {

    Cantidad_de_estados_inicales:  8
    Continuas_a_explotar:  2
    Nombres_continuas:  Bonete,Salto
    Discretas_a_explotar:  0
    Estrellas:
    -- de aquí en más un renglón por estrella serializada --
  }


  AssignFile(archi, archi_txt);
  reset(archi);

  ReadLn(archi, str);
  NextPal(str); //Cantidad_de_estados_inicales:
  NEstadosIniciales := StrToInt(NextPal(str));

  ReadLn(archi, str);
  NextPal(str); //Continuas_a_explotar:
  NContinuasAExplotar := StrToInt(NextPal(str));

  SetLength(nombresContinuas, NContinuasAExplotar);

  ReadLn(archi, str);
  NextPal(str); //Nombres_continuas:
  for kVariable := 0 to NcontinuasAExplotar - 1 do
    nombresContinuas[kVariable] := NextPal(str);

  ReadLn(archi, str);
  NextPal(str); //Discretas_a_explotar:
  NdiscretasAExplotar := StrToInt(NextPal(str));

  SetLength(nombresDiscretas, NdiscretasAExplotar);

  ReadLn(archi, str);
  NextPal(str); //Nombres_discretas:
  for kVariable := 0 to NdiscretasAExplotar - 1 do
    nombresDiscretas[kVariable] := NextPal(str);


  ReadLn(archi, str); //Estrellas:

  setlength(EstadosIniciales, NEstadosIniciales);

  for kEstadoInicial := 0 to high(EstadosIniciales) do
  begin
    readln(archi, str);
    EstadosIniciales[kEstadoInicial] :=
      TEstadoX.CreateUnserializeXLT(NContinuasAExplotar, NDiscretasAExplotar, str);
  end;

  CloseFile(archi);
end;


procedure TNubeDePuntos_XEstado.WriteToArchiXLT(archi: string);
var
  fsal: TextFile;
  kVariable, kEstado: integer;
begin
  AssignFile(fsal, archi);
  Rewrite(fsal);
  Writeln(fsal, 'Cantidad_de_estados_inicales:' + #9, NEstadosIniciales);

  writeln(fsal, 'Continuas_a_explotar:' + #9, NcontinuasAExplotar);

  Write(fsal, 'Nombres_continuas:' + #9);
  for kVariable := 0 to NcontinuasAExplotar - 1 do
    Write(fsal, nombresContinuas[kVariable] + #9);
  writeln(fsal);

  writeln(fsal, 'Discretas_a_explotar:' + #9, NDiscretasAExplotar);

  Write(fsal, 'Nombres_discretas:' + #9);
  for kVariable := 0 to NdiscretasAExplotar - 1 do
    Write(fsal, nombresDiscretas[kVariable] + #9);
  writeln(fsal);

  Writeln(fsal, 'Estrellas:' + #9);

  for kEstado := 0 to high(EstadosIniciales) do
    Writeln(fsal, EstadosIniciales[kEstado].SerializeXLT);

  CloseFile(fsal);
end;

procedure TNubeDePuntos_XEstado.indexarVariables(CF: TAdminEstados);
var
  kVariable: integer;

begin

  indicesContinuas := TVectE.Create_Init(NcontinuasAExplotar);
  indicesDiscretas := TVectE.Create_Init(NdiscretasAExplotar);

  // Guardo los indices
  for kVariable := 0 to NcontinuasAExplotar - 1 do
    indicesContinuas.pon_e(kVariable + 1, CF.indexOf_Continua(
      nombresContinuas[kVariable]));
  for kVariable := 0 to NdiscretasAExplotar - 1 do
    indicesDiscretas.pon_e(kVariable + 1, CF.indexOf_Discreta(
      nombresDiscretas[kVariable]));

end;

procedure TNubeDePuntos_XEstado.cargarVectorDeEstadoEnCF(CF: TAdminEstados;
  kEstadoIniTrayectoria: integer);
var
  kVariable: integer;
begin

  for kVariable := 1 to NcontinuasAExplotar do
    CF.xr[indicesContinuas.e(kVariable)] :=
      EstadosIniciales[kEstadoIniTrayectoria - 1].Xr.e(kVariable);

  for kVariable := 1 to NdiscretasAExplotar do
    CF.xd[indicesDiscretas.e(kVariable)] :=
      EstadosIniciales[kEstadoIniTrayectoria - 1].Xd.e(kVariable);
end;


destructor TNubeDePuntos_XEstado.Destroy;
var
  k: integer;
begin
  setlength(nombresContinuas, 0);
  setlength(nombresDiscretas, 0);
  if indicesContinuas <> nil then
    indicesContinuas.Free;
  if indicesDiscretas <> nil then
    indicesDiscretas.Free;
  if EstadosIniciales <> nil then
  begin
    for k := 0 to high(EstadosIniciales) do
      EstadosIniciales[k].Free;
    setlength(EstadosIniciales, 0);
  end;
  inherited Destroy;
end;


end.
