(*
 rch.061122

 El propósito de esta unidad es definir una clase TAdminEstados
 que siva para administrar los estados de un sistema
 y brinde los servicios necesarios par realizar
 programación dinámica estocástica (PDE) sobre  el sistema y
 realizar simulaciones del sistema una vez que se ha fijado
 la mejor política de operación en base a la PDE.

 Para que el armado del espacio de estados se pueda realizar en forma
 colaborativa por el conjutno de Actores definimos métodos para
 registrar variables de estado indicando el rango de la variable,
 el tipo (continua o discreta) y la cantidad de puntos de discretización
 que se desea tener sobre el rango. La mínima cantidad de puntos es 2 y
 serían los extremos del rango de la variable.

 Al inicio, en la creación del sistema los Actores deben registar las variables
 Luego de registrados todos los actores, se debe indicar la cantidad de pasos
 de tiempo más uno como la cantidad de FOTOS del espacio de estado que se
 deben considerar.

*)

unit uestados;

{$MODE Delphi}

interface

uses
  uparseadorsupersimple,
  Classes,
  Math, xmatdefs, uodt_types, uFechas, SysUtils,
  uCosa,
  uVersiones,
  matreal,
  MatEnt,
  ucontroladordeterminista,
  uRecCFMP,
  uauxiliares;

resourcestring
  exCopiarVariablesDe =
    'TAdminEstados.copiarVariablesDe: el CF de destino no tiene la misma cantidad de variables que el CF de origen';


const
  cfbin_nver = 2; // agrego numero de versión al CF.bin

type
  TFuncTraduccion = function(x: NReal): NReal of object;

  { TEngancheCFReal }

  TEngancheCFReal = class(TCosa)
  public
    nombreVar: string;
    unidades: string;
    valor: NReal;

    constructor Create(capa: integer; const nombreVar, unidades: string; valor: NReal);
    function Rec: TCosa_RecLnk; override;
    procedure AfterRead(f:TArchiTexto); override;
  end;

  TDAOfEngancheCFReal = array of TEngancheCFReal;

  { TEngancheCFEntero }

  TEngancheCFEntero = class(TCosa)
  public
    nombreVar: string;
    unidades: string;
    valor: integer;

    constructor Create(capa: integer; const nombreVar, unidades: string; valor: integer);

    function Rec: TCosa_RecLnk; override;
    procedure AfterRead(f:TArchiTexto); override;

    function ConversionV94(input: array of string): TDAofString;
  end;

  TDAOfEngancheCFEntero = array of TEngancheCFEntero;


  { TAdminEstados }

  TAdminEstados = class

    //*********** Descripción del espacio *************************
    // dimensionado
    nVarsContinuas: integer;
    nVarsDiscretas: integer;

    // vectores con las definiciones de las variablas continuas y discretas
    xr_def: TDAOfDefVarContinua;
    xd_def: TDAOfDefVarDiscreta;

    // descripción de TIEMPO
    nPuntosT: integer; // nPasos+2  uno por la posición CERO que se descarta y otro para la tapa final
    {

    Se indexa desde 1 por lo que la posición 0 no se usa y se necesita una al final en nPasos + 1
    para proyectar el último punto

    kpunto 1.. nPuntosT - 1

    0            1            2      nPuntosT-2     nPuntosT-1
    |------------|------------|............|------------|

    los índices que hacen referencia al tiempo (kPaso, kPunto) se indexan desde 1!!

    }


    fechaIni, fechaFin: TFecha;
    horasDelPaso: NReal;

    // Factor de actualización del paso
    fActPaso: NReal;

    //***************** mapeo CF(X) *******************
    // soporte para el espacio de estado definido por los vectores anteriores
    constelacion_: TConstelacion;

    // agrego soporte para controlador_determinista
    deterministico: boolean;
    // false si es un espacio de estado común, true si es para que sea determinista
    ControladorDeterministico: TControladorDeterministico;


    //***************** CURSOR por defecto del espacio *****************
    // Agregados para manejo de Trayectoria
    // vectores para almacenar el ESTADO ACTUAL
    xr: TDAOfNReal;
    xd: TDAOfNInt;

    // Indices de la posición de la estrellita en cada  variables de estado
    // al recorrer las estrellas de un frame
    estrella_kr, estrella_kd: TDAOfNInt;

    // ordinal de la estrellita al recorrer las estrellas de un frame.
    ordinalEstrellaActual: integer;


    // Soporte para los multiplicadores de Lagrange de las restricciones dinámicas
    // en el último punto resuelto
    lambda: TVectR;


    flg_SoyParasito: boolean;


    {$IFDEF PRUEBAS_ENGANCHE}
    flg_usarCFEnganches:boolean;
    {$ENDIF}

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

    function CreateParasito: TAdminEstados; virtual;

    class function CreateReadFromArchi( archi: string ): TAdminEstados;
    class function CreateFromStream( f: TStream ): TAdminEstados;


    // abre el archivo (archi) para escritura, llama a StoreInFile y luego
    // cierra el archivo
    // si flg_compress = -1 se aplica la compresión más avanzada al guardar
    // la información del costo futuro.
    procedure WriteToArchi( archi: string;  flg_compress: integer = -1  );
    procedure WriteToBin(f: TStream; flg_compress: integer);
    procedure WriteToXLT(f: TStream);

    procedure WriteEncabToBin( f: TStream ); virtual;
    procedure WriteCuerpoToBin(f: TStream; flg_compress: integer=-1); virtual;

    procedure WriteEncabToXlt( f: TStream ); virtual;
    procedure WriteCuerpoToXLT( f: TStream); virtual;

    procedure ReadEncabFromBin( f: TStream ); virtual;
    procedure ReadCuerpoFromBin( f: TStream); virtual;

    procedure ReadEncabFromXlt( f: TStream ); virtual;
    procedure ReadCuerpoFromXLT( f: TStream); virtual;

    // guardan sin comprimir para compatibilidad con v178 de SimSEE y anteriores
    procedure StoreInArchi_178_(const archi: string);
    procedure StoreInFile_178_(f: TStream);

    procedure brwf_Encabezado(f: TStream; flgw: boolean );
    procedure brwf_Cursor(f: TStream; flgw: boolean );

    // ponemos constelación y deterministico vaciopara que se liberen solo los cursores
    // si una clase hereda de TAdminEstados e incluye DatosParasitos, debe desvincularlos
    // sobreescribiendo este método.
    procedure FreeParasito; virtual;

    destructor destroy; override;

    procedure Registrar_Continua(ixr: integer; xmin, xmax: NReal;
      nPuntos: integer; nombre: string; unidades: string);

    function indexOf_Continua(nombre: string): integer;

    procedure RegistrarTraduccion_Continua(ixr: integer;
    // xmin, xmax: NReal;  nPuntos: integer;
      const nombre, unidades: string; funcTraduccion: TFuncTraduccion);

    procedure Registrar_Discreta(ixd: integer; npuntos: integer;
      const nombre, unidades: string);

    function indexOf_Discreta(nombre: string): integer;

    {
    procedure RegsitrarTraduccion_Discreta(ixd: integer;
    //npuntos: integer;
      nombre: string; unidades: string);
 }

    //Cuando cambiemos a paso variable cambiar el horasDelPaso por un array con
    //las horas de cada paso

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

    procedure SetEstadoToEstrella;
    procedure SetEstadoToEstrella_indexada(vkr, vkd, idx_r, idx_d: TDAOfNInt);
    procedure SetEstrella_Indexada(vkr, vkd, idx_r, idx_d: TDAOfNInt);


    // interpona los vectores del Manto para la posición continua actual y
    // carga el resultado en "res" desde la posición jBase
    procedure mantoContinuo(var res: TDAOfNReal; jBase: integer;
      const Manto: TMatOfNReal);


    procedure SetCostoEstrella(kPuntoT: integer; valCosto: NReal);
    procedure AcumCostoEstrella(kPuntoT: integer; valCosto: NReal);


    function costoEstrella(kpuntoT: integer): NReal; virtual;
    function costoContinuo(kPuntoT: integer): NReal; virtual;

    // calcula la derivadas respecto de la variabla cuyo índice es (irx) para
    // el punto de tiempo kpuntoT. La derivada dCdx_Inc es la calculada con
    // un incremento de x, la dCdx_Dec es calculada con un decremento.
    procedure devxr_estrella_20_(irx: integer; kpuntoT: integer;
      out dCdx_Inc, dCdx_Dec: NReal); virtual;

    procedure devxr_continuo_20(irx: integer; kpuntoT: integer;
      out dCdx_Inc, dCdx_Dec: NReal); virtual;

    procedure devxr_estrella_(irx: integer; kpuntoT: integer;
      out dCdx_Inc, dCdx_Dec: NReal; out resCod: integer); virtual;

    procedure devxr_continuo(irx: integer; kpuntoT: integer;
      out dCdx_Inc, dCdx_Dec: NReal; out resCod: integer;
    // -1 me fuir por abajo , 0 en la caja , 1 me fui por arriba
      out xrpos: NReal     // Posición del punto en la cajita de aproximación en por unidad
      ); virtual;

    // Calcula la variación del costo por un incremento delta_xd en la variable ird
    // en el punto de tiempo kpuntoT
    function deltaCosto_vxd_estrella_(ird: integer; kpuntoT: integer;
      delta_xd: integer): NReal; virtual;
    function deltaCosto_vxd_continuo(ird: integer; kpuntoT: integer;
      delta_xd: integer): NReal; virtual;

    function deltaCosto_vxr_continuo_DosEstados_UTE(irx, irx2, kpuntoT: integer;
      delta_xr, delta_xr2: NReal): NReal; virtual;
    // delta costo sobre una coordenada real
    function deltaCosto_vxr_continuo(irx: integer; kpuntoT: integer;
      delta_xr: NReal): NReal; virtual;

    // fija los vectores índices estrella_kr, estrella_kd al vértice CERO
    // de la discretización.
    procedure setEstrellaCERO;

    // incrementa los índices estrella_kr, estrella_kd de forma de apuntar
    // la siguiente estrella de la discretización.
    function IncEstrella: boolean;

    // Fija el punto de inicio de un barrido sobre los indexados;
    procedure SetEstrellaCERO_indexada(var estrella_idx_r, estrella_idx_d: TDAOfNint);

    // incrementa la estrella, pero sobre las variables indexadas
    function IncEstrella_indexada(var estrella_idx_r, estrella_idx_d: TDAOfNint;
      idx_r, idx_d: TDAOfNInt): boolean;

    procedure posicionarseEnEstrella(ordinalEstrella: integer);
    function nEstrellasPorPuntoT: integer;

    function CrearCF_AUX_para_enganaches_CFbin(archivoCF: string;
      CarpetaAlternativa: string): TAdminEstados;

    procedure InicializarFrameFinal(const CFaux: TAdminEstados; enganchesContinuos,
      enganchesDiscretos: TListaDeCosas; enganchar_promediando: boolean;
  uniformizar_promediando: string; flg_usar_mapeo: boolean; mapeo_str: string;
  sala: TCosa; MultiplicadorCF: NReal); virtual;

    procedure InicializarFrameFinal_mapeo_enganches(const CFaux: TAdminEstados;
    // desde: TFecha;
      enganchesContinuos, enganchesDiscretos: TListaDeCosas;
      enganchar_promediando: boolean; uniformizar_promediando: string ); virtual;

    procedure InicializarFrameFinal_mapeo_evaluador(const CFaux: TAdminEstados;
      mapeo_str, uniformizar_promediando: string; sala: TCosa );


    // recibe un string con los nombres de las variables,
    // separados por ";" , para uniformizar
    // promediando el último frame.

    // Clasifica las variables en "a_Uniformizar" y "Otras".
    // entonces, hace un FOR en Otras recorriendo las estrellas que define
    // el producto cartesiano de sus discretizaciones. En cada Super_Estrella así definida
    // se recorren todas las estrellas definidas para ese punto del producto cartesinao de otras
    // por el producto cartesiano de las discretizaciones de las variables "a_Uniformizar".
    procedure uniformizar_ultimo_frame_en(uniformizar_promediando: string);


    function variablesIgualesA(otroCF: TAdminEstados): boolean;
    procedure copiarVariablesDe(otroCF: TAdminEstados);

    // Copiar el útimo frame en todos los demas.
    procedure LlenarConFrameFinal;


    // retorna un string con las coordenadas de los estados continuos y discretos
    // separados por tabuladores.
    function GetEstado_XLT: string;

    // Cheque que el CFAux pasado como parámetro sea compatible para ser
    // accedido como un CFAux durante la simulación.
    function ChequearCompatibilidad_CFAux(const CFAux: TAdminEstados): boolean;

    // Retorna una TStringList con los nombres de las variables de estado
    function VariablesDeEstado_lst: TStringList;

    procedure ActualizarEstadoGlobal(kPaso:integer); virtual;

    function getDtFromKpunto( kPunto: integer): TDateTime;
    function getkPuntoFromDT(dt: TDateTime): Integer;

    procedure ClonarCursorParasito( res: TAdminEstados ); virtual;
    procedure ClonarInfoadParasito( res: TAdminEstados ); virtual;

    procedure CompletarParasito( res: TAdminEstados );

    function Primer_kPuntoT: integer; virtual;
    function Ultimo_kPuntoT: integer; virtual;

  private
    constructor CreateFromBin(f: TStream); virtual;
    constructor CreateFromXLT(f: TStream); virtual;
  end;




  TClassAdminEstados = class of TAdminEstados;


procedure AlInicio;
procedure AlFinal;

// auxiliares para lectura escritura en archivo binario
procedure brwf(f: TStream; var X: integer; flgw: boolean); overload;
procedure brwf(f: TStream; var X: NReal; flgw: boolean); overload;
procedure brwf(f: TStream; var X: TDateTime; flgw: boolean); overload;
procedure brwf(f: TStream; var X: TDAOfNReal; flgw: boolean); overload;
procedure brwf(f: TStream; var X: TVectR; flgw: boolean); overload;
procedure brwf(f: TStream; var X: TDAOfNInt; flgw: boolean); overload;
procedure brwf(f: TStream; var x: TDAOfDefVarContinua; flgw: boolean); overload;
procedure brwf(f: TStream; var x: TDAOfDefVarDiscreta; flgw: boolean); overload;
procedure brwf(f: TStream; var X: string; flgw: boolean); overload;


// Las clases derivadas de TAdminEstado deben implementar el constructor
// CreateFromFile para que puedena persistirse sin inconvenientes.
procedure RegistrarClase_AdminEstados( clase: TClassAdminEstados );


implementation
uses
  usalasdejuego, ucfmpute;

type

  { TClaseAdminEstadoRec }

  TClaseAdminEstadoRec = class
    nombre_clase: string;
    clase: TClassAdminEstados;
    constructor Create( clase: TClassAdminEstados );
  end;

  { TListOfClasesAdminEstado }

  TListOfClasesAdminEstado = class( TList )
    constructor Create;
    procedure Registrar(clase: TClassAdminEstados);
    destructor destroy; override;
    function ClassOf( nombre_clase: String ): TClassAdminEstados;
  end;


var
  RegistroClasesAdminEstado: TListOfClasesAdminEstado;

{ TClaseAdminEstadoRec }

constructor TClaseAdminEstadoRec.Create(clase: TClassAdminEstados );
begin
  inherited Create;
  nombre_Clase:= clase.ClassName;
  self.clase:= clase;
end;

{ TListOfClasesAdminEstado }

constructor TListOfClasesAdminEstado.Create;
begin
  inherited Create;
end;

procedure TListOfClasesAdminEstado.Registrar(clase: TClassAdminEstados );
var
  aRec: TClaseAdminEstadoRec;
begin
  aRec:= TClaseAdminEstadoRec.Create( clase );
  add( aRec );
end;


destructor TListOfClasesAdminEstado.destroy;
var
  k: integer;
begin
  for k:= 0 to count - 1 do
    TClaseAdminEstadoRec( items[ k ] ).Free;
  inherited destroy;
end;

function TListOfClasesAdminEstado.ClassOf(nombre_clase: String
  ): TClassAdminEstados;
var
  encontrada: boolean;
  k: integer;
  aRec: TClaseAdminEstadoRec;
begin
  encontrada:= false;

  for k:= 0 to count -1 do
  begin
    aRec:= items[k];
    if aRec.nombre_clase = nombre_clase then
    begin
      encontrada:= true;
      break;
    end;
  end;

  if encontrada then
    result:= aRec.clase
  else
    result:= nil;

end;



constructor TEngancheCFReal.Create(capa: integer; const nombreVar, unidades: string;
  valor: NReal);
begin
  inherited Create(capa);
  self.nombreVar := nombreVar;
  self.unidades := unidades;
  self.valor := valor;
end;

function TEngancheCFReal.Rec: TCosa_RecLnk;
begin
  Result := inherited Rec;
  Result.addCampoDef('nombreVar', nombreVar);
  Result.addCampoDef('unidades', unidades, 94);
  Result.addCampoDef('valor', valor);
end;

procedure TEngancheCFReal.AfterRead(f:TArchiTexto);
var
  i1, i2: integer;
begin
  inherited AfterRead(f);
  if f.Version < 94 then
  begin
    i1 := pos('[', nombreVar);
    i2 := pos(']', nombreVar);
    if (i1 > 0) and (i2 > i1) then
    begin
      unidades := trim(copy(nombreVar, i1 + 1, i2 - i1 - 1));
      Delete(nombreVar, i1, length(nombreVar) - i1 + 1);
      nombreVar := trim(nombreVar);
    end
    else
      unidades := '';
  end;
end;


constructor TEngancheCFEntero.Create(capa: integer; const nombreVar, unidades: string;
  valor: integer);
begin
  inherited Create(capa);
  self.nombreVar := nombreVar;
  self.unidades := unidades;
  self.valor := valor;
end;

function TEngancheCFEntero.Rec: TCosa_RecLnk;
begin
  Result := inherited Rec;
  Result.addCampoDef('nombreVar', nombreVar);
  Result.addCampoDef('unidades', unidades, 94);
  Result.addCampoDef('valor', valor);
end;

procedure TEngancheCFEntero.AfterRead(f:TArchiTexto);
var
  i1, i2: integer;
begin
  inherited AfterRead(f);
  if f.Version < 94 then
  begin
    i1 := pos('[', nombreVar);
    i2 := pos(']', nombreVar);
    if (i1 > 0) and (i2 > i1) then
    begin
      unidades := trim(copy(nombreVar, i1 + 1, i2 - i1 - 1));
      Delete(nombreVar, i1, length(nombreVar) - i1 + 1);
      nombreVar := trim(nombreVar);
    end
    else
      unidades := '';
  end;
end;



function TEngancheCFEntero.ConversionV94(input: array of string): TDAofString;
var
  i1: SizeInt;
  i2: SizeInt;

  nombreVar: string;
  unidades: string;

begin

  nombreVar := input[0];

  i1 := pos('[', nombreVar);
  i2 := pos(']', nombreVar);
  if (i1 > 0) and (i2 > i1) then
  begin
    unidades := trim(copy(nombreVar, i1 + 1, i2 - i1 - 1));
    Delete(nombreVar, i1, length(nombreVar) - i1 + 1);
    nombreVar := trim(nombreVar);
  end
  else
    unidades := '';

  SetLength(Result, 2);
  Result[0] := nombreVar;
  Result[1] := unidades;
end;

procedure brwf(f: TStream; var X: integer; flgw: boolean); overload;
begin
  if flgw then
    f.Write( X, SizeOf(X))
  else
    f.Read( X, SizeOf(X));
end;

procedure brwf(f: TStream; var X: NReal; flgw: boolean); overload;
begin
  if flgw then
    f.Write( X, SizeOf(X))
  else
    f.Read( X, SizeOf(X));
end;

procedure brwf(f: TStream; var X: TDateTime; flgw: boolean); overload;
begin
  if flgw then
    f.Write( X, SizeOf(X))
  else
    f.Read( X, SizeOf(X));
end;

procedure brwf(f: TStream; var X: TDAOfNReal; flgw: boolean); overload;
var
  n, k: integer;
begin
  if flgw then
  begin
    n := length(X);
    brwf(f, n, True);
    for k := 0 to high(X) do
      brwf(f, x[k], True);
  end
  else
  begin
    brwf(f, n, False);
    setlength(X, n);
    for k := 0 to high(X) do
      brwf(f, x[k], False);
  end;
end;

procedure brwf(f: TStream; var X: TVectR; flgw: boolean);
var
  n, k: integer;
begin
  if flgw then
  begin
    n := X.n;
    brwf(f, n, True);
    for k := 1 to n do
      brwf(f, x.pv[k], True);
  end
  else
  begin
    brwf(f, n, False);
    X:= TVectR.Create_init( n );
    for k := 1 to n do
      brwf(f, x.pv[k], False);
  end;
end;

procedure brwf(f: TStream; var X: TDAOfNInt; flgw: boolean); overload;
var
  n, k: integer;
begin
  if flgw then
  begin
    n := length(X);
    brwf(f, n, True);
    for k := 0 to high(X) do
      brwf(f, x[k], True);
  end
  else
  begin
    brwf(f, n, False);
    setlength(X, n);
    for k := 0 to high(X) do
      brwf(f, x[k], False);
  end;
end;

procedure brwf(f: TStream; var x: TDAOfDefVarContinua; flgw: boolean);
  overload;
var
  n, k: integer;
begin
  if flgw then
  begin
    n := length(X);
    brwf(f, n, True);
    for k := 0 to high(X) do
      x[k].WriteToBinStream(f);
  end
  else
  begin
    brwf(f, n, False);
    setlength(X, n);
    for k := 0 to high(X) do
      x[k] := TDefVarContinua.CreateFromBinStream(f);
  end;
end;

procedure brwf(f: TStream; var x: TDAOfDefVarDiscreta; flgw: boolean);
  overload;
var
  n, k: integer;
begin
  if flgw then
  begin
    n := length(X);
    brwf(f, n, True);
    for k := 0 to high(X) do
      x[k].WriteToBinStream(f);
  end
  else
  begin
    brwf(f, n, False);
    setlength(X, n);
    for k := 0 to high(X) do
      x[k] := TDefVarDiscreta.CreateFromBinStream(f);
  end;
end;

procedure brwf(f: TStream; var X: string; flgw: boolean);
var
  n, k, m: integer;
begin
  if flgw then
  begin
    n := length(X);
    brwf(f, n, True);
    if n > 0 then
    begin
      m:= sizeOf( X[1] );
      for k:= 1 to n do
        f.Write( X[k], m);
    end;
  end
  else
  begin
    brwf(f, n, False);
    setlength(X, n);
    if n > 0 then
    begin
      m:= sizeOf( X[1] );
      for k:= 1 to n do
       f.Read( X[k], m);

    end;
  end;
end;

procedure RegistrarClase_AdminEstados(clase: TClassAdminEstados);
begin
  RegistroClasesAdminEstado.Registrar( clase );
end;


procedure TAdminEstados.StoreInArchi_178_(const archi: string);
var
  f: TFileStream;
begin
  f:= TFileStream.Create( archi, fmCreate );
  StoreInFile_178_(f);
  f.Free;
end;

procedure TAdminEstados.StoreInFile_178_(f: TStream);
begin
  brwf_Encabezado(f, true );
  constelacion_.StoreInFile_178_(f);
  brwf_Cursor(f, true );
end;

procedure TAdminEstados.brwf_Encabezado( f: TStream; flgw: boolean );
var
  raux: double;
  iaux: integer;

  // primer numero. Si es -1 indica que
  // el segundo es el número de versión.
  // si no es -1 asumo que el numero de versión es 1
  nver: integer;
  dtAux: TDateTime;
  intaux: integer;
  v0: double;

begin
  if flgw then
  begin
  raux := -1;
  iaux := cfbin_nver;
  brwf(f, raux, flgw);
  brwf(f, iaux, flgw);
  brwf(f, fechaIni.dt, flgw);
  brwf(f, fechaFin.dt, flgw);
  brwf(f, horasDelPaso, flgw);
  brwf(f, nVarsContinuas, flgw);
  brwf(f, nVarsContinuas, flgw);
  brwf(f, nVarsDiscretas, flgw);
  brwf(f, nPuntosT, flgw);
  brwf(f, xr_def, flgw);
  brwf(f, xd_def, flgw);
  end
  else
  begin
      constelacion_ := nil;
      ControladorDeterministico := nil;

      brwf(f, v0{%H-}, flgw);
      if (v0 = -1) then
      begin
        brwf(f, nver{%H-}, flgw);
        brwf(f, dtAux{%H-}, flgw);
      end
      else
      begin
        nver := 1;
        dtAux := TDateTime(v0);
      end;

      FechaIni := TFecha.Create_Dt(dtAux);
      brwf(f, dtAux, flgw);
      fechaFin := TFecha.Create_Dt(dtAux);

      if nver < 2 then
      begin
        brwf(f, intaux{%H-}, flgw);
        horasDelPaso := intaux;
      end
      else
      begin
        brwf(f, horasDelPaso, flgw);
      end;
      brwf(f, nVarsContinuas, flgw);
      brwf(f, nVarsContinuas, flgw);
      brwf(f, nVarsDiscretas, flgw);
      brwf(f, nPuntosT, flgw);
      brwf(f, xr_def, flgw);
      brwf(f, xd_def, flgw);
  end;


end;



procedure TAdminEstados.brwf_Cursor(f: TStream; flgw: boolean);
begin
  brwf(f, xr, flgw);
  brwf(f, xd, flgw);
  brwf(f, estrella_kr, flgw);
  brwf(f, estrella_kd, flgw);
  brwf(f, ordinalEstrellaActual, flgw);
end;

procedure TAdminEstados.FreeParasito;
begin
  self.constelacion_:= nil;
  self.ControladorDeterministico:= nil;
  inherited Free;
end;



procedure TAdminEstados.WriteToArchi(archi: string; flg_compress: integer);
var
  f: TFileStream;
  sext: string;
begin
  sext:= ExtractFileExt( archi );
  if sext = '.bin' then
  begin
   f:= TFileStream.Create( archi, fmCreate + fmShareExclusive );
   WriteToBin( f, flg_compress );
   f.Free;
  end
  else if sext = '.xlt' then
  begin
    f:= TFileStream.Create( archi, fmCreate + fmShareExclusive );
    WriteToXLT( f );
    f.Free;
  end
  else
    raise Exception.Create(' no es posible manejar la extensión: '+ sext );
end;




procedure TAdminEstados.WriteToBin(f: TStream; flg_compress: integer);
var
  nombre_clase: string;
  fins: string;
begin
  nombre_clase:= '<+'+ClassName+'.bin>';
  writelnS( f, nombre_clase );

  WriteEncabToBin( f );
  WriteCuerpoToBin( f );

  fins:= '<-'+ClassName+'.bin>';
  writelnS( f, fins );
end;

function TAdminEstados.variablesIgualesA(otroCF: TAdminEstados): boolean;
var
  res: boolean;
  i: integer;
begin
  if (nVarsContinuas = otroCF.nVarsContinuas) or (nVarsDiscretas =
    otroCF.nVarsDiscretas) then
  begin
    res := True;
    for i := 0 to nVarsContinuas - 1 do
      if not xr_def[i].esIgualA(otroCF.xr_def[i]) then
      begin
        res := False;
        break;
      end;

    if res then
      for i := 0 to nVarsContinuas - 1 do
        if not xd_def[i].esIgualA(otroCF.xd_def[i]) then
        begin
          res := False;
          break;
        end;
    Result := res;
  end
  else
    Result := False;
end;

procedure TAdminEstados.copiarVariablesDe(otroCF: TAdminEstados);
var
  i: integer;
begin
  if (Self.nVarsContinuas <> otroCF.nVarsContinuas) or
    (self.nVarsDiscretas <> otroCF.nVarsDiscretas) then
    raise Exception.Create(exCopiarVariablesDe);

  for i := 0 to High(otroCF.xr_def) do
    self.xr_def[i] := otroCF.xr_def[i].clonar;
  for i := 0 to high(otroCF.xd_def) do
    self.xd_def[i] := otroCF.xd_def[i].clonar;
end;


procedure TAdminEstados.WriteEncabToXlt(f: TStream);
var
  k: integer;
begin
  writelnS(f, 'Versión del simulador:'#9 + vSimSEESimulador_ );
  writelnS(f, 'fActPaso:'+ #9 + FloatToStrF( fActPaso , ffGeneral, 12, 4 ));

  WriteLnS(f,'NContinuas:'+ #9 + IntToStr( NVarsContinuas));
  WriteLnS(f,'NDiscretas:'+ #9 + IntToStr( NVarsDiscretas));
  WriteLnS(f,'nPuntosT:'+ #9 + IntToStr(nPuntosT)); // había un -1
  WriteLnS(f,'dtIni:'+ #9 + DateTimeToIsoStr(fechaIni.dt));
 // WriteLnS(f,'dtFin:'+ #9 + DateTimeToIsoStr(fechaFin.dt));
  WriteLnS(f,'HorasDelPaso:'+ #9 + FloatToStr(horasDelPaso));


 if nVarsContinuas > 0 then
 begin
    WriteLnS(f,'-- Descripción variables contínuas --');
   for k := 0 to nVarsContinuas - 1 do
     self.xr_def[k].WriteToXlt(f);
 end;

 if nVarsDiscretas > 0 then
 begin
   WriteLnS(f,'-- Descripción variables discretas --');
   for k := 0 to nVarsDiscretas - 1 do
     xd_def[k].WriteToXlt(f);
 end;

end;

procedure TAdminEstados.WriteCuerpoToXLT(f: TStream);
var
  k: Integer;
begin

 constelacion_.WriteToXlt( f, self.fechaIni.dt, horasDelPaso * horaToDt  );

 writeS(f,'iEstrellas Continua');
 for k:=0 to nVarsContinuas-1 do
    writeS(f, #9 + IntToStr(estrella_kr[k]));

 writelnS(f);

 writeS(f,'iEstrellas Discreta');
 for k:=0 to nVarsDiscretas-1 do
    writeS(f, #9 + IntToStr(estrella_kd[k]));

 writelnS(f);
end;

procedure TAdminEstados.ReadEncabFromBin(f: TStream);
begin
  brwf_Encabezado(f, false  );
end;

procedure TAdminEstados.ReadCuerpoFromBin(f: TStream);
begin
  constelacion_ := TConstelacion.CreateFromBinStrem(f);
  brwf_Cursor( f, false );
end;


procedure TAdminEstados.WriteToXLT(f: TStream);
var
  nombre_clase: string;
  fins: string;
begin
  nombre_clase:= '<+'+ClassName+'.xlt>';
  writelnS( f, nombre_clase );
  setSeparadoresGlobales;
  WriteEncabToXlt(f);
  WriteCuerpoToXLT(f);
  setSeparadoresLocales;
  fins:= '<-'+ClassName+'.xlt>';
  writelnS( f, fins );
end;

procedure TAdminEstados.WriteEncabToBin(f: TStream);
begin
  brwf_Encabezado( f, true );
end;

procedure TAdminEstados.WriteCuerpoToBin(f: TStream; flg_compress: integer = -1 );
begin
  constelacion_.StoreInFile(f, flg_compress );
  brwf_Cursor( f, true );
end;


procedure TAdminEstados.ReadEncabFromXlt(f: TStream);
var
  k: integer;
  pal, r:String;
  VersionAdmisEstados: string;
begin


  readlnS( f, r );
  VersionAdmisEstados:= NextPal_SkipN( r, 1, #9 );

  readlnS( f, r );
  pal:= NextPal_SkipN( r, 1, #9 );
  fActPaso:= StrToFloat( pal );

  readlnS( f, r );
  pal:= NextPal_SkipN( r, 1, #9 );
  NVarsContinuas:= StrToInt( pal );
  setlength( xr_def, nVarsContinuas );

  readlnS( f, r );
  pal:= NextPal_SkipN( r, 1, #9 );
  NVarsDiscretas:= StrToInt( pal );
  setlength( xd_def, nVarsDiscretas );

  readlnS( f, r );
  pal:= NextPal_SkipN( r, 1, #9 );
  NPuntosT:= StrToInt( pal );

  readlnS(f, r);
  pal:= NextPal_SkipN( r, 1, #9 );
  fechaIni:=TFecha.Create_Dt(StrToDateTime(pal));

  {readlnS(f, r);
  fechaFin:=TFecha.Create_ISOStr(r); }

  readlnS(f, r);
  pal:= NextPal_SkipN( r, 1, #9 );
  horasDelPaso:=NextFloat(pal);

  fechaFin:= TFecha.Create_Dt( fechaIni.dt + (self.nPuntosT-1) * horasDelPaso / 24.0 );


 if nVarsContinuas > 0 then
 begin
    ReadlnS(f, r ); //'-- Descripción variables continuas --');
   for k := 0 to nVarsContinuas - 1 do
     self.xr_def[k]:= TDefVarContinua.CreateReadFromXlt( f );
   SetLength(self.xr,nVarsContinuas);

 end;

 if nVarsDiscretas > 0 then
 begin
   ReadlnS(f, r );//'-- Descripción variables discretas --');
   for k := 0 to nVarsDiscretas - 1 do
     xd_def[k]:= TDefVarDiscreta.CreateReadFromXLT( f );
   SetLength(self.xd,nVarsDiscretas);
 end;



end;

procedure TAdminEstados.ReadCuerpoFromXLT(f: TStream);
var
  r, pal:string;
  k, j: Integer;
  dtDelPaso: NReal;
  iterFecha: TDateTime;
begin



  constelacion_:=TConstelacion.CreateReadFromXlt(f,xr_def,xd_def,nPuntosT);

 { brwf(f, xr, flgw);
  brwf(f, xd, flgw);  }

  readlnS( f, r );
  getNextPalSep( r, #9 );  //iEstrellas Continua
  setLength(estrella_kr, nVarsContinuas);
  for k:=0 to nVarsContinuas - 1 do
    estrella_kr[k]:=NextInt(r);

  readlnS( f, r );
  getNextPalSep( r, #9 ); //iEstrellas Discreta
  setLength(estrella_kd, nVarsDiscretas);
  for k:=0 to nVarsDiscretas - 1 do
    estrella_kd[k]:=NextInt(r);



//  brwf(f, ordinalEstrellaActual, true)


 { ReadLnS(f, r);
  NextPal(r); //'paso\estado'
  NextPal(r); //'Fecha'
  ReadlnS(f,r);
  for k := 1 to nEstrellasPorPuntoT do
      NextPal(r);
  //WritelnS(f);

  dtDelPaso:= horasDelPaso * horaToDt;



  // salvamos el frame del último paso de tiempo
  ReadlnS(f,r);
  for k := nPuntosT - 1 downto 1 do
  begin
    iterFecha := fechaIni.dt + dtDelPaso * (k - 1);
    NextPal(r);

    for j := 0 to nEstrellasPorPuntoT - 1 do
     constelacion_.fcosto[k][j]:= NextFloat(r);
  end;
       }

end;



constructor TAdminEstados.CreateFromBin(f: TStream);
begin
  inherited Create;
  flg_SoyParasito:=false;
  {$IFDEF PRUEBAS_ENGANCHE}
  flg_usarCFEnganches:=false;
  {$ENDIF}
  ReadEncabFromBin( f );
  ReadCuerpoFromBin( f );
  lambda:=TVectR.Create_Init(nVarsContinuas + nVarsDiscretas);
end;

constructor TAdminEstados.CreateFromXLT(f: TStream);
begin
  inherited Create;
  flg_SoyParasito:=false;
  {$IFDEF PRUEBAS_ENGANCHE}
  flg_usarCFEnganches:=false;
  {$ENDIF}
  setSeparadoresGlobales;
  ReadEncabFromXlt( f );
  ReadCuerpoFromXLT( f );
  setSeparadoresLocales;
  lambda:=TVectR.Create_Init(nVarsContinuas + nVarsDiscretas);
end;



procedure TAdminEstados.CompletarParasito( res: TAdminEstados);
begin
  ClonarCursorParasito( res );
  ClonarInfoadParasito( res )
end;

function TAdminEstados.Primer_kPuntoT: integer;
begin
  result:= 1;
end;

function TAdminEstados.Ultimo_kPuntoT: integer;
begin
  result:= nPuntosT;
end;

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

class function TAdminEstados.CreateReadFromArchi(archi: string): TAdminEstados;
var
  f: TFileStream;
  res: TAdminEstados;
begin
  if not FileExists( archi ) then
    result:= nil
  else
  begin
    f:= TFileStream.Create( archi, fmOpenRead + fmShareDenyWrite );
    res:= CreateFromStream( f );
    if res = nil then
    begin
      f.Seek(0, soFromBeginning );
      res:= TAdminEstados.CreateFromBin( f );
    end;
    result:= res;
    f.Free;
  end;
end;


class function TAdminEstados.CreateFromStream(f: TStream): TAdminEstados;
var
  r, nombre_clase, sext: string;
  aClass: TClassAdminEstados;
begin
  ReadlnS( f, r );
  if pos(  '<+', r ) = 1 then
  begin
    getNextPalSep( r, '<+' );
    nombre_clase:= getNextPalSep( r, '.' );
    sext:= getNextPalSep( r, '>' );
    aClass:= RegistroClasesAdminEstado.ClassOf( nombre_clase );
    if aClass = nil then
      raise Exception.Create( 'Clase no registrada: '+nombre_clase );
    if sext  = 'bin' then
      result:= aClass.CreateFromBin( f )
    else if sext = 'xlt' then
      result:= aClass.CreateFromXLT( f )
    else
      raise Exception.Create('Error, la extensión: '+sext+' no es válida para la clase: '+nombre_clase );
    ReadlnS( f, r );
    if r <> '<-'+ nombre_clase+'.'+sext+'>' then
      raise Exception.Create( 'Error, no se terminó correctamente la lectura del objeto CF' );
  end
  else // si no empieza declarando la clase debe ser un archivo viejo
    result:= nil;

end;



function TAdminEstados.IncEstrella: boolean;
begin
  Result := constelacion_.inc_estrella(estrella_kr, estrella_kd);
  ordinalEstrellaActual := constelacion_.ordinalEstrella(estrella_kr, estrella_kd);
end;


function TAdminEstados.IncEstrella_indexada(
  var estrella_idx_r, estrella_idx_d: TDAOfNint; idx_r, idx_d: TDAOfNInt): boolean;

begin
  Result := constelacion_.inc_estrella_indexada(estrella_idx_r,
    estrella_idx_d, idx_r, idx_d);
end;


procedure TAdminEstados.posicionarseEnEstrella(ordinalEstrella: integer);
begin
  constelacion_.indicesEstrella_i(estrella_kr, estrella_kd, ordinalEstrella);
  ordinalEstrellaActual := ordinalEstrella;
end;

function TAdminEstados.nEstrellasPorPuntoT: integer;
begin
  Result := constelacion_.nEstrellas;
end;

function TAdminEstados.CrearCF_AUX_para_enganaches_CFbin(archivoCF: string;
  CarpetaAlternativa: string): TAdminEstados;
var
  CFaux: TAdminEstados;
begin
  try
    if not FileExists(archivoCF) then
      archivoCF := CarpetaAlternativa + DirectorySeparator + ExtractFileName(archivoCF);
    CFaux := TAdminEstados.CreateReadFromArchi(archivoCF);
  except
    raise Exception.Create('Error al intentar leer CFaux: ' + archivoCF +
      '. Capaz deba optimizar la otra sala primero.');
  end;

  Result := CFaux;

end;

procedure TAdminEstados.InicializarFrameFinal(const CFaux: TAdminEstados;
  enganchesContinuos, enganchesDiscretos: TListaDeCosas;
  enganchar_promediando: boolean; uniformizar_promediando: string;
  flg_usar_mapeo: boolean; mapeo_str: string; sala: TCosa; MultiplicadorCF: NReal );
begin
  if flg_usar_mapeo then
    InicializarFrameFinal_mapeo_evaluador(CFaux, mapeo_str,
      uniformizar_promediando, sala )
  else
    InicializarFrameFinal_mapeo_enganches(CFaux, enganchesContinuos,
      enganchesDiscretos, enganchar_promediando,
      uniformizar_promediando );

    // Ahora si hay que multiplicar multiplicamos.
    if MultiplicadorCF <> 1 then
        constelacion_.PorRealUltimoFrame( MultiplicadorCF );

end;

procedure TAdminEstados.InicializarFrameFinal_mapeo_enganches(
  const CFaux: TAdminEstados; enganchesContinuos,
  enganchesDiscretos: TListaDeCosas; enganchar_promediando: boolean;
  uniformizar_promediando: string);

var

  //Guarda los indices en self de las variables comunes a ambos CFs
  xr_varsComunes, xd_varsComunes: TDAofNInt;
  //Guarda los indices en CFaux de las variables comunes a ambos CFs
  xr_varsComunesAux, xd_varsComunesAux: TDAofNInt;
  costoAux: NReal;

  desde: TFecha;

  i, j, nVarsComunes: integer;
  finBarridoEstrellas: boolean;
  kpr, alfa, beta: NReal;
  kp1, kp2: integer;
  encontre: boolean;
  {$IFDEF DBG}
  fDbg: Textfile;
  {$ENDIF}
  // Desaparecida significa que Está En CFAux y no en Self.
  cnt_desaparecidas_continuas, cnt_desaparecidas_discretas: integer;
  k_desaparecidas_continuas, k_desaparecidas_discretas: TDAOfNInt;
  cnt_: integer;
  encontradas: array of boolean;
  contadores_continuas, contadores_discretas: TDAOfNInt;
  k: integer;
  recorriendo_desaparecidas: boolean;
  hay_desaparecidas: boolean;

begin
  desde := self.fechaFin;

  //kpr es la cantidad de pasos desde el inicio de CFaux hasta "desde.dt"
  //con el paso de tiempo de aux
  kpr := (desde.dt - CFaux.fechaIni.dt) * 24.0 / CFaux.horasDelPaso + 1;
  alfa := frac(kpr);
  beta := 1 - alfa;
  kp1 := trunc(kpr);
  kp2 := kp1 + 1;

  if not (CFaux is TAdminEstados_CFMPUTE) then
    if (kp1 <= 0) or (kp2 > high(CFAux.constelacion_.fcosto)) then
      raise Exception.Create(
        'TAdminEstados.InicializarFrameFinal: se desea enganchar el ' +
        desde.AsStr + ' y el archivo de costo futuro con que desea enganchar va desde el '
        + CFaux.fechaIni.AsStr + ' hasta el ' + CFaux.fechaFin.AsStr +
        '.'#10'La fecha de enganche debe estar contenida dentro del período de optimización del archivo CF.bin');

  //Identifico las variables reales comunes a ambos CFs
  setLength(xr_varsComunes, length(xr_def));
  setLength(xr_varsComunesAux, length(CFaux.xr_def));
  setlength(encontradas, length(CFaux.xr_def));
  nVarsComunes := 0;
  cnt_desaparecidas_continuas := length(CFaux.xr_def);
  for j := 0 to high(CFaux.xr_def) do
  begin  // buscamos en CFaux si hay una con igual nombre
    encontradas[j] := False;
    for i := 0 to high(xr_def) do
    begin // para cada variable del CF
      if xr_def[i].nombre = CFaux.xr_def[j].nombre then
      begin
        xr_varsComunes[nVarsComunes] := i;
        xr_varsComunesAux[nVarsComunes] := j;
        Inc(nVarsComunes);
        Dec(cnt_desaparecidas_continuas);
        encontradas[j] := True;
        break;
      end;
    end;
  end;

  setlength(k_desaparecidas_continuas, cnt_desaparecidas_continuas);
  cnt_ := 0;
  for j := 0 to high(CFaux.xr_def) do
    if not encontradas[j] then
    begin
      k_desaparecidas_continuas[cnt_] := j;
      Inc(cnt_);
    end;


  if nVarsComunes < Length(xr_varsComunes) then
    if nVarsComunes <> 0 then
      xr_varsComunes := copy(xr_varsComunes, 0, nVarsComunes)
    else
      xr_varsComunes := nil;

  if nVarsComunes < Length(xr_varsComunesAux) then
    if nVarsComunes <> 0 then
      xr_varsComunesAux := copy(xr_varsComunesAux, 0, nVarsComunes)
    else
      xr_varsComunesAux := nil;

  cnt_desaparecidas_discretas := length(CFaux.xd_def);
  setlength(encontradas, length(CFaux.xd_def));
  //Identifico las variables discretas comunes a ambos CFs
  SetLength(xd_varsComunes, length(xd_def));
  SetLength(xd_varsComunesAux, length(CFaux.xd_def));
  nVarsComunes := 0;
  for j := 0 to high(CFaux.xd_def) do
  begin
    encontradas[j] := False;
    for i := 0 to high(xd_def) do
    begin
      if xd_def[i].nombre = CFaux.xd_def[j].nombre then
      begin
        xd_varsComunes[nVarsComunes] := i;
        xd_varsComunesAux[nVarsComunes] := j;
        Inc(nVarsComunes);
        Dec(cnt_desaparecidas_discretas);
        encontradas[j] := True;
        break;
      end;
    end;
  end;

  setlength(k_desaparecidas_discretas, cnt_desaparecidas_discretas);
  cnt_ := 0;
  for j := 0 to high(CFaux.xd_def) do
    if not encontradas[j] then
    begin
      k_desaparecidas_discretas[cnt_] := j;
      Inc(cnt_);
    end;


  if nVarsComunes < Length(xd_varsComunes) then
    if nVarsComunes <> 0 then
      xd_varsComunes := copy(xd_varsComunes, 0, nVarsComunes)
    else
      xd_varsComunes := nil;

  if nVarsComunes < Length(xd_varsComunesAux) then
    if nVarsComunes <> 0 then
      xd_varsComunesAux := copy(xd_varsComunesAux, 0, nVarsComunes)
    else
      xd_varsComunesAux := nil;

  hay_desaparecidas := (cnt_desaparecidas_continuas + cnt_desaparecidas_discretas) > 0;

  setEstrellaCERO; // iniciamos barrido

  //Resolver los enganches
  //Fijamos los valores especificados de las variables continuas en el CFAux
  for j := 0 to high(CFaux.xr_def) do
  begin
    encontre := False;
    for i := 0 to enganchesContinuos.Count - 1 do
    begin
      if CFaux.xr_def[j].nombre = TEngancheCFReal(enganchesContinuos[i])
        .nombreVar then
      begin
        CFaux.xr[j] := TEngancheCFReal(enganchesContinuos[i]).valor;
        encontre := True;
        break;
      end;
    end;
    if not encontre then  //Si no me especificaron su valor, la pongo en el valor medio
      CFaux.xr[j] := CFAux.xr_def[j].xmed;
  end;

  //Fijamos los valores especificados de las variables discretas en el CFAux
  for j := 0 to high(CFaux.xd_def) do
  begin
    encontre := False;
    for i := 0 to enganchesDiscretos.Count - 1 do
    begin
      if CFaux.xd_def[j].nombre = TEngancheCFEntero(enganchesDiscretos[i])
        .nombreVar then
      begin
        CFaux.xd[j] := TEngancheCFEntero(enganchesDiscretos[i]).valor;
        encontre := True;
        break;
      end;
    end;
    if not encontre then
      //Si no me especificaron su valor, la pongo en el valor mínimo
      CFaux.xd[j] := CFAux.xd_def[j].x[0];
  end;

  {$IFDEF DBG}
  AssignFile(fDbg, 'inicializarFrameFinalDbg.xlt');
  rewrite(fDbg);
  {$ENDIF}

  if hay_desaparecidas and enganchar_promediando then
  begin
    // si se va a precisar iterar en los estados perdidos de CFAux ponemos
    // los contadores de las discretizaciones para poder iterar.
    setlength(contadores_continuas, cnt_desaparecidas_continuas);
    setlength(contadores_discretas, cnt_desaparecidas_discretas);
    for k := 0 to high(contadores_continuas) do
      contadores_continuas[k] := CFaux.xr_def[k_desaparecidas_continuas[k]].NPuntos;
    for k := 0 to high(contadores_discretas) do
      contadores_continuas[k] := CFaux.xd_def[k_desaparecidas_discretas[k]].NPuntos;
  end;

  repeat
    //Iteramos en los estados de CF
    SetEstadoToEstrella; // cargamos las variables de acuerdo con la estrella

    /// $Y_j = $X_k
    for i := 0 to High(xr_varsComunes) do
      CFaux.xr[xr_varsComunesAux[i]] := xr[xr_varsComunes[i]];
    for i := 0 to High(xd_varsComunes) do
      CFaux.xd[xd_varsComunesAux[i]] := xd[xd_varsComunes[i]];

    if (hay_desaparecidas and enganchar_promediando) then
    begin
      costoAux := 0;
      cnt_ := 0;
      recorriendo_desaparecidas := True;
      CFaux.SetEstrellaCERO_indexada(contadores_continuas, contadores_discretas);
      while recorriendo_desaparecidas do
      begin
        // fijamos los valores de las indexaddas
        for i := 0 to high(k_desaparecidas_continuas) do
          CFaux.xr[k_desaparecidas_continuas[i]] := contadores_continuas[i];
        for i := 0 to high(k_desaparecidas_discretas) do
          CFaux.xr[k_desaparecidas_discretas[i]] := contadores_discretas[i];
        if abs(alfa) > AsumaCero then
          costoAux := costoAux + CFaux.costoContinuo(kp1) * beta +
            CFaux.costoContinuo(kp2) * alfa
        else
          costoAux := costoAux + CFaux.costoContinuo(kp1);
        Inc(cnt_);

        recorriendo_desaparecidas :=
          CFAux.IncEstrella_indexada(contadores_continuas,
          contadores_discretas, k_desaparecidas_continuas,
          k_desaparecidas_discretas);

      end;
      costoAux := costoAux / cnt_;
    end
    else
    begin
      if abs(alfa) > AsumaCero then
        costoAux := CFaux.costoContinuo(kp1) * beta +
          CFaux.costoContinuo(kp2) * alfa
      else
        costoAux := CFaux.costoContinuo(kp1);
    end;


    constelacion_.set_costo_estrella(high(constelacion_.fcosto),
      ordinalEstrellaActual, costoAux);


  {$IFDEF DBG}
    Write(fDbg, FloatToStrF(costoAux, ffGeneral, 6, 2), #9);
  {$ENDIF}
    finBarridoEstrellas := not IncEstrella;
  until (finBarridoEstrellas);


  {$IFDEF DBG}
  CloseFile(fDbg);
  {$ENDIF}

  // Ahora si hay alguna en uniformizar_promediando que
  // no haya desaparecido calculo el promedio y se lo impongo
  uniformizar_ultimo_frame_en(uniformizar_promediando);

end;



// (*****
procedure TAdminEstados.InicializarFrameFinal_mapeo_evaluador(
  const CFaux: TAdminEstados; mapeo_str, uniformizar_promediando: string;
  sala: TCosa);

var
  costoAux: NReal;
  desde: TFecha;
  i: integer;
  finBarridoEstrellas: boolean;
  kpr, alfa, beta: NReal;
  kp1, kp2: integer;
  // Desaparecida significa que Está En CFAux y no en Self.
  cnt_desaparecidas_continuas, cnt_desaparecidas_discretas: integer;
  k_desaparecidas_continuas, k_desaparecidas_discretas: TDAOfNInt;

  cnt_y: integer;
  xrs, xds, yrs, yds: array of TVar;
  iyrs, iyds: TDAOfNInt;

  cnt_: integer;
  contadores_continuas, contadores_discretas: TDAOfNInt;
  k: integer;
  recorriendo_desaparecidas: boolean;
  hay_desaparecidas: boolean;

  Evaluador: TEvaluadorExpresionesSimples;

  aVar: TVar;

  s, ss: string;

  aScript: TExprLst;
  sdj: TSalaDeJuego;
  rval: double;

begin
  sdj:= Sala as TSalaDeJuego;
  s:= MemoToStr( mapeo_str );
  desde := self.fechaFin;

  //kpr es la cantidad de pasos desde el inicio de CFaux hasta "desde.dt"
  //con el paso de tiempo de aux
  kpr := (desde.dt - CFaux.fechaIni.dt) * 24.0 / CFaux.horasDelPaso + 1;
  alfa := frac(kpr);
  beta := 1 - alfa;
  kp1 := trunc(kpr);
  kp2 := kp1 + 1;

  if not (CFaux is TAdminEstados_CFMPUTE) then
    if (kp1 <= 0) or (kp2 > high(CFAux.constelacion_.fcosto)) then
      raise Exception.Create(
        'TAdminEstados.InicializarFrameFinal: se desea enganchar el ' +
        desde.AsStr + ' y el archivo de costo futuro con que desea enganchar va desde el '
        + CFaux.fechaIni.AsStr + ' hasta el ' + CFaux.fechaFin.AsStr +
        '.'#10'La fecha de enganche debe estar contenida dentro del período de optimización del archivo CF.bin');


  setEstrellaCERO; // iniciamos barrido
  SetEstadoToEstrella; // cargamos las variables de acuerdo con la estrella
  sdj.PosicionarseEnEstrellita;
  evaluador := TEvaluadorExpresionesSimples.Create;
  sala.AgregarDefinicionesEvaluador(Evaluador);

  //inicializamos variables "X" en entorno de cálculo
  for i := 0 to nVarsContinuas - 1 do
  begin
    ss:= '$X_' + xr_Def[i].nombre + ':= 0.0';
    if not evaluador.Ejecutar( rval, ss ) then
      raise Exception.Create('TAdminEstados.InicializarFrameFinal, imposible evaluar: '+ss );
  end;

  for i := 0 to nVarsDiscretas - 1 do
  begin
    ss:= '$X_' + xd_Def[i].nombre + ':= 0';
    if not evaluador.Ejecutar( rval, ss ) then
      raise Exception.Create('TAdminEstados.InicializarFrameFinal, imposible evaluar: '+ss );
  end;


  aScript := evaluador.GetExprLst(s);
  setlength(xrs, nVarsContinuas);
  setlength(xds, nVarsDiscretas);

  SetEstadoToEstrella; // cargamos las variables de acuerdo con la estrella
  //Cargamos variables "X" según estado actual
  for i := 0 to nVarsContinuas - 1 do
  begin
    aVar := evaluador.FindVar('$X_' + xr_Def[i].nombre);
    aVar.val.Val_F := xr[i];
    xrs[i] := aVar;
  end;
  for i := 0 to nVarsDiscretas - 1 do
  begin
    aVar := evaluador.FindVar('$X_' + xd_Def[i].nombre);
    aVar.val.Val_I := xd[i];
    xds[i] := aVar;
  end;
  aScript.evaluar;

  setlength(k_desaparecidas_continuas, length(CFaux.xr_def));
  cnt_desaparecidas_continuas := 0;
  cnt_y := 0;
  //leo los valores "Y" resultantes. Si no encuentro alguna variable la marco como
  // desaparecida.
  setlength(yrs, CFAux.nVarsContinuas);
  setlength(iyrs, CFAux.nVarsContinuas);
  for i := 0 to CFAux.nVarsContinuas - 1 do
  begin
    aVar := evaluador.FindVar('$Y_' + CFAux.xr_Def[i].nombre);
    if aVar <> nil then
    begin
      yrs[cnt_y] := aVar;
      iyrs[cnt_y] := i;
      Inc(cnt_y);
    end
    else
    begin
      k_desaparecidas_continuas[cnt_desaparecidas_continuas] := i;
      Inc(cnt_desaparecidas_continuas);
    end;
  end;

  setlength(yrs, cnt_y);
  setlength(iyrs, cnt_y);
  setlength(k_desaparecidas_continuas, cnt_desaparecidas_continuas);

  setlength(k_desaparecidas_discretas, length(CFaux.xd_def));
  cnt_y := 0;
  cnt_desaparecidas_discretas := 0;

  setlength(yds, CFAux.nVarsDiscretas);
  setlength(iyds, CFAux.nVarsDiscretas);
  for i := 0 to CFAux.nVarsDiscretas - 1 do
  begin
    aVar := evaluador.FindVar('$Y_' + CFAux.xd_Def[i].nombre);
    if aVar <> nil then
    begin
      yds[cnt_y] := aVar;
      iyds[cnt_y] := i;
      Inc(cnt_y);
    end
    else
    begin
      k_desaparecidas_discretas[cnt_desaparecidas_discretas] := i;
      Inc(cnt_desaparecidas_discretas);
    end;
  end;

  setlength(yds, cnt_y);
  setlength(iyds, cnt_y);
  setlength(k_desaparecidas_discretas, cnt_desaparecidas_discretas);

  hay_desaparecidas := (cnt_desaparecidas_continuas + cnt_desaparecidas_discretas) > 0;

  if hay_desaparecidas then
  begin
    // si se va a precisar iterar en los estados perdidos de CFAux ponemos
    // los contadores de las discretizaciones para poder iterar.
    setlength(contadores_continuas, cnt_desaparecidas_continuas);
    setlength(contadores_discretas, cnt_desaparecidas_discretas);
    for k := 0 to high(contadores_continuas) do
      contadores_continuas[k] := CFaux.xr_def[k_desaparecidas_continuas[k]].NPuntos;
    for k := 0 to high(contadores_discretas) do
      contadores_discretas[k] := CFaux.xd_def[k_desaparecidas_discretas[k]].NPuntos;
  end;

  repeat
    //Iteramos en los estados de CF
    SetEstadoToEstrella; // cargamos las variables de acuerdo con la estrella
    sdj.PosicionarseEnEstrellita;

    //Cargamos variables "X" según estado actual
    for i := 0 to nVarsContinuas - 1 do
      xrs[i].val.Val_F := xr[i];
    for i := 0 to nVarsDiscretas - 1 do
      xds[i].val.Val_I := xd[i];

    // cargo y ejecuto las funciones Y=f(X)
    //    evaluador.Ejecutar(s);
    aScript.evaluar;

    // leemos los resultados
    for i := 0 to high(yrs) do
    begin
//   writeln( iyrs[i], ': ', yrs[i].ValAsFloat );
      CFAux.xr[iyrs[i]] := yrs[i].ValAsFloat;
    end;

    for i := 0 to high(yds) do
      CFAux.xd[iyds[i]] := yds[i].ValAsInt;

    if (hay_desaparecidas) then
    begin
      costoAux := 0;
      cnt_ := 0;
      recorriendo_desaparecidas := True;
      CFaux.SetEstrellaCERO_indexada(contadores_continuas, contadores_discretas);
      while recorriendo_desaparecidas do
      begin
        // fijamos los valores de las indexaddas
        for i := 0 to high(k_desaparecidas_continuas) do
          CFaux.xr[k_desaparecidas_continuas[i]] := contadores_continuas[i];
        for i := 0 to high(k_desaparecidas_discretas) do
          CFaux.xr[k_desaparecidas_discretas[i]] := contadores_discretas[i];
        if abs(alfa) > AsumaCero then
          costoAux := costoAux + CFaux.costoContinuo(kp1) * beta +
            CFaux.costoContinuo(kp2) * alfa
        else
          costoAux := costoAux + CFaux.costoContinuo(kp1);
        Inc(cnt_);

        recorriendo_desaparecidas :=
          CFAux.IncEstrella_indexada(contadores_continuas,
          contadores_discretas, k_desaparecidas_continuas,
          k_desaparecidas_discretas);

      end;
      costoAux := costoAux / cnt_;
    end
    else
    begin
      if abs(alfa) > AsumaCero then
        costoAux := CFaux.costoContinuo(kp1) * beta +
          CFaux.costoContinuo(kp2) * alfa
      else
        costoAux := CFaux.costoContinuo(kp1);
    end;
    constelacion_.set_costo_estrella(high(constelacion_.fcosto),
      ordinalEstrellaActual, costoAux);
    finBarridoEstrellas := not IncEstrella;
  until (finBarridoEstrellas);

  setlength(yrs, 0);
  setlength(iyrs, 0);
  setlength(k_desaparecidas_continuas, 0);
  setlength(yds, 0);
  setlength(iyds, 0);
  setlength(k_desaparecidas_discretas, 0);
  setlength(contadores_continuas, 0);
  setlength(contadores_discretas, 0);

  evaluador.Free;

  // Ahora si hay alguna en uniformizar_promediando que
  // no haya desaparecido calculo el promedio y se lo impongo
  uniformizar_ultimo_frame_en(uniformizar_promediando);
end;

//***)


procedure TAdminEstados.uniformizar_ultimo_frame_en(uniformizar_promediando: string);
var
  v_uniformizar: TStringList;
  clasificadas_r, clasificadas_d: array of boolean;
  h, j, k: integer;
  cnt_r: integer;
  cnt_d: integer;

  a_uniformizar_r, otras_r, a_uniformizar_d, otras_d: TDAofNInt;
  u_r, u_d, o_r, o_d: TDAOfNInt;
  loop_otras: boolean;
  m: NREal;
  loop_uniformizar: boolean;
  cnt_: integer;
begin
  if trim(uniformizar_promediando) = '' then
    exit;

  // creamos una lista con el nombre de las variables
  v_uniformizar := TStringList.Create;
  v_uniformizar.Delimiter := ';';
  v_uniformizar.DelimitedText := uniformizar_promediando;

  if v_uniformizar.Count = 0 then
    exit;

  // armo el grupo de los a_uniformizar y el grupo otras
  setlength(clasificadas_r, length(xr_def));
  setlength(clasificadas_d, length(xd_def));

  for k := 0 to high(clasificadas_r) do
    clasificadas_r[k] := False;
  for k := 0 to high(clasificadas_d) do
    clasificadas_d[k] := False;

  cnt_r := 0;
  cnt_d := 0;

  for k := 0 to v_uniformizar.Count - 1 do
  begin
    j := indexOf_Continua(v_uniformizar[k]);
    if j >= 0 then
    begin
      clasificadas_r[j] := True;
      Inc(cnt_r);
    end
    else
    begin
      j := indexOf_Discreta(v_uniformizar[k]);
      if j < 0 then
        raise Exception.Create('No enonctré: ' + v_uniformizar[k] +
          ', en la función de CF. Imposible aplicar uniformizador sobre dicha variable');
      clasificadas_d[j] := True;
      Inc(cnt_d);
    end;
  end;

  setlength(a_uniformizar_r, cnt_r);
  setlength(otras_r, length(xr_def) - cnt_r);

  j := 0;
  h := 0;
  for k := 0 to high(clasificadas_r) do
    if clasificadas_r[k] then
    begin
      a_uniformizar_r[j] := k;
      Inc(j);
    end
    else
    begin
      otras_r[h] := k;
      Inc(h);
    end;

  setlength(a_uniformizar_d, cnt_d);
  setlength(otras_d, length(xd_def) - cnt_d);
  j := 0;
  h := 0;
  for k := 0 to high(clasificadas_d) do
    if clasificadas_d[k] then
    begin
      a_uniformizar_d[j] := k;
      Inc(j);
    end
    else
    begin
      otras_d[h] := k;
      Inc(h);
    end;

  setlength(o_r, length(otras_r));
  setlength(o_d, length(otras_d));
  setlength(u_r, length(a_uniformizar_r));
  setlength(u_d, length(a_uniformizar_d));

  SetEstrellaCERO_indexada(o_r, o_d);
  loop_otras := True;
  while loop_otras do
  begin
    SetEstrella_Indexada(o_r, o_d, otras_r, otras_d);

    // calculamos el promedio
    m := 0;
    SetEstrellaCERO_indexada(u_r, u_d);
    loop_uniformizar := True;
    cnt_ := 0;
    while loop_uniformizar do
    begin
      SetEstrella_Indexada(u_r, u_d, a_uniformizar_r, a_uniformizar_d);
      m := m + costoEstrella(high(constelacion_.fcosto));
      Inc(cnt_);
      loop_uniformizar := IncEstrella_indexada(u_r, u_d, a_uniformizar_r,
        a_uniformizar_d);
    end;
    m := m / cnt_;

    // imponemos el promedio calculado
    SetEstrellaCERO_indexada(u_r, u_d);
    loop_uniformizar := True;
    cnt_ := 0;
    while loop_uniformizar do
    begin
      SetEstrella_Indexada(u_r, u_d, a_uniformizar_r, a_uniformizar_d);
      SetCostoEstrella(high(constelacion_.fCosto), m);
      loop_uniformizar := IncEstrella_indexada(u_r, u_d, a_uniformizar_r,
        a_uniformizar_d);
    end;


    loop_otras := IncEstrella_Indexada(o_r, o_d, otras_r, otras_d);
  end;

end;

procedure TAdminEstados.setEstrellaCERO;
begin
  vclear(estrella_kr);
  vclear(estrella_kd);
  ordinalEstrellaActual := 0;
end;

procedure TAdminEstados.SetEstrellaCERO_indexada(
  var estrella_idx_r, estrella_idx_d: TDAOfNint);
begin
  vclear(estrella_idx_r);
  vclear(estrella_idx_d);
end;


procedure TAdminEstados.SetEstrella_Indexada(vkr, vkd, idx_r, idx_d: TDAOfNInt);
var
  i: integer;
begin
  for i := 0 to high(idx_r) do
    estrella_kr[idx_r[i]] := vkr[i];
  for i := 0 to high(idx_d) do
    estrella_kd[idx_d[i]] := vkd[i];
end;


procedure TAdminEstados.AcumCostoEstrella(kPuntoT: integer; valCosto: NReal);
begin
  constelacion_.acum_costo_estrella(kPuntoT, estrella_kr, estrella_kd, valCosto);
  //  constelacion.acum_costo_estrella( kPuntoT, ordinalEstrellaActual, valCosto );
end;

procedure TAdminEstados.SetCostoEstrella(kPuntoT: integer; valCosto: NReal);
begin
  constelacion_.set_costo_estrella(kPuntoT, estrella_kr, estrella_kd, valCosto);
  //  constelacion.set_costo_estrella( kPuntoT, ordinalEstrellaActual, valCosto );
end;

function TAdminEstados.costoEstrella(kpuntoT: integer): NReal;
begin
  Result := constelacion_.costo_estrella(kpuntoT, estrella_kr, estrella_kd);
  //  result:= constelacion.costo_estrella(kpuntoT, ordinalEstrellaActual);
end;

function TAdminEstados.costoContinuo(kPuntoT: integer): NReal;
begin
  if deterministico then
    if kPuntoT < nPuntosT then
      Result := ControladorDeterministico.GradInfos[kPuntoT - 1].CF
    else
      Result := constelacion_.costo_continuo(1, xr, xd)
  else
    Result := constelacion_.costo_continuo(kpuntoT, xr, xd);
end;

function TAdminEstados.GetEstado_XLT: string;
var
  k: integer;
  res: string;
begin
  res := 'xr:';
  for k := 0 to high(xr) do
    res := res + #9 + FloatToStr(xr[k]);
  res := res + #9 + 'xd:';
  for k := 0 to high(xd) do
    res := res + #9 + IntToStr(xd[k]);
  Result := res;
end;

function TAdminEstados.ChequearCompatibilidad_CFAux(
  const CFAux: TAdminEstados): boolean;
var
  msg: string;


  procedure apm(s: string);
  begin
    if msg <> '' then
      msg := msg + ', ';
    msg := msg + s;
  end;

begin
  msg := '';
  // chequear ventana temporal
  if nPuntosT <> CFAux.nPuntosT then
    apm('nPuntosT <> CFAux.nPuntosT');

  if fechaIni.dt <> CFAux.fechaIni.dt then
    apm('fechaIni.dt <> CFAux.fechaIni.dt');

  if fechaFin.dt <> CFAux.fechaFin.dt then
    apm('fechaFin.dt <> CFAux.fechaFin.dt');

  if horasDelPaso <> CFAux.horasDelPaso then
    apm('horasDelPaso <> CFAux.horasDelPaso');


  // dimensionado
  if nVarsContinuas <> CFAux.nVarsContinuas then
    apm('nVarsContinuas <> CFAux.nVarsContinuas');
  if nVarsDiscretas <> CFAux.nVarsDiscretas then
    apm('nVarsDiscretas <> CFAux.nVarsDiscretas');

  if msg <> '' then
  begin
    Result := False;
    raise Exception.Create('CFAux incompatible!!! : ' + msg);

  end
  else
    Result := True;
end;


// Retorna una TStringList con los nombres de las variables de estado
function TAdminEstados.VariablesDeEstado_lst: TStringList;
var
  k: integer;
  res: TStringList;
begin
  res := TStringList.Create;
  for k := 0 to nVarsContinuas - 1 do
    res.add(xr_def[k].nombre);
  for k := 0 to nVarsDiscretas - 1 do
    res.add(xd_def[k].nombre);
  Result := res;
end;

procedure TAdminEstados.ActualizarEstadoGlobal(kPaso: integer);
begin
  // por ahora nada, en un futuro podria calcularse el gradiente??
end;



procedure TAdminEstados.ClonarCursorParasito(res: TAdminEstados);
var
    k: integer;

begin
  // Copiar Encabezado
  res.fechaIni := TFecha.Create_Clone(fechaIni);
  res.FechaFin := TFecha.Create_Clone(fechaFin);
  res.horasDelPaso := HorasDelPaso;
  for k := 0 to high(res.xr_def) do
    res.xr_def[k] := xr_def[k].clonar;
  for k := 0 to high(res.xd_def) do
    res.xd_def[k] := xd_def[k].clonar;


  // Copiar Cursor
  for k := 0 to high(res.xr) do
    res.xr[k] := xr[k];
  for k := 0 to high(res.xd) do
    res.xd[k] := xd[k];

  for k := 0 to high(estrella_kr) do
    res.estrella_kr[k] := estrella_kr[k];
  for k := 0 to high(estrella_kd) do
    res.estrella_kd[k] := estrella_kd[k];
  res.ordinalEstrellaActual := ordinalEstrellaActual;

end;

procedure TAdminEstados.ClonarInfoadParasito(res: TAdminEstados);
begin
  res.constelacion_ := constelacion_.CreateParasito;
  res.ControladorDeterministico:= ControladorDeterministico;
end;


procedure TAdminEstados.mantoContinuo(var res: TDAOfNReal; jBase: integer;
  const Manto: TMatOfNReal);
begin
  constelacion_.manto_continuo(xr, xd, res, jBase, Manto);
end;

procedure TAdminEstados.devxr_estrella_(irx: integer; kpuntoT: integer; out
  dCdx_Inc, dCdx_Dec: NReal; out resCod: integer);
begin
  constelacion_.dev_costo_estrella_(kpuntoT, estrella_kr, estrella_kd, irx,
    dCdx_Inc, dCdx_Dec, resCod);
end;

procedure TAdminEstados.devxr_estrella_20_(irx: integer; kpuntoT: integer; out
  dCdx_Inc, dCdx_Dec: NReal);
var
  codRes: integer;
  //  xrpos: NReal;
begin
  devxr_estrella_(irx, kpuntoT, dCdx_Inc, dCdx_Dec, codRes);

  if codRes <> 0 then
  begin
    if codRes < 0 then
      dCdx_Dec := dCdx_Inc * 2
    else
      dCdx_Inc := 0;
  end;
end;




procedure TAdminEstados.LlenarConFrameFinal;
var
  k, j: integer;
  a: NReal;
begin

  // k puede ir de 1 a nPuntosT - 2
  // k = nPuntosT - 2 corresponde al fin de la última etapa.
  // k = 1 corresponde al inicio de la primer etapa
  // k = 0 no se utiliza

  // para cada estrella
  for j := 0 to nEstrellasPorPuntoT - 1 do
  begin
    // valor en el último frame
    a := constelacion_.fcosto[nPuntosT - 1][j];
    for k := 1 to nPuntosT - 2 do
      constelacion_.fcosto[k][j] := a;
    // lo copio en las estrellas de los frames anteriores
  end;
end;

procedure TAdminEstados.devxr_continuo(irx: integer; kpuntoT: integer;
  out dCdx_Inc, dCdx_Dec: NReal; out resCod: integer; out xrpos: NReal);
begin
  if deterministico then
  begin
    if kPuntoT < nPuntosT then
    begin
      dCdx_Inc := ControladorDeterministico.GradInfos[kPuntoT - 1].Grad_Xr[irx];
      dCdx_Dec := dcdx_Inc;
      resCod := 0;
      xrpos := 0;
    end
    else
      constelacion_.dev_costo_continuo(1, xr, xd, irx, dCdx_Inc, dCdx_Dec,
        resCod, xrpos);
  end
  else
    constelacion_.dev_costo_continuo(kpuntoT, xr, xd, irx, dCdx_Inc, dCdx_Dec,
      resCod, xrpos);
end;


procedure TAdminEstados.devxr_continuo_20(irx: integer; kpuntoT: integer; out
  dCdx_Inc, dCdx_Dec: NReal);

var
  codRes: integer;
  xrpos: NReal;

begin
  devxr_continuo(irx, kpuntoT, dCdx_Inc, dCdx_Dec, codRes, xrpos);

  if codRes <> 0 then
  begin
    if codRes < 0 then
    begin
      if xrpos > 0 then
      begin
        dCdx_Dec := dCdx_Dec * xrpos + (1 - xrpos) * dCdx_Inc * 2;

        // me aseguro la convexidad.
        dCdx_Dec := min(dCdx_Inc, dCdx_Dec);
      end
      else
        dCdx_Dec := dCdx_Inc * 2;
    end
    else
    begin
      if xrpos < 1 then
      begin
        // me aseguro la convexidad
        dCdx_Inc := max(dCdx_Dec, dCdx_Inc);
      end
      else
        dCdx_Inc := 0;
    end;
  end;

end;

function TAdminEstados.deltaCosto_vxd_estrella_(ird: integer;
  kpuntoT: integer; delta_xd: integer): NReal;
begin
    Result := constelacion_.delta_costo_estrella_dx_(kPuntoT, estrella_kr,
      estrella_kd, ird, delta_xd);
end;

function TAdminEstados.deltaCosto_vxd_continuo(ird: integer; kpuntoT: integer;
  delta_xd: integer): NReal;
var
  res: NReal;
begin
  if deterministico then
    if kPuntoT < nPuntosT then
      Res := ControladorDeterministico.GradInfos[kPuntoT - 1].Grad_Xr[ird]
    else
      Res := constelacion_.delta_costo_continuo_dx(1, xr, xd, ird, delta_xd)
  else
    Res := constelacion_.delta_costo_continuo_dx(kpuntoT, xr, xd, ird, delta_xd);
  result:= res;
end;

function TAdminEstados.deltaCosto_vxr_continuo(irx: integer; kpuntoT: integer;
  delta_xr: NReal): NReal;
begin
   Result := constelacion_.delta_costo_continuo_rx(kpuntoT, xr, xd, irx, delta_xr);
end;

function TAdminEstados.deltaCosto_vxr_continuo_DosEstados_UTE(
  irx, irx2, kpuntoT: integer; delta_xr, delta_xr2: NReal): NReal;

begin
   Result := constelacion_.delta_costo_continuo_rx_DosEstados_UTE(kPuntoT,
      xr, xd, irx, irx2, delta_xr, delta_xr2);
end;



procedure TAdminEstados.SetEstadoToEstrella;
begin
  constelacion_.coordenadasEstrella_icid(xr, xd, estrella_kr, estrella_kd);
end;


procedure TAdminEstados.SetEstadoToEstrella_indexada(
  vkr, vkd, idx_r, idx_d: TDAOfNInt);
begin
  constelacion_.coordenadasEstrella_icid_indexada(xr, xd, vkr, vkd, idx_r, idx_d);
end;

constructor TAdminEstados.Create(nVarsContinuas, nVarsDiscretas,
  nPasosT: integer);
begin
  inherited Create;
  self.nVarsContinuas := nVarsContinuas;
  self.nVarsDiscretas := nVarsDiscretas;
  //1 porque el de la posicion 0 se tira y otro para almacenar el costo del
  //al final del últimpo paso de tiempo.
  Self.nPuntosT := nPasosT + 2; // o no? decía + 2

  setLength(xr_def, nVarsContinuas);
  setLength(xd_def, nVarsDiscretas);
  setLength(xr, nVarsContinuas);
  setLength(xd, nVarsDiscretas);
  setLength(estrella_kr, nVarsContinuas);
  setLength(estrella_kd, nVarsDiscretas);
  constelacion_ := nil;
  deterministico := False;
  ControladorDeterministico := nil;
  lambda:=TVectR.Create_Init(nVarsContinuas + nVarsDiscretas);
  flg_SoyParasito:= false;
  {$IFDEF PRUEBAS_ENGANCHE}
  flg_usarCFEnganches:=false;
  {$ENDIF}
end;

destructor TAdminEstados.destroy;
var
  k: integer;
begin

  FechaIni.Free;
  fechaFin.Free;

  if xr_def <> nil then
  begin
    for k:= 0 to high( xr_def ) do
      xr_def[k].Free;
    setLength(xr_def, 0);
  end;

  if xd_def <> nil then
  begin
    for k:= 0 to high( xd_def ) do
      xd_def[k].Free;
    setLength(xd_def, 0);
  end;
  setLength(xr, 0);
  setLength(xd, 0);
  setLength(estrella_kr, 0);
  setLength(estrella_kd, 0);

  if constelacion_ <> nil then
  begin
    constelacion_.Free;
    constelacion_ := nil;
  end;

  if ControladorDeterministico <> nil then
  begin
    ControladorDeterministico.Free;
    ControladorDeterministico := nil;
  end;

  lambda.Free;

  inherited destroy;
end;

procedure TAdminEstados.Registrar_Continua(ixr: integer; xmin, xmax: NReal;
  nPuntos: integer; nombre: string; unidades: string);
begin
  if nPuntos < 2 then
    raise Exception.Create('TAdminEstados.Registrar_Continua, Nombre: ' +
      nombre + ' NPuntos :' + IntToStr(nPuntos) + '. Tiene que ser > 1');
  xr_def[ixr] := TDefVarContinua.Create(nombre, unidades, xmin, xmax, nPuntos);
end;

function TAdminEstados.indexOf_Continua(nombre: string): integer;
var
  k: integer;
  buscando: boolean;
begin
  k := 0;
  buscando := True;
  while buscando and (k < length(xr_def)) do
    if xr_def[k].nombre = nombre then
      buscando := False
    else
      Inc(k);
  if buscando then
    Result := -1
  else
    Result := k;
end;

procedure TAdminEstados.RegistrarTraduccion_Continua(ixr: integer;
  //xmin, xmax: NReal; nPuntos: integer;
  const nombre, unidades: string; funcTraduccion: TFuncTraduccion);
var
  i: integer;
begin
  xr_def[ixr].traduccion := TDefVarContinua.Create(nombre, unidades,
    0, 1, xr_def[ixr].nPuntos);
  for i := 0 to high(xr_def[ixr].x) do
    xr_def[ixr].traduccion.x[i] := funcTraduccion(xr_def[ixr].x[i]);
end;

procedure TAdminEstados.Registrar_Discreta(ixd: integer; npuntos: integer;
  const nombre, unidades: string);
begin
  xd_def[ixd] := TDefVarDiscreta.Create(nombre, unidades, Npuntos);
end;


function TAdminEstados.indexOf_Discreta(nombre: string): integer;
var
  k: integer;
  buscando: boolean;
begin
  k := 0;
  buscando := True;
  while buscando and (k < length(xd_def)) do
    if xd_def[k].nombre = nombre then
      buscando := False
    else
      Inc(k);
  if buscando then
    Result := -1
  else
    Result := k;
end;



{
 procedure TAdminEstados.RegsitrarTraduccion_Discreta(ixd: integer;
  // npuntos: integer;
  nombre: string; unidades: string);
 begin
  xd_def[ixd].traduccion := TDefVarDiscreta.Create(nombre, unidades, xd_def[ixd].Npuntos);
 end;
}

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

begin
  self.FechaIni := TFecha.Create_Clone(FechaIni);
  self.fechaFin := TFecha.Create_Clone(fechaFin);
  self.horasDelPaso := horasDelPaso;
  self.deterministico := deterministico;
  self.fActPaso:= fActPaso;

  if not deterministico then
  begin
    Constelacion_ := TConstelacion.Create(xr_def, xd_def, nPuntosT, costoFuturo);
    ControladorDeterministico := nil;
  end
  else
  begin
    if costoFuturo <> nil then
      raise Exception.Create(
        'TAdminEstados.ClearElEspacioTiempo ... deterministico  and ( costofuturo <> nil ) no es posible'
        );
    // creo un solo frame de la constelación para ser usado como FRAME FINAL
    // este frame debe ser llenado con el enganche que corresponda.
    Constelacion_ := TConstelacion.Create(xr_def, xd_def, 2, nil);
    ControladorDeterministico :=
      TControladorDeterministico.Create(length(xr_def), length(xd_def), nPuntosT - 1);
  end;
end;


function TAdminEstados.getDtFromKpunto( kPunto: integer): TDateTime;
begin
  Result:= self.fechaIni.dt + ( kPunto  - 1 ) * self.horasDelPaso/24.0;
end;
function TAdminEstados.getkPuntoFromDT(dt: TDateTime): Integer;
begin
  result:= trunc( ( dt - self.fechaIni.dt + dt_100ms ) / ( self.horasDelPaso / 24.0 )  )+1;
end;



procedure AlInicio;
begin
  registrarClaseDeCosa(TEngancheCFReal.ClassName, TEngancheCFReal);
  registrarClaseDeCosa(TEngancheCFEntero.ClassName, TEngancheCFEntero);

  RegistrarClase_AdminEstados( TAdminEstados );
  RegistrarClase_AdminEstados( TAdminEstados_CFMPUTE );
end;

procedure AlFinal;
begin

end;

initialization
   RegistroClasesAdminEstado:= TListOfClasesAdminEstado.Create;

finalization
   RegistroClasesAdminEstado.Free;
end.
