unit uAdministradorDeEstadosMultiPlano;
{$mode delphi}

interface

uses
  Classes, SysUtils, uEstados, uauxiliares, matreal,
  ucosa, ufechas,
  xmatdefs, MatEnt, uodt_types, uhiperplanos;

const
  //  ARCHI_CFMP = 'C:\basura\CFMP\CF_pruebas.txt';
  VERSION_ARCHI_HIPERPLANOS = '1';

type

  { TAdminEstadosMultiPlano }

  TAdminEstadosMultiPlano = class(TAdminEstados)
    // Información del manto CF(X) en base a hiperplanos por paso
    conjuntosDeHiperPlanos: TDAOfConjuntosDeHiperplanos; // Va indexado de 1 a N
    nHiperplanosPorPasoT: integer;

    // Auxiliar, ordinal del hiperplano de mayor valor en la última llamada a evaluar el costo
    kHiperplanoMayorValor: integer;

    NombresVariables: array of string;
    versionArchi: integer;

    archiCFMP: string;
    kHiperPlanosFromDts: TVectE;

    (*
 Información del Cursor Temporal
    dtIniSala, dtFinSala, dtPasoSala:TDateTime;
    nPuntosSala:integer;
      *)

    constructor Create(nVarsContinuas, nVarsDiscretas, nPasosT,
      nHiperPlanosPorPasoT: integer);

    procedure CrearElEspacioTiempo(fechaIni, fechaFin: TFecha;
      horasDelPaso: NReal; const costoFuturo: pointer; deterministico: boolean;
      fActPaso: NReal); override;

    (*
    class function CreateLoadCFMPFromArchi(const archi:string): TAdminEstadosMultiPlano;

    class function CreateReadFromArchi( archi: string ): TAdminEstadosMultiPlano;
      *)
    function costoContinuo(kPuntoT: integer): NReal; override;
    function deltaCosto_vxr_continuo(irx: integer; kpuntoT: integer;
      delta_xr: NReal): NReal; override;

    function getDtFromKpunto(kPunto: integer): TDateTime;
    function getHiperplanosFromDT(dt: TDateTime): TConjuntoDeHiperplanos;
    function getHiperplanosFromkPunto(kPunto: integer): TConjuntoDeHiperplanos;
    function evaluarHiperplano(hiperplano: THiperplano; estadoR: TDAOfNReal;
      estadoD: TDAOfNInt): NReal;

    // crea un conjunto con un solo hiperplano NULO
    function hiperplanosNulos: TConjuntoDeHiperplanos;

    procedure devxr_continuo(irx: integer; kpuntoT: integer;
      out dCdx_Inc, dCdx_Dec: NReal; out resCod: integer; out xrpos: NReal); override;


    // En principio activa el hiperplano de mayor costo correspondiente al estado
    // actual en kHiperplanoDeMayorCosto
    procedure ActualizarEstadoGlobal(kPaso: integer); override;
    function getkHiperplanosFromDT(dt: TDateTime): integer;



    // carga un CF desde la posición actual del archivo f  (formato binario)
    procedure ReadCuerpoFromBin(f: TStream); override;
    procedure ReadCuerpoFromXLT(f: TStream); override;

    // guarda CF desde la posición actual del archivo f (formato binario)
    procedure WriteCuerpoToBin(f: TStream; flg_compress: integer = -1); override;
    procedure WriteCuerpoToXLT(f: TStream); override;


    {$IFDEF _aprolin_}
    procedure WriteToFileAprolin(archi: string; coeficientes: TDAofMatR;
      hiperplanosPorPaso: integer);

    procedure WriteEncabHiperplanos(var fsal: TextFile; dt: TDateTime;
      NHiperplanos: integer);
    procedure WriteHiperplanos(var fsal: TextFile; CF_X0: NReal; strGrad: string);
    {$ENDIF}

    destructor Destroy; override;
    procedure FreeParasito; override;

    function CreateParasito: TAdminEstados; override;

    procedure ClonarInfoadParasito(res: TAdminEstados); override;


    function Primer_kPuntoT: integer; override;
    function Ultimo_kPuntoT: integer; override;

  end;


procedure AlInicio;
procedure AlFinal;


implementation

procedure AlInicio;
begin
  RegistrarClase_AdminEstados(TAdminEstadosMultiPlano);
end;

procedure AlFinal;
begin

end;

{ TAdminEstadosMultiPlano }

constructor TAdminEstadosMultiPlano.Create(nVarsContinuas, nVarsDiscretas,
  nPasosT, nHiperPlanosPorPasoT: integer);
begin
  inherited Create(nVarsContinuas, nVarsDiscretas, nPasosT);
  self.nHiperplanosPorPasoT := nHiperplanosPorPasoT;
  conjuntosDeHiperPlanos := nil;
end;

procedure TAdminEstadosMultiPlano.CrearElEspacioTiempo(
  fechaIni, fechaFin: TFecha;
  horasDelPaso: NReal; const costoFuturo: pointer; deterministico: boolean;
  fActPaso: NReal);
var
  kPasoT, nPasosT: integer;
begin

  if nHiperplanosPorPasoT < 1 then
    raise Exception.Create(
      'Debe fijar la variable nHiperplanosPorPasoT antes de llamar a TAdminEstadosMultiPlano.CrearElEspacioTiempo'
      );

  if self.FechaIni <> nil then
     self.FechaIni.Free;
  self.FechaIni := TFecha.Create_Clone(FechaIni);

  if self.fechaFin <> nil then
     self.FechaFin.Free;
  self.fechaFin := TFecha.Create_Clone(fechaFin);

  self.horasDelPaso := horasDelPaso;
  self.deterministico := deterministico;
  self.fActPaso := fActPaso;

  SetLength(xr, nVarsContinuas);
  SetLength(xd, nVarsDiscretas);

  ControladorDeterministico := nil;
  if not deterministico then
  begin
    if costoFuturo <> nil then
      conjuntosDeHiperPlanos := TDAOfConjuntosDeHiperplanos(costoFuturo)
    else
    begin
      nPasosT := trunc((FechaFin.dt - FechaIni.dt + dt_100ms) * 24.0 / horasDelPaso);
      nPuntosT := nPasosT + 2;
      setlength(conjuntosDeHiperPlanos, nPuntosT);
      for kPasoT := 1 to high(conjuntosDeHiperPlanos) do
      begin
        conjuntosDeHiperPlanos[kPasoT] :=
          TConjuntoDeHiperplanos.Create(nVarsContinuas + nVarsDiscretas,
          nHiperplanosPorPasoT);
      end;
    end;
  end
  else
    raise Exception.Create(
      'TAdminEstadosMultiPlnao.ClearElEspacioTiempo ... deterministico   no es posible'
      );
end;



(*
class function TAdminEstadosMultiPlano.CreateLoadCFMPFromArchi(const archi: string
  ): TAdminEstadosMultiPlano;


var
  fechaIni_, fechaFin_: TFecha;
  res: TAdminEstadosMultiPlano;
begin



end;
  *)

procedure TAdminEstadosMultiPlano.ReadCuerpoFromBin(f: TStream);
var
  k: integer;
begin
  brwf(f, k, False);
  setlength(conjuntosDeHiperPlanos, k);
  for k := 1 to high(conjuntosDeHiperPlanos) do
    conjuntosDeHiperPlanos[k] := TConjuntoDeHiperplanos.CreateFromBinStream(f);
  brwf_Cursor(f, False);
end;

procedure TAdminEstadosMultiPlano.WriteCuerpoToBin(f: TStream;
  flg_compress: integer = -1);
var
  k: integer;
begin
  k := length(conjuntosDeHiperPlanos);
  brwf(f, k, True);
  for k := 1 to high(conjuntosDeHiperPlanos) do
    conjuntosDeHiperPlanos[k].WriteToBinStream(f);
  brwf_Cursor(f, True);
end;

procedure TAdminEstadosMultiPlano.ClonarInfoadParasito(res: TAdminEstados);
var
  resx: TAdminEstadosMultiPlano;
begin
  resx := res as TAdminEstadosMultiPlano;

  // Información del manto CF(X) en base a hiperplanos por paso
  resx.conjuntosDeHiperPlanos := conjuntosDeHiperPlanos;
  resx.NombresVariables := NombresVariables;
  resx.fActPaso := fActPaso;
  resx.archiCFMP := archiCFMP;

  //*** ¿se usa?
  resx.kHiperPlanosFromDts := kHiperPlanosFromDts;

      (*
  // Información del Cursor Temporal
      resx.dtIniSala:= dtIniSala;
      resx.dtFinSala:= dtFinSala;
      resx.dtPasoSala:= dtPasoSala;
      resx.nPuntosSala:= nPuntosSala;
      *)
end;

function TAdminEstadosMultiPlano.Primer_kPuntoT: integer;
begin
  Result := 1;
end;

function TAdminEstadosMultiPlano.Ultimo_kPuntoT: integer;
begin
  Result := High(conjuntosDeHiperPlanos);
end;

function TAdminEstadosMultiPlano.costoContinuo(kPuntoT: integer): NReal;
begin
  Result := getHiperplanosFromkPunto(kPuntoT).Valmax(xr, xd);
end;

function TAdminEstadosMultiPlano.deltaCosto_vxr_continuo(irx: integer;
  kpuntoT: integer; delta_xr: NReal): NReal;

var
  c0, c1: NReal;
  xr0: NReal;
begin
  c0 := getHiperplanosFromkPunto(kPuntoT).Valmax(xr, xd);
  xr0:= xr[irx];
  xr[irx]:= xr0+delta_xr;
  c1 := getHiperplanosFromkPunto(kPuntoT).Valmax( xr , xd);
  xr[irx]:= xr0;
  Result:= c1 - c0;
end;

function TAdminEstadosMultiPlano.getDtFromKpunto(kPunto: integer): TDateTime;
begin
  Result := fechaIni.dt + (kPunto - 1) * self.horasDelPaso / 24.0;
end;

function TAdminEstadosMultiPlano.getHiperplanosFromDT(dt: TDateTime):
TConjuntoDeHiperplanos;
var
  kHiperplanos: integer;
begin
  kHiperplanos := getkHiperplanosFromDT(dt);
  if kHiperplanos >= 0 then
    Result := conjuntosDeHiperPlanos[kHiperplanos]
  else
    Result := nil;
end;

function TAdminEstadosMultiPlano.getkHiperplanosFromDT(dt: TDateTime): integer;
begin
  Result := trunc((dt - self.fechaIni.dt + dt_100ms) /
    (self.horasDelPaso / 24.0)) + 1;
end;

(*
class function TAdminEstadosMultiPlano.CreateReadFromArchi(archi: string
  ): TAdminEstadosMultiPlano;
var
  res: TAdminEstadosMultiPlano;
begin

  setSeparadoresGlobales;

  try
    if not FileExists(archi) then
       raise Exception.Create('No se encontró: ' + archi);
    res := TAdminEstadosMultiPlano(inherited CreateReadFromArchi(archi));
  except
    raise Exception.Create('Error al intentar leer CF: ' + archi);
  end;

 setSeparadoresLocales;


  res.nHiperplanosPorPasoT:=1;
  res.archiCFMP:=archi;

  Result:=res;

end;
  *)

procedure TAdminEstadosMultiPlano.WriteCuerpoToXLT(f: TStream);
var
  kPaso, kVA: integer;
begin
  { @xc Lo pasé para el encabezado, en TAdminEstados
  WritelnS(f, 'dt_Ini' + #9 + DateTimeToIsoStr(fechaIni.dt) + #9);
  WritelnS(f, 'Horas_del_paso' + #9 + FloatToStr(horasDelPaso) + #9); }

  writeS(f, 'NHiperplanos' + #9);
  writeS(f, 'Cantidad_de_VE' + #9);

  for kVA := 0 to High(conjuntosDeHiperPlanos[1].hiperPlanos[0].A) do
    writeS(f, 'Coef' + IntToStr(kVA) + #9);
  writelnS(f, 'C0' + #9);

  for kPaso := 1 to High(conjuntosDeHiperPlanos) do
    conjuntosDeHiperPlanos[kPaso].WriteToXLT(f);

end;

procedure TAdminEstadosMultiPlano.ReadCuerpoFromXLT(f: TStream);
var
  r: string;
  kPaso: integer;
begin
  setlength(conjuntosDeHiperPlanos, self.nPuntosT); // porque está indexado desde 1

  archiCFMP := TFileStream(f).FileName;

 { @xc Lo pasé para el encabezado, en TAdminEstados
 readlnS(f, r);
  NextStr(r);  //dt_Ini
  fechaIni := TFecha.Create_Dt(StrToDateTime(NextStr(r)));
  readlnS(f, r);
  NextStr(r);  //Horas del paso
  horasDelPaso := NextFloat(r);
  fechaFin:= TFecha.Create_Dt( fechaIni.dt + (self.nPuntosT-1) * horasDelPaso / 24.0 );   }

  readlnS(f, r);  //NHiperplanos  Cantidad_de_VE  Coef....n   C0

  for kPaso := 1 to High(conjuntosDeHiperPlanos) do
    conjuntosDeHiperPlanos[kPaso] := TConjuntoDeHiperplanos.CreateReadFromXLT(f);

  if length(conjuntosDeHiperPlanos) > 0 then
    nHiperplanosPorPasoT := Length(conjuntosDeHiperPlanos[1].hiperPlanos)
  else
    nHiperplanosPorPasoT := 1;

end;



{$IFDEF _PORVER_}
procedure TAdminEstadosMultiPlano.WriteToFileAprolin(archi: string;
  coeficientes: TDAofMatR; hiperplanosPorPaso: integer);
var
  kVariable, kPaso, kHiperPlano: integer;
  dt: TDateTime;
  grad_CF_X0: TVectR;
  A0, CF_X0: NReal;
  strGrad: string;
  fsal: TextFile;
begin

  AssignFile(fsal, archi);
  Rewrite(fsal);


 { if high( coeficientes ) > 0 then
     self.nPuntosT_:= Length( coeficientes );
  }
  createArchiCFMPEncab(fsal);

  // Escribimos los hiperplanos en el archivo de CFMP
  for kPaso := 1 to high(coeficientes) do
  begin

    dt := getDtFromKpunto(kPaso + 1);

    WriteEncabHiperplanos(fsal, dt, hiperplanosPorPaso);

    //  CF(X0) = A0 + grad(CF(X0))*X0

    for kHiperPlano := 0 to hiperplanosPorPaso - 1 do
    begin
      grad_CF_X0 := TVectR.Create_Init(nVarsContinuas + nVarsDiscretas);
      //coeficientes[kPaso].WriteArchiXLT('C:\basura\dbg\coeficientes.xlt');
      A0 := coeficientes[kPaso].e(1, kHiperPlano + 1);
      CF_X0 := A0;
      strGrad := '';

      for kVariable := 1 to (nVarsContinuas + nVarsDiscretas) do
      begin
        grad_CF_X0.pon_e(kVariable, coeficientes[kPaso].e(kVariable + 1, kHiperPlano + 1));
        //en kVariable=0 esta A0
        strGrad := strGrad + FloatToStr(grad_CF_X0.e(kVariable)) + #9;
      end;

      WriteHiperplanos(fsal, CF_X0, strGrad);

      {
        CF(X) =  CF(X0) + grad(CF(X0))*(X-X0) =

        CF(X) = CF(X0) - grad(CF(X0))*X0  + grad(CF(X0))*X

        CF(X) = A1X1 + A2X2 + A3X3 + A0 ; (A0, A1, A2, A3)

        grad(CF(X0)) = (A1, A2, A3)
        X0 = impresion variables de estado
        CF(X0) = ?
        A0 = CF(X0) - grad(CF(X0))*X0

        CF(X0)= A0 + (A1, A2, A3)*X0
      }

      grad_CF_X0.Free;
    end;
  end;

  CloseFile(fsal);

end;



procedure TAdminEstadosMultiPlano.WriteEncabHiperplanos(var fsal: TextFile;
  dt: TDateTime; NHiperplanos: integer);
begin
  writeln(fsal, 'dt:', #9, dt, #9, 'NHiperplanos', #9, NHiperplanos);
end;

procedure TAdminEstadosMultiPlano.WriteHiperplanos(var fsal: TextFile;
  CF_X0: NReal; strGrad: string);
begin
  writeln(fsal, CF_X0, #9, strGrad);
end;

{$ENDIF}
 {
procedure TAdminEstadosMultiPlano.createArchiCFMPEncab(var fsal: TextFile);
var
  kVariable: Integer;
begin

  Writeln(fsal, 'Version_archi_hiperplanos:'#9, VERSION_ARCHI_HIPERPLANOS);
  Writeln(fsal, 'fActPaso: '#9, FloatToStrF( fActPaso, ffGeneral, 12, 10));
  Writeln(fsal, 'NContinuas:', #9, nVarsContinuas);
  Writeln(fsal, 'NDiscretas:', #9, nVarsDiscretas);
  Writeln(fsal, 'nPuntosT:', #9, nPuntosT);

  if nVarsContinuas > 0 then
  begin
    writeln(fsal, '-- Descripcion variables continuas --');
    for kVariable := 0 to nVarsContinuas - 1 do
      xr_def[kVariable].PrintToText(fsal);
  end;
  if nVarsDiscretas > 0 then
  begin
    writeln(fsal, '-- Descripcion variables discretas --');
    for kVariable := 0 to nVarsDiscretas - 1 do
      xd_def[kVariable].PrintToText(fsal);
  end;

  write(fsal, 'CF_0' + #9);

  for kVariable := 0 to nVarsContinuas - 1 do
    write(fsal,'dCF/d' + xr_def[kVariable].nombre + #9);
  for kVariable := 0 to nVarsDiscretas - 1 do
    write(fsal,'dCF/d' + xd_def[kVariable].nombre + #9);
  writeLn(fsal);

end;          }

destructor TAdminEstadosMultiPlano.Destroy;
var
  kConjunto: integer;
begin
  if conjuntosDeHiperPlanos <> nil then
  begin
    for kConjunto := 1 to high(conjuntosDeHiperPlanos) do
      conjuntosDeHiperPlanos[kConjunto].Free;
    SetLength(conjuntosDeHiperPlanos, 0);
  end;
  inherited Destroy;
end;

procedure TAdminEstadosMultiPlano.FreeParasito;
begin
  conjuntosDeHiperPlanos := nil;
  NombresVariables := nil;
  inherited FreeParasito;
end;

function TAdminEstadosMultiPlano.CreateParasito: TAdminEstados;
var
  res: TAdminEstadosMultiPlano;
begin
  res := TAdminEstadosMultiPlano.Create(nVarsContinuas, nVarsDiscretas,
    nPuntosT, self.nHiperplanosPorPasoT);
  CompletarParasito(res);
  Result := res;
end;

function TAdminEstadosMultiPlano.getHiperplanosFromkPunto(kPunto: integer):
TConjuntoDeHiperplanos;
begin
  Result := conjuntosDeHiperPlanos[kPunto];
end;

function TAdminEstadosMultiPlano.evaluarHiperplano(hiperplano: THiperplano;
  estadoR: TDAOfNReal; estadoD: TDAOfNInt): NReal;
begin
  Result := hiperplano.val(estadoR, estadoD);
end;

function TAdminEstadosMultiPlano.hiperplanosNulos: TConjuntoDeHiperplanos;
begin
  Result := TConjuntoDeHiperplanos.Create(nVarsContinuas + nVarsDiscretas, 1);
end;

procedure TAdminEstadosMultiPlano.devxr_continuo(irx: integer;
  kpuntoT: integer; out dCdx_Inc, dCdx_Dec: NReal; out resCod: integer;
  out xrpos: NReal);
var
  hiperplanos: TConjuntoDeHiperplanos;
  hp: THiperPlano;
  MC: NReal;

begin
  hiperplanos := getHiperplanosFromkPunto(kpuntoT);
  resCod := 0;
  xrpos := 0;

  if hiperplanos = nil then
  begin
    dCdx_Inc := 0;
    dCdx_Dec := 0;
    exit;
  end;
  hp := hiperplanos.HiperplanoMayorCostoAt(Xr, Xd, MC, kHiperPlanoMayorValor);
  hp := hiperplanos.hiperplanos[kHiperplanoMayorValor];
  dCdx_Inc := hp.a[irx];
  dCdx_Dec := dCdx_Inc;
end;

procedure TAdminEstadosMultiPlano.ActualizarEstadoGlobal(kPaso: integer);
var
  hiperplanos: TConjuntoDeHiperplanos;
  MC: NReal;
begin
  hiperplanos := getHiperplanosFromkPunto(kPaso);
  hiperplanos.HiperplanoMayorCostoAt(Xr, Xd, MC, kHiperPlanoMayorValor);
end;

end.
