unit uintermediariocostofuturo;

{$mode delphi}
interface

uses
  Classes, SysUtils, xmatdefs, uestados, umipsimplex, uCosaConNombre, Math, matreal,
  usimplex, uVarDefs, ucosaparticipedemercado, uglobs, uAdministradorDeEstadosMultiPlano,
  uauxiliares;

const
  UMBRAL_HIPERPLANOS_IGUALES = 1e-1;//1e12;//1e-3; PRUEBA
  COTA_CF = 1e10;

type
  {

   Se compara la variable con la restricción y se impone el valor de la variable
   si la restricción es violada.

   }
  TTipoDeRestriccionGrad = (
    IGUAL, // La variable tiene que ser igual al valor de la restricción
    MENOR, // La variable tiene que ser menor que el valor de la restricción
    MAYOR, // La variable tiene que ser mayor que el valor de la restricción
    POSITIVO, // La variable tiene que ser positiva
    NEGATIVO, // La variable tiene que ser negativa
    SUMAR // Se le suma el valor de la restricción a la variable
    );

  TTipoDerivada = (
    DEVXR_CONTINUO, //La variable se deriva con  TAdminEstados.devxr_continuo
    DELTACOSTO_VXR_CONTINUO //La variable se deriva con TAdminEstados.deltaCosto_vxr_continuo
    );


  { TRestriccionGradiente }
  TRestriccionGradiente = class
    tipo: TTipoDeRestriccionGrad;
    valor: NReal;// indica el valor contra el que comparar la variable
    constructor Create(atipo: TTipoDeRestriccionGrad; avalor: NReal);
  end;

  { TMetodoDerivada }
  TMetodoDerivada = class
    tipo: TTipoDerivada;
    //    delta: NReal; // indica el delta de las derivadas
    Cteinc: NReal;
    deltainc: NReal;
    //inc para derivada incremental, dec para derivada decremental (para delta costo continuo)
    Ctedec: NReal;
    deltadec: NReal;
    constructor Create(atipo: TTipoDerivada; aCteinc: NReal; adeltainc: NReal;
      aCtedec: NReal; adeltadec: NReal);
  end;

  { TInfoHiperplano }

  TInfoHiperplano = class
    CF: NReal;
    xr: TDAOfNreal; // estado continuo
    xd: TDAOfNInt; // estado discreto
    gradiente_xr, gradiente_xd: TDAofNReal;

    constructor Create(CF: NReal; xr: TDAOfNreal; // estado continuo
      xd: TDAOfNInt; // estado discreto
      gradiente_xr, gradiente_xd: TDAofNReal);
    destructor Destroy;
  end;

  TDAOfRestriccionGradiente = array of TRestriccionGradiente;

  { TIntermediarioCostoFuturo }

  TIntermediarioCostoFuturo = class(TCosaParticipeDeMercado)

    CF: TAdminEstados; // Administrador de la función de Costo Futuro.

    idx_SPX_xr, idx_SPX_xd: TDAOfNInt; // indices de la posición en el Simplex
    // de cada una de las variables.

    idx_SPX_yr, idx_SPX_yd: TDAOfNInt; // indices de la posición en el Simplex
    // de cada una de las restricciones.

    ivarCFSPX, iresCFSPX_base: integer;
    // indice del CF_Xs en el simplex en variable y en restriccion

    restricciones_xr, restricciones_xd: array of TDAOfRestriccionGradiente;

    tipo_derivadas_xr, tipo_derivadas_xd: array of TMetodoDerivada;

    // cada actor puede tener un array de restricciones

    nombres_xr, nombres_xd, unidades_xr, unidades_xd: TDAofString;

    // contador de variable registrada
    // se inicializa a cero con Create y Clear y se incrementa con cada registro
    cnt_var_registrada: integer;

    pubvarlst: TListaVarDefs; // lista de variables pinchables

    listaDeHiperplanos: TList;

    constructor Create;

    procedure PrepararMemoria(Catalogo: TCatalogoReferencias; globs: TGlobs); override;

    function getNombreVar(ivar: integer; var nombre: string): boolean;
    function getNombreRes(ires: integer; var nombre: string): boolean;

    // registra los indices de una variable de estado en el Costo Futuro y en el Simplex y la restriccion sobre el gradiente
    procedure registrarVariableContinua(iCF, iSPX_x, iSPX_y: integer;
      restricciones: TDAOfRestriccionGradiente; nombreVar, unidades: string;
      metodoDerivada: TMetodoDerivada);
    procedure registrarVariableDiscreta(iCF, iSPX_x, iSPX_y: integer;
      restricciones: TDAOfRestriccionGradiente; nombreVar, unidades: string;
      metodoDerivada: TMetodoDerivada);

    // trae el gradiente del Costo Futuro en kPaso, además carga el estado proyectado
    // y devuelve el hiperplano
    function calcularGradiente(kPaso: integer; fActPaso: NReal): TInfoHiperplano;


    //procedure calcularEstadoActual(kPaso: integer);

    // cagra el gradiente en en simplex segun los inices definidos en idxCF e idxSPX

    procedure ClearRestricciones;

    procedure prepararpaso_ps; override;
    procedure PubliVars; override;
    procedure opt_nvers(var ivar, {%H-}ivae, ires: integer);
    procedure opt_cargue(s: TMIPSimplex);
    {$IFDEF SPXCONLOG}
    procedure spx_NombrarVariables(s: TSimplex; cnt_vars, cnt_ress: integer);
    {$ENDIF}

    function aplicarRestricciones(restricciones: TDAOfRestriccionGradiente;
      valorOriginal: NReal): NReal;

    // revisa si hay un hiperplano nuevo que agregar, y solo lo agrega si no lo tenía
    function opt_NecesitoIterar: boolean;

    //  agrega el hiperplano a la lista si no estaba, devuelve true si lo agrego
    function agregarSiNoExiste(xInfoHP: TInfoHiperplano): boolean;

    procedure getLambdas(s: TMIPSimplex);

    destructor destroy; override;

  private
    NContinuas, NDiscretas: integer;

  end;



implementation

{ TMetodoDerivada }

constructor TMetodoDerivada.Create(atipo: TTipoDerivada; aCteinc: NReal;
  adeltainc: NReal; aCtedec: NReal; adeltadec: NReal);
begin
  tipo := atipo;
  Cteinc := aCteinc;
  deltainc := adeltainc;
  Ctedec := aCtedec;
  deltadec := adeltadec;
end;

{ TInfoHiperplano }

constructor TInfoHiperplano.Create(CF: NReal; xr: TDAOfNreal;
  xd: TDAOfNInt; gradiente_xr, gradiente_xd: TDAofNReal);
begin
  self.CF := CF;
  self.xr := xr;
  self.xd := xd;
  self.gradiente_xr := gradiente_xr;
  self.gradiente_xd := gradiente_xd;

end;

destructor TInfoHiperplano.Destroy;
begin
  // no puese hacer esto porque le estoy dando punteros
  //setlength( xr, 0 );
  //setlength( xd, 0 );
  //setlength( gradiente_xr, 0 );
  //setlength( gradiente_xd, 0 );
end;

function TIntermediarioCostoFuturo.aplicarRestricciones(
  restricciones: TDAOfRestriccionGradiente; valorOriginal: NReal): NReal;
var
  valorRes: NReal;
  tipoRes: TTipoDeRestriccionGrad;
  res: NReal;
  kRestriccion, NRestricciones: integer;
  aRestriccion: TRestriccionGradiente;
begin
  res := 0;
  NRestricciones := Length(restricciones);

  for kRestriccion := 0 to NRestricciones - 1 do
  begin
    aRestriccion := restricciones[kRestriccion];
    if aRestriccion <> nil then
    begin
      valorRes := aRestriccion.valor;
      tipoRes := aRestriccion.tipo;
      case tipoRes of
        MAYOR: res := max(valorOriginal, valorRes);
        MENOR: res := min(valorOriginal, valorRes);
        IGUAL: res := valorRes;
        POSITIVO: res := max(valorOriginal, 0);
        NEGATIVO: res := min(valorOriginal, 0);
        SUMAR: res := valorOriginal + valorRes;
      end;
    end
    else
    begin
      res := valorOriginal;
    end;
  end;

  Result := res;
end;

function TIntermediarioCostoFuturo.opt_NecesitoIterar: boolean;
var
  aHP: TInfoHiperplano;
begin
  aHP := calcularGradiente(globs.kPaso_Opt + 1, globs.fActPaso);
  if not (agregarSiNoExiste(aHP)) then
  begin
    aHP.Free;
    Result := False;
  end
  else
    Result := True;
end;

function TIntermediarioCostoFuturo.agregarSiNoExiste(xInfoHP:
  TInfoHiperplano): boolean;
var
  xB, aB, xVar, aVar: Nreal;
  kHiperplano, NHiperplanos, kVariableContinua, kVariableDiscreta: integer;
  aInfoHP: TInfoHiperplano;
  sonIguales, xInfoYaExiste: boolean;
begin

  // La info de los HP viene en CF(Xo), grad(CF(Xo)) y Xo
  // Para que dor hiperplanos sean iguales, expresados en la forma AX+B deben ser iguales
  // Con la info como viene, la ecuación sería CF(X) = grad(CF(Xo))*X  + CF(Xo) - grad(CF(Xo))*Xo
  // A = grad(CF(Xo)), por lo que los gradientes deben ser iguales.
  // B = CF(Xo) - grad(CF(Xo))*Xo, esto hay que calcularlo para cada HP

  // if (globs.kPaso_Opt = 13) and (globs.CF.ordinalEstrellaActual = 102) then
  //   writeln();

  NHiperplanos := listaDeHiperplanos.Count;
  sonIguales := False; // para que agregue si no hay ninguno
  {$IFDEF chequear_HP}
  if (globs.kPaso_Opt = 453) and  (globs.CF.ordinalEstrellaActual = 7101) then
     writeln('a probar');
  {$ENDIF}
  if NHiperplanos > 0 then
  begin
    // Primero calculo el B del xInfoHP que es una vez sola
    xB := xInfoHP.CF;
    for kVariableContinua := 0 to NContinuas - 1 do
      xB := xB - xInfoHP.gradiente_xr[kVariableContinua] *
        xInfoHP.xr[kVariableContinua];
    for kVariableDiscreta := 0 to NDiscretas - 1 do
      xB := xB - xInfoHP.gradiente_xd[kVariableDiscreta] *
        xInfoHP.xd[kVariableDiscreta];

    for kHiperplano := 0 to NHiperplanos - 1 do
    begin
      aInfoHP := TInfoHiperplano(listaDeHiperplanos[kHiperplano]);
      sonIguales := True;
      // Comparamos los gradientes elemento a elemento
      // primero las continuas

      for kVariableContinua := 0 to NContinuas - 1 do
      begin
        aVar := aInfoHP.gradiente_xr[kVariableContinua];
        xVar := xInfoHP.gradiente_xr[kVariableContinua];
        {$IFNDEF chequear_HP}
        if aVar < CasiCero_Simplex then
           aVar := 0;
        if xVar < CasiCero_Simplex then
           xVar := 0;
        {$ENDIF}
        if aVar <> 0 then
        begin
          {$IFDEF chequear_HP}
          if (abs(abs(aVar) - abs(xVar)) > UMBRAL_HIPERPLANOS_IGUALES) then
          {$ELSE}
          if (abs((aVar - xVar) / aVar) > UMBRAL_HIPERPLANOS_IGUALES) then
          {$ENDIF}
            sonIguales := False;
        end
        else
        if xVar <> 0 then
        {$IFNDEF chequear_HP}
          if (abs((aVar - xVar) / xVar) > UMBRAL_HIPERPLANOS_IGUALES) then
            sonIguales := False;
        {$ELSE}
        begin
        end;
        {$ENDIF}
      end;

      // luego las discretas
      for kVariableDiscreta := 0 to NDiscretas - 1 do
      begin
        aVar := aInfoHP.gradiente_xd[kVariableDiscreta];
        xVar := xInfoHP.gradiente_xd[kVariableDiscreta];

        if aVar <> 0 then
        begin
          if (abs((aVar - xVar) / aVar) > UMBRAL_HIPERPLANOS_IGUALES) then
            sonIguales := False;
        end
        else
        if xVar <> 0 then
          if (abs((aVar - xVar) / xVar) > UMBRAL_HIPERPLANOS_IGUALES) then
            sonIguales := False;
      end;

      // Finalmente los B
      aB := aInfoHP.CF;
      for kVariableContinua := 0 to NContinuas - 1 do
        aB := aB - aInfoHP.gradiente_xr[kVariableContinua] *
          aInfoHP.xr[kVariableContinua];
      for kVariableDiscreta := 0 to NDiscretas - 1 do
        aB := aB - aInfoHP.gradiente_xd[kVariableDiscreta] *
          aInfoHP.xd[kVariableDiscreta];


      if aB <> 0 then
      begin
        if (abs((aB - xB) / aB) > UMBRAL_HIPERPLANOS_IGUALES) then
          sonIguales := False;
      end
      else
      if xB <> 0 then
        if (abs((aB - xB) / xB) > UMBRAL_HIPERPLANOS_IGUALES) then
          sonIguales := False;
      if sonIguales then  // si llegó hasta acá en true es porque son iguales
        break;
    end;
  end;

  xInfoYaExiste := sonIguales;


  if not (xInfoYaExiste) then
  begin
    listaDeHiperplanos.add(xInfoHP);
    Result := True;
  end
  else
    Result := False;

end;

procedure TIntermediarioCostoFuturo.getLambdas(s: TMIPSimplex);
var
  kd, kr, iposte: integer;
begin
  for kr := 0 to CF.nVarsContinuas - 1 do
    CF.lambda.pon_e(kr + 1, s.ymult(idx_SPX_yr[kr]));

  for kd := 0 to CF.nVarsDiscretas - 1 do
    CF.lambda.pon_e(CF.nVarsContinuas + kd + 1, s.ymult(idx_SPX_yd[kd]));
end;

destructor TIntermediarioCostoFuturo.destroy;
var
  k, j: integer;

begin

  for k := 0 to listaDeHiperplanos.Count - 1 do
    TInfoHiperplano(listaDeHiperplanos[k]).Free;
  listaDeHiperplanos.Free;

  SetLength(idx_SPX_xr, 0);
  SetLength(idx_SPX_xd, 0);

  SetLength(idx_SPX_yr, 0);
  SetLength(idx_SPX_yd, 0);

  for k := 0 to high(restricciones_xr) do
  begin
    for j := 0 to high(restricciones_xr[k]) do
      restricciones_xr[k][j].Free;
    SetLength(restricciones_xr[k], 0);
  end;
  SetLength(restricciones_xr, 0);

  for k := 0 to high(restricciones_xd) do
  begin
    for j := 0 to high(restricciones_xd[k]) do
      restricciones_xd[k][j].Free;
    SetLength(restricciones_xd[k], 0);
  end;
  SetLength(restricciones_xd, 0);

  SetLength(nombres_xr, 0);
  SetLength(nombres_xd, 0);
  SetLength(unidades_xr, 0);
  SetLength(unidades_xd, 0);

  for k := 0 to high(tipo_derivadas_xr) do
  begin
    tipo_derivadas_xr[k].Free;
  end;
  for k := 0 to high(tipo_derivadas_xd) do
  begin
    tipo_derivadas_xd[k].Free;
  end;

  SetLength(tipo_derivadas_xr, 0);
  SetLength(tipo_derivadas_xr, 0);

  pubvarlst.Free;

  inherited Destroy;
end;

{ TRestriccionGradiente }

constructor TRestriccionGradiente.Create(atipo: TTipoDeRestriccionGrad; avalor: NReal);
begin
  tipo := atipo;
  valor := avalor;
end;

{ TIntermediarioCostoFuturo }

constructor TIntermediarioCostoFuturo.Create;
begin
  inherited Create(capa, 'IntermediarioCF');
  cnt_var_registrada := 0;
  listaDeHiperplanos := TList.Create;
end;

procedure TIntermediarioCostoFuturo.PrepararMemoria(Catalogo: TCatalogoReferencias;
  globs: TGlobs);
var
  kVariable: integer;
begin
  inherited PrepararMemoria(Catalogo, globs);
  self.CF := globs.CF;

  NContinuas := CF.nVarsContinuas;
  NDiscretas := CF.nVarsDiscretas;

  SetLength(idx_SPX_xr, NContinuas);
  SetLength(idx_SPX_xd, NDiscretas);

  SetLength(tipo_derivadas_xr, NContinuas);
  SetLength(tipo_derivadas_xd, NDiscretas);

  SetLength(idx_SPX_yr, NContinuas);
  SetLength(idx_SPX_yd, NDiscretas);


  self.NContinuas := NContinuas;
  self.NDiscretas := NDiscretas;

  SetLength(restricciones_xr, NContinuas);
  SetLength(restricciones_xd, NDiscretas);


  SetLength(nombres_xr, NContinuas);
  SetLength(nombres_xd, NDiscretas);

  SetLength(unidades_xr, NContinuas);
  SetLength(unidades_xd, NDiscretas);

  for kVariable := 0 to NContinuas - 1 do
  begin
    nombres_xr[kVariable] := CF.xr_def[kVariable].nombre;
    unidades_xr[kVariable] := CF.xr_def[kVariable].unidades;
  end;

  for kVariable := 0 to NDiscretas - 1 do
  begin
    nombres_xd[kVariable] := CF.xd_def[kVariable].nombre;
    unidades_xd[kVariable] := CF.xd_def[kVariable].unidades;
  end;

end;

function TIntermediarioCostoFuturo.getNombreVar(ivar: integer;
  var nombre: string): boolean;
begin
  if ivar = ivarCFSPX then
  begin
    nombre := 'CF';
    Result := True;
  end
  else
  begin
    nombre := '';
    Result := False;
  end;
end;

function TIntermediarioCostoFuturo.getNombreRes(ires: integer;
  var nombre: string): boolean;
var
  XoStr: string;
  NHiperplanos: integer;
begin
  NHiperplanos := listaDeHiperplanos.Count;
  if (ires >= iresCFSPX_base) and (ires <= iresCFSPX_base +
    listaDeHiperplanos.Count - 1) then
  begin
    XoStr := IntToStr(ires - iresCFSPX_base);
    nombre := 'CF(Xs) >= CF(X' + XoStr + ') + grad(CF(X' + XoStr +
      ')).(Xs-X' + XoStr + ')';
    Result := True;
  end
  else
  begin
    nombre := '';
    Result := False;
  end;
end;

procedure TIntermediarioCostoFuturo.registrarVariableContinua(
  iCF, iSPX_x, iSPX_y: integer; restricciones: TDAOfRestriccionGradiente;
  nombreVar, unidades: string; metodoDerivada: TMetodoDerivada);
var
  kRestriccion, NRestricciones: integer;
begin
  // agarrar el costo futuro y casarlo con el indice de la variable dinamica del actor
  idx_SPX_xr[iCF] := iSPX_x;
  idx_SPX_yr[iCF] := iSPX_y;
  restricciones_xr[iCF] := restricciones;
  nombres_xr[iCF] := nombreVar;
  unidades_xr[iCF] := '[' + unidades + ']';
  tipo_derivadas_xr[iCF] := metodoDerivada;
  Inc(cnt_var_registrada);

end;

procedure TIntermediarioCostoFuturo.registrarVariableDiscreta(
  iCF, iSPX_x, iSPX_y: integer; restricciones: TDAOfRestriccionGradiente;
  nombreVar, unidades: string; metodoDerivada: TMetodoDerivada);
begin
  // agarrar el costo futuro y casarlo con el indice de la variable dinamica del actor
  idx_SPX_xd[iCF] := iSPX_x;
  idx_SPX_yd[iCF] := iSPX_y;
  restricciones_xd[iCF] := restricciones;
  nombres_xd[iCF] := nombreVar;
  unidades_xd[iCF] := '[' + unidades + ']';
  tipo_derivadas_xd[iCF] := metodoDerivada;
  Inc(cnt_var_registrada);
end;


function TIntermediarioCostoFuturo.calcularGradiente(kPaso: integer;
  fActPaso: NReal): TInfoHiperplano;
var
  kr, kd, resCod: integer;
  dCdx_Inc, dCdx_Dec, xrpos: NReal;
  aInfoHP: TInfoHiperplano;
  xr, gradiente_xr, gradiente_xd: TDAofNReal;
  xd: TDAOfNInt;
  valCF: NReal;
  f: textfile;
  archi: string;
begin

  SetLength(xr, NContinuas);
  setlength(xd, NDiscretas);
  SetLength(gradiente_xr, NContinuas);
  SetLength(gradiente_xd, NDiscretas);

  // Copiamos el estado y el costo desde el administrador de estados
  // el estado es el proyectado por los actores y fuentes en la primera iteración y
  // el resuelto por el simplex en las siguientes
  valCF := CF.costoContinuo(kPaso);
  vcopy(xr, CF.xr);
  vcopy(xd, CF.xd);

  aInfoHP := TInfoHiperplano.Create(valCF, xr, xd, gradiente_xr, gradiente_xd);

  {$IFDEF imprimirderivadas}
  if globs.kPaso_Opt > 40 then
  begin
    archi := 'derivadas' + IntToStr(globs.kPaso_Opt) + '.xlt';
    AssignFile(f, archi);
    if FileExists(archi) then
      Append(f)
    else
      Rewrite(f);
    writeln(f, 'kEstrellita:  ' + #9 + IntToStr(globs.CF.ordinalEstrellaActual));
  end;
  {$ENDIF}


  for kr := 0 to CF.nVarsContinuas - 1 do
  begin
    case tipo_derivadas_xr[kr].tipo of
      DEVXR_CONTINUO:
      begin
        CF.devxr_continuo(kr, kPaso, dCdx_Inc, dCdx_Dec, resCod, xrpos);
        {$IFDEF chequeo_caja_derivada}
        case resCod of
          -1: gradiente_xr[kr] := tipo_derivadas_xr[kr].Cteinc * dCdx_Inc;
          0: gradiente_xr[kr] :=
              tipo_derivadas_xr[kr].Cteinc * (dCdx_Inc + dCdx_Dec) / 2;
          1: gradiente_xr[kr] := tipo_derivadas_xr[kr].Ctedec * dCdx_Dec;
        end;
        {$ELSE}//esto
        gradiente_xr[kr] := tipo_derivadas_xr[kr].Cteinc * (dCdx_Inc + dCdx_Dec) / 2;
        //o esto
        //  gradiente_xr[kr]:= gradiente_xr[kr]*fActPaso;
        {$ENDIF}
      end;
      DELTACOSTO_VXR_CONTINUO:
      begin
        dCdx_Inc := tipo_derivadas_xr[kr].Cteinc *
          CF.deltaCosto_vxr_continuo(kr, kPaso, tipo_derivadas_xr[kr].deltainc);
        dCdx_Dec := tipo_derivadas_xr[kr].Ctedec *
          CF.deltaCosto_vxr_continuo(kr, kPaso, tipo_derivadas_xr[kr].deltadec);
        gradiente_xr[kr] := (dCdx_Inc + dCdx_Dec) / 2;
      end;
    end;

    {$IFDEF imprimirderivadas}
    if globs.kPaso_Opt > 40 then
      writeln(f, 'variable:  ' + #9 + nombres_xr[kr] + #9 +
        'valor_variable: ' + #9 + FloatToStr(xr[kr]) + #9 + 'valor_gradiente: ' +
        #9 + FloatToStr(gradiente_xr[kr]));
    {$ENDIF}

    if restricciones_xr[kr] <> nil then
      gradiente_xr[kr] := aplicarRestricciones(restricciones_xr[kr], gradiente_xr[kr]);
  end;

  {$IFDEF imprimirderivadas}
  if globs.kPaso_Opt > 40 then
    closefile(f);
  {$ENDIF}


  for kd := 0 to CF.nVarsDiscretas - 1 do
  begin
    raise Exception.Create('OJO; derivando variables enteras SIN PENSAR');

    dCdx_Inc := CF.deltaCosto_vxd_continuo(kd, kPaso, 1);
    dCdx_Dec := CF.deltaCosto_vxd_continuo(kd, kPaso, -1);

    gradiente_xd[kd] := (dCdx_Dec + dCdx_Inc) / 2 * fActPaso;

    if restricciones_xd[kd] <> nil then
      gradiente_xd[kd] :=
        aplicarRestricciones(restricciones_xd[kd], gradiente_xd[kd]);
  end;

  Result := aInfoHP;

end;

(*
procedure TIntermediarioCostoFuturo.calcularEstadoActual(kPaso: integer);
begin
  vcopy(xr, CF.xr);
  vcopy(xd, CF.xd);
  costoFuturoDelEstadoActual := CF.costoContinuo(kPaso);
end;
  *)
procedure TIntermediarioCostoFuturo.opt_cargue(s: TMIPSimplex);
var
  kr, kd, NHiperplanos, khp: integer;
  aInfoHP: TInfoHiperplano;

begin
  if (globs.kPaso_Opt = 94) and (s.nc = 33) then
     writeln('globs.kPaso_Opt');

  NHiperplanos := listaDeHiperplanos.Count;

  for khp := 0 to NHiperplanos - 1 do
  begin
    aInfoHP := listaDeHiperplanos[khp];
    // esta restriccion es CF(Xs) >= CF(X) + grad(CF(X))*(Xs - X)
    // --> CF(Xs) - CF(X) + grad(CF(X))*X - suma(grad(CF(X)[i]*Xs[i]) >= 0
    for kr := 0 to CF.nVarsContinuas - 1 do
    begin
      {$IFDEF CC_DBG}
      writeln('paso: ' + IntToStr(globs.kPaso_Opt) + #9 + 's.nf' + #9 + IntToStr(s.nf) + #9 + 's.nc' + #9 + IntToStr(s.nc));
      {$ENDIF}
      // carga -gradiente en las variables de estado
      s.pon_e(iresCFSPX_base + khp, idx_SPX_xr[kr], -aInfoHP.gradiente_xr[kr]);
      // acumula en el termino independiente
      s.acum_e(iresCFSPX_base + khp, s.nc, aInfoHP.gradiente_xr[kr] * aInfoHP.xr[kr]);
    end;

    for kd := 0 to CF.nVarsDiscretas - 1 do
    begin
      // carga -gradiente en las variables de estado
      s.pon_e(iresCFSPX_base + khp, idx_SPX_xd[kd], -aInfoHP.gradiente_xd[kd]);
      // acumula en el termino independiente
      s.acum_e(iresCFSPX_base + khp, s.nc, aInfoHP.gradiente_xd[kd] * aInfoHP.xd[kd]);
    end;


    // el 1 en su propia restriccion
    s.pon_e(iresCFSPX_base + khp, ivarCFSPX, 1);
    // el -CF(X) en el ti
    s.acum_e(iresCFSPX_base + khp, s.nc, -1 * aInfoHP.CF);

    // s.nc es el ti
    // ivarCFSPX es el CF_Xs

    // s.nf es la funcion de costo
    // iresCFSPX_base  es la restriccion del gradiente
  end;


  // - CF(Xs) en la funcion de costo
  //s.pon_e(s.nf, ivarCFSPX, -globs.fActPaso );
  s.pon_e(s.nf, ivarCFSPX, -globs.fActPaso);

  // Ponemos cota superior al CF(Xs)
  s.cota_sup_set(ivarCFSPX, COTA_CF);
  // no sacar (o sí, no se... si arreglaN el simplex)
  s.cota_inf_set(ivarCFSPX, -COTA_CF);
  // no sacar (o sí, no se... si arreglaN el simplex)

end;

procedure TIntermediarioCostoFuturo.ClearRestricciones;
var
  k, j: integer;
begin
  for k := 0 to high(restricciones_xr) do
    for j := 0 to high(restricciones_xr[k]) do
    begin
      restricciones_xr[k][j].Free;
      restricciones_xr[k][j] := nil;
    end;
  for k := 0 to high(restricciones_xd) do
    for j := 0 to high(restricciones_xd[k]) do
    begin
      restricciones_xd[k][j].Free;
      restricciones_xd[k][j] := nil;
    end;
end;

procedure TIntermediarioCostoFuturo.prepararpaso_ps;
var
  k: integer;
begin
  for k := 0 to listaDeHiperplanos.Count - 1 do
    TInfoHiperplano(listaDeHiperplanos[k]).Free;
  listaDeHiperplanos.Free;
  listaDeHiperplanos := TList.Create;
  ;
end;

procedure TIntermediarioCostoFuturo.PubliVars;
var
  kVariable: integer;
begin
  inherited PubliVars;
  (*
  for kVariable := 0 to high(xd) do
    PublicarVariableNI(nombres_xd[kVariable], unidades_xd[kVariable],
      xd[kVariable], True);
  for kVariable := 0 to high(xr) do
    PublicarVariableNR(nombres_xr[kVariable], unidades_xr[kVariable], 12, 1,
      xr[kVariable], True);
      *)
end;

procedure TIntermediarioCostoFuturo.opt_nvers(var ivar, ivae, ires: integer);
begin
  ivarCFSPX := ivar;
  Inc(ivar);
  iresCFSPX_base := ires;
  if listaDeHiperplanos.Count = 0 then
    Inc(ires)
  else
    Inc(ires, listaDeHiperplanos.Count); // antes había un + 1

end;

{$IFDEF SPXCONLOG}
procedure TIntermediarioCostoFuturo.spx_NombrarVariables(s: TSimplex;
  cnt_vars, cnt_ress: integer);
var
  kvar, kres: integer;
  s_nombre: string;
  bres: boolean;

begin
  if getNombreVar(ivarCFSPX, s_nombre) then
    s.set_NombreVar(ivarCFSPX, s_nombre);
  if getNombreRes(iresCFSPX_base, s_nombre) then
    s.set_NombreRest(iresCFSPX_base, s_nombre);
end;

{$ENDIF}

end.
