unit ufuncionesbasicas;

interface

uses
  Classes, SysUtils, uparseadorsupersimple, uoperadoresbinomicosbasicos, Math;

procedure AgregarFunciones(Evaluador: TEvaluadorExpresionesSimples);

type
  TFun_F_FF_OfObject = function(x, y: double): double of object;
  TFun_F_F_OfObject = function(x: double): double of object;

  { TFunc_F_FF_OfObject }
  TFunc_F_FF_OfObject = class(TOperProcDef_)
    func_ptr: TFun_F_FF_OfObject;
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create(nombre_: string; func_ptr_: TFun_F_FF_OfObject);
  end;

  { TFunc_F_F_OfObject }
  TFunc_F_F_OfObject = class(TOperProcDef_)
    func_ptr: TFun_F_F_OfObject;
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create(nombre_: string; func_ptr_: TFun_F_F_OfObject);
  end;


  {
Funciones definidas.
Nombre_TipoResultado_TiposEntradas
  abs_F_F
  ceil_I_F
  cos_F_F
  exp_F_F
  floor_I_F
  inv_F_F
  ln_F_F
  max_F_FF
  min_F_FF
  neg_F_F
  neg_I_I
  pow_F_FF
  round_I_F
  rsqrt_F_F   y = 1/sqrt( x )
  sign_I_F
  sign_I_I
  sin_F_F
  sqrt_F_F
  sqr_F_F
  sqr_I_I

  si_F_FFF    y = si( a, b, c ) ; if a > 0 then y:= b else y:= c;
  sigmoide_F_F  y := 1/(1+exp(-x));
  tanh_F_F   y :=  ( exp( x ) - exp( -x ) ) / ( exp( x ) + exp( -x ) )
  relu_F_F   if x >= 0 then y:= x else y:= 0.0;


  }


  { TFuncSqrt_F_F }
  TFuncSqrt_F_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;

  { TFuncSqr_F_F }
  TFuncSqr_F_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;

  { TFuncSqr_I_I }
  TFuncSqr_I_I = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;

  { TFuncSign_I_I }
  TFuncSign_I_I = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create;
  end;

  { TFuncSign_I_F }
  TFuncSign_I_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create;
  end;

  { TFuncRSqrt_F_F }// y = 1/sqrt( x )
  TFuncRSqrt_F_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;

  { TFuncRound_I_F }
  TFuncRound_I_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create;
  end;

  { TFuncNeg_I_I }
  TFuncNeg_I_I = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;

  { TFuncNeg_F_F }
  TFuncNeg_F_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;


  { TFuncMin_F_L }
  TFuncMin_F_L = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;

  { TFuncMax_F_L }
  TFuncMax_F_L = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;


  { TFuncLn_F_F }
  TFuncLn_F_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;

  { TFuncInv_F_F }
  TFuncInv_F_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;


  { TFuncFloor_I_F }
  TFuncFloor_I_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create;
  end;

  { TFuncCeil_I_F }
  TFuncCeil_I_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create;
  end;

  { TFuncAbs_F_F }
  TFuncAbs_F_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;

  { TFuncSin_F_F }
  TFuncSin_F_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;

  { TFuncCos_F_F }
  TFuncCos_F_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;

  { TFuncExp_F_F }
  TFuncExp_F_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;

  { TFuncPow_F_FF }
  TFuncPow_F_FF = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    {$IFDEF CREAR_EXPRESION_DERIVADA}
    function crearDerivada(variable: TNodoToken; parametros: TExprLst): TExpresion;
      override;
    {$ENDIF}
    constructor Create;
  end;



  { TFuncSi_F_FF }
  TFuncSi_F_FF = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create;
  end;

  { TFuncSigmoide_F_F }
  TFuncSigmoide_F_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create;
  end;

  { TFuncTanh_F_F }
  TFuncTanh_F_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create;
  end;

  { TFuncReLu_F_F }
  TFuncReLu_F_F = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create;
  end;

  { TFuncSumaProducto }
  TFuncSumaProducto = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create;
  end;


  { TFuncSoftMax }
  TFuncSoftMax = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create;
  end;

  { TFuncPonderSoftMax }
  TFuncPonderSoftMax = class(TOperProcDef_)
    procedure evaluar(salida: TExpresion; entradas: TExprLst); override;
    constructor Create;
  end;


implementation
uses
  xmatdefs, utanh, usigmoide;

{ TFuncPonderSoftMax }

procedure TFuncPonderSoftMax.evaluar(salida: TExpresion; entradas: TExprLst);
var
  aExp: TExpresion;
  res: double;
  k: integer;
  y, x: TDAOfNReal;

begin
  entradas.evaluar;
  res:= 0;

  setlength( x, entradas.lst.count );
  setlength( y, entradas.lst.count );

  for k := 0 to high( x ) do
  begin
    aExp := entradas.lst[k];
    x[k]:= aExp.ValAsFloat;
    res:= xmatdefs.PonderSoftMax( y, x );
  end;
  setlength( x, 0 );
  setlength( y, 0 );

  salida.val.val_F:= res;
end;

constructor TFuncPonderSoftMax.Create;
begin
  inherited Create('pondersoftmax', 'F', 'F+');
end;

{ TFuncSoftMax }

procedure TFuncSoftMax.evaluar( salida: TExpresion; entradas: TExprLst);
var
  s: TExprLst;
  aExp: TExpresion;
  k: integer;
  x, y: TDAofNReal;
begin
  s:= salida as TExprLst;
  if ( entradas.lst.count <> s.lst.count)  then
    raise Exception.Create( 'SoftMax .. la salida debe tener la misma cantidad de elementos que la entrada.' );

  setlength(x, entradas.lst.count );

  for k := 0 to entradas.lst.count-1 do
  begin
    aExp := entradas.lst[k];
    aExp.evaluar;
    x[k]:= aExp.ValAsFloat;
  end;

  y:= xmatdefs.softmax( x );

  for k := 0 to s.lst.count-1 do
  begin
    aExp := s.lst[k];
    aExp.val.val_F:= y[k];
  end;
  setlength( x, 0 );
  setlength( y, 0 );
end;

constructor TFuncSoftMax.Create;
begin
  inherited Create('softmax', 'L', 'F+');
end;

{ TFuncSumaProducto }

procedure TFuncSumaProducto.evaluar(salida: TExpresion; entradas: TExprLst);
var
  a, b: TExprLst;
  aExp, bExp: TExpresion;
  res: double;
  k: integer;

begin
  a:= entradas[0] as TExprLst;
  b:= entradas[1] as TExprLst;
  res:= 0;
  if a.lst.count <> b.lst.count then
    raise Exception.Create( 'SumaProducto .. las dos listas de expresiones deben tener la misma cantidad de elementos.' );

  for k := 0 to a.lst.count-1 do
  begin
    aExp := a.lst[k];
    aExp.evaluar;
    bExp := b.lst[k];
    bExp.evaluar;
    res:= res+ aExp.ValAsFloat * bExp.ValAsFloat;
  end;
  salida.val.val_F:= res;
end;

constructor TFuncSumaProducto.Create;
begin
  inherited Create('sumaproducto', 'F', 'LL');
end;


{ TFuncReLu_F_F }

procedure TFuncReLu_F_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := max( 0.0, parA.ValAsFloat );
end;


constructor TFuncReLu_F_F.Create;
begin
  inherited Create('relu', 'F', 'F');
end;

{ TFuncTanh_F_F }

procedure TFuncTanh_F_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := tanh(  parA.ValAsFloat );
end;


constructor TFuncTanh_F_F.Create;
begin
  inherited Create('tanh', 'F', 'F');
end;

{ TFuncSigmoide_F_F }

procedure TFuncSigmoide_F_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := sigmoide(  parA.ValAsFloat );
end;


constructor TFuncSigmoide_F_F.Create;
begin
  inherited Create('sigmoide', 'F', 'F');
end;

{ TFuncSi_F_FF }

procedure TFuncSi_F_FF.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA, parB, parC: TExpresion;
begin
  res := salida;
  parA:= entradas[0];
  parB:= entradas[1];
  parC:= entradas[2];

  parA.evaluar;
  if parA.ValAsFloat > 0 then
  begin
    parB.evaluar;
    res.val.val_F := parB.ValAsFloat
  end
  else
  begin
    parC.evaluar;
    res.val.Val_F:=  parC.ValAsFloat;
  end;

end;


constructor TFuncSi_F_FF.Create;
begin
  inherited Create('si', 'F', 'FF');
end;


procedure TFuncSqr_I_I.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_I := sqr(parA.ValAsInt);
end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncSqr_I_I.crearDerivada(variable: TNodoToken; parametros: TExprLst
  ): TExpresion;
var
  parA, dParA: TExpresion;
  dos: TConst_I;
  dosPorA_lst, dorPorAPorAPrima_lst: TExprLst;
  dosPorA_oper, dorPorAPorAPrima_oper: TOperProc;
begin

  ///////  (SQR(A))' = 2*A*A'  //////

  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'
  dos:=TConst_I.Create(2); // 2

  // 2*A //
  dosPorA_lst:=TExprLst.Create;
  dosPorA_lst.add(dos);
  dosPorA_lst.add(parA.crearClon);
  lst_opers.add(TOperProducto_F_FF.Create);
  dosPorA_oper:=TOperProc.Create( lst_opers[lst_opers.Count - 1],dosPorA_lst);

  // 2*A*A' //
  dorPorAPorAPrima_lst:=TExprLst.Create;
  dorPorAPorAPrima_lst.add(dosPorA_oper);
  dorPorAPorAPrima_lst.add(dParA);
  lst_opers.add( TOperProducto_F_FF.Create);
  dorPorAPorAPrima_oper:=TOperProc.Create( lst_opers[lst_opers.Count - 1],dorPorAPorAPrima_lst);

  Result:=dorPorAPorAPrima_oper;

end;
{$ENDIF}

constructor TFuncSqr_I_I.Create;
begin
  inherited Create('sqr', 'I', 'I');
end;

procedure TFuncSqr_F_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := sqr(parA.ValAsFloat);
end;


{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncSqr_F_F.crearDerivada(variable: TNodoToken; parametros: TExprLst
  ): TExpresion;
var
  parA, dParA: TExpresion;
  dos: TConst_I;
  dosPorA_lst, dorPorAPorAPrima_lst: TExprLst;
  dosPorA_oper, dorPorAPorAPrima_oper: TOperProc;
begin

  ///////  (SQR(A))' = 2*A*A'  //////

  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'
  dos:=TConst_I.Create(2); // 2

  // 2*A //
  dosPorA_lst:=TExprLst.Create;
  dosPorA_lst.add(dos);
  dosPorA_lst.add(parA.crearClon);
  lst_opers.add(TOperProducto_F_FF.Create);
  dosPorA_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],dosPorA_lst);

  // 2*A*A' //
  dorPorAPorAPrima_lst:=TExprLst.Create;
  dorPorAPorAPrima_lst.add(dosPorA_oper);
  dorPorAPorAPrima_lst.add(dParA);
  lst_opers.add(TOperProducto_F_FF.Create);
  dorPorAPorAPrima_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],dorPorAPorAPrima_lst);

  Result:=dorPorAPorAPrima_oper;
end;

{$ENDIF}

constructor TFuncSqr_F_F.Create;
begin
  inherited Create('sqr', 'F', 'F');
end;

procedure TFuncSqrt_F_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := sqrt(parA.ValAsFloat);
end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncSqrt_F_F.crearDerivada(variable: TNodoToken; parametros: TExprLst
  ): TExpresion;
var
  parA, dParA: TExpresion;
  dos: TConst_I;
  raizDeA_lst, dorPorRaizDeA_lst, APrimaSobredorPorRaizDeA_lst: TExprLst;
  raizDeA_oper, dorPorRaizDeA_oper, APrimaSobredorPorRaizDeA_oper: TOperProc;
begin

  ///////  (SQRT(A))' = A'/(2*SQRT(A))  //////

  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'
  dos:=TConst_I.Create(2); // 2

  // SQRT(A) //
  raizDeA_lst:=TExprLst.Create;
  raizDeA_lst.add(parA.crearClon);
  lst_opers.add(TFuncSqrt_F_F.Create);
  raizDeA_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],raizDeA_lst);

  // 2*SQRT(A) //
  dorPorRaizDeA_lst:=TExprLst.Create;
  dorPorRaizDeA_lst.add(dos);
  dorPorRaizDeA_lst.add(raizDeA_oper);
  lst_opers.add(TOperProducto_F_FF.Create);
  dorPorRaizDeA_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],dorPorRaizDeA_lst);

  // A'/(2*SQRT(A)) //
  APrimaSobredorPorRaizDeA_lst:=TExprLst.Create;
  APrimaSobredorPorRaizDeA_lst.add(dPara);
  APrimaSobredorPorRaizDeA_lst.add(dorPorRaizDeA_oper);
  lst_opers.add(TOperDivision_F_FF.Create);
  APrimaSobredorPorRaizDeA_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],APrimaSobredorPorRaizDeA_lst);

  Result:=APrimaSobredorPorRaizDeA_oper;

end;
{$ENDIF}

constructor TFuncSqrt_F_F.Create;
begin
  inherited Create('sqrt', 'F', 'F');
end;

procedure TFuncSign_I_I.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_I := sign(parA.ValAsInt);
end;

constructor TFuncSign_I_I.Create;
begin
  inherited Create('sign', 'I', 'I');
end;

procedure TFuncSign_I_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_I := sign(parA.ValAsFloat);
end;

constructor TFuncSign_I_F.Create;
begin
  inherited Create('sign', 'I', 'F');
end;

procedure TFuncNeg_I_I.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_I := -parA.ValAsInt;
end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncNeg_I_I.crearDerivada(variable: TNodoToken; parametros: TExprLst
  ): TExpresion;
var
  parA, dParA: TExpresion;
  menosUno: TConst_I;
  menosUnoPorAPrima_lst: TExprLst;
  menosUnoPorAPrima_oper: TOperProc;
begin

  ///////  (NEG(A))' = -A'  //////

  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'
  menosUno:=TConst_I.Create(-1); // -1

  menosUnoPorAPrima_lst:=TExprLst.Create;
  menosUnoPorAPrima_lst.add(menosUno);
  menosUnoPorAPrima_lst.add(dParA);
  lst_opers.add(TOperProducto_F_FF.Create);
  menosUnoPorAPrima_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],menosUnoPorAPrima_lst);

  Result:=menosUnoPorAPrima_oper;

end;
{$ENDIF}

constructor TFuncNeg_I_I.Create;
begin
  inherited Create('neg', 'I', 'I');
end;

procedure TFuncRSqrt_F_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := 1 / sqrt(parA.ValAsFloat);
end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncRSqrt_F_F.crearDerivada(variable: TNodoToken; parametros: TExprLst
  ): TExpresion;
var
  tresMedios: TConst_F;
  parA, dParA: TExpresion;
  menosDos: TConst_I;
  aAlaTresMedios_lst, menosDosPorAAlaTresMedios_lst,
    APrimaSobreMenosDosPorAAlaTresMEdios_lst: TExprLst;
  aAlaTresMedios_oper, menosDosPorAAlaTresMedios_oper,
    APrimaSobreMenosDosPorAAlaTresMEdios_oper: TOperProc;

begin

  ///////  (1/SQRT(A))' = -A'/(2*(A)^(3/2))  //////

  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'
  tresMedios:=TConst_F.Create(3/2); // 3/2
  menosDos:=TConst_I.Create(-2); // -2

  // A^(3/2) //
  aAlaTresMedios_lst:=TExprLst.Create;
  aAlaTresMedios_lst.add(parA.crearClon);
  aAlaTresMedios_lst.add(tresMedios);
  lst_opers.add(TOperPower_F_FF.Create);
  aAlaTresMedios_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],aAlaTresMedios_lst);

  // -2*A^(3/2) //
  menosDosPorAAlaTresMedios_lst:=TExprLst.Create;
  menosDosPorAAlaTresMedios_lst.add(menosDos);
  menosDosPorAAlaTresMedios_lst.add(aAlaTresMedios_oper);
  lst_opers.add(TOperProducto_F_FF.Create);
  menosDosPorAAlaTresMedios_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],menosDosPorAAlaTresMedios_lst);

  // A'/(-2*(A)^(3/2)) //
  APrimaSobreMenosDosPorAAlaTresMEdios_lst:=TExprLst.Create;
  APrimaSobreMenosDosPorAAlaTresMEdios_lst.add(dParA);
  APrimaSobreMenosDosPorAAlaTresMEdios_lst.add(menosDosPorAAlaTresMedios_oper);
  lst_opers.add(TOperDivision_F_FF.Create);
  APrimaSobreMenosDosPorAAlaTresMEdios_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],APrimaSobreMenosDosPorAAlaTresMEdios_lst);

  Result:=APrimaSobreMenosDosPorAAlaTresMEdios_oper;
end;
{$ENDIF}

constructor TFuncRSqrt_F_F.Create;
begin
  inherited Create('rsqrt', 'F', 'F');
end;


procedure TFuncRound_I_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_I := round( parA.ValAsFloat );
end;

constructor TFuncRound_I_F.Create;
begin
  inherited Create('round', 'I', 'F');
end;

procedure TFuncNeg_F_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := -parA.ValAsFloat;
end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncNeg_F_F.crearDerivada(variable: TNodoToken; parametros: TExprLst
  ): TExpresion;
var
  parA, dParA: TExpresion;
  menosUno: TConst_I;
  menosUnoPorAPrima_lst: TExprLst;
  menosUnoPorAPrima_oper: TOperProc;
begin

  ///////  (NEG(A))' = -A'  //////

  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'
  menosUno:=TConst_I.Create(-1); // -1

  menosUnoPorAPrima_lst:=TExprLst.Create;
  menosUnoPorAPrima_lst.add(menosUno);
  menosUnoPorAPrima_lst.add(dParA);
  lst_opers.add(TOperProducto_F_FF.Create);
  menosUnoPorAPrima_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],menosUnoPorAPrima_lst);

  Result:=menosUnoPorAPrima_oper;
end;
{$ENDIF}


constructor TFuncNeg_F_F.Create;
begin
  inherited Create('neg', 'F', 'F');
end;


procedure TFuncMin_F_L.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA, parB: TExpresion;
  k: integer;
  m: NReal;
begin
  entradas.evaluar;
  res := salida;
  {
  parA := entradas[0];
  parB := entradas[1];
  res.val.val_F := min(parA.ValAsFloat, parB.ValAsFloat);
  }
  m:= entradas[0].ValAsFloat;
  for k:= 1 to entradas.lst.Count-1 do
  begin
    m:= min( m, entradas[k].ValAsFloat );
  end;
  res.val.val_F:= m;
end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncMin_F_FF.crearDerivada(variable: TNodoToken; parametros: TExprLst
  ): TExpresion;
var
  parA, dParA, parB, dParB: TExpresion;
  dos: TConst_I;
  AMenosB_lst, signoDeAMenosB_lst, BPrimaMenosAPrima_lst,
    BPrimaMenosAPrimaSobreDos_lst,
    signoDeAMenosBPorBPrimaMenosAPrimaSobreDos_lst,
    APrimaMasBPrima_lst, APrimaMasBPrimaSobreDos_lst,
    signoDeAMenosBPorBPrimaMenosAPrimaSobreDosMasAPrimaMasBPrimaSobreDos_lst: TExprLst;
  AMenosB_oper, signoDeAMenosB_oper, BPrimaMenosAPrima_oper,
    BPrimaMenosAPrimaSobreDos_oper,
    signoDeAMenosBPorBPrimaMenosAPrimaSobreDos_oper,
    APrimaMasBPrima_oper, APrimaMasBPrimaSobreDos_oper,
    signoDeAMenosBPorBPrimaMenosAPrimaSobreDosMasAPrimaMasBPrimaSobreDos_oper: TOperProc;
begin

  ///////  (MIN(A,B))' = sign(A-B)*(B'-A')/2+(A'+B')/2  //////

  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'
  parB := parametros[1]; // B
  dParB := parB.crearDerivada(variable); // B'
  dos := TConst_I.Create(2); // 2

  // A - B //
  AMenosB_lst := TExprLst.Create;
  AMenosB_lst.add(parA.crearClon);
  AMenosB_lst.add(parB.crearClon);
  lst_opers.add(TOperResta_F_FF.Create);
  AMenosB_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], AMenosB_lst);

  // sign(A-B) //
  signoDeAMenosB_lst := TExprLst.Create;
  signoDeAMenosB_lst.add(AMenosB_oper);
  lst_opers.add(TFuncSign_I_F.Create);
  signoDeAMenosB_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], signoDeAMenosB_lst);

  // B' - A' //
  BPrimaMenosAPrima_lst := TExprLst.Create;
  BPrimaMenosAPrima_lst.add(dParB);
  BPrimaMenosAPrima_lst.add(dParA);
  lst_opers.add(TOperResta_F_FF.Create);
  BPrimaMenosAPrima_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], BPrimaMenosAPrima_lst);

  // (B'-A')/2 //
  BPrimaMenosAPrimaSobreDos_lst := TExprLst.Create;
  BPrimaMenosAPrimaSobreDos_lst.add(BPrimaMenosAPrima_oper);
  BPrimaMenosAPrimaSobreDos_lst.add(dos);
  lst_opers.add(TOperDivision_F_FF.Create);
  BPrimaMenosAPrimaSobreDos_oper :=
    TOperProc.Create(lst_opers[lst_opers.Count - 1], BPrimaMenosAPrimaSobreDos_lst);

  // sign(A-B)*(B'-A')/2 //
  signoDeAMenosBPorBPrimaMenosAPrimaSobreDos_lst := TExprLst.Create;
  signoDeAMenosBPorBPrimaMenosAPrimaSobreDos_lst.add(signoDeAMenosB_oper);
  signoDeAMenosBPorBPrimaMenosAPrimaSobreDos_lst.add(BPrimaMenosAPrimaSobreDos_oper);
  lst_opers.add(TOperProducto_F_FF.Create);
  signoDeAMenosBPorBPrimaMenosAPrimaSobreDos_oper :=
    TOperProc.Create(lst_opers[lst_opers.Count - 1],
    signoDeAMenosBPorBPrimaMenosAPrimaSobreDos_lst);

  // A'+B' //
  APrimaMasBPrima_lst := TExprLst.Create;
  APrimaMasBPrima_lst.add(dParA.crearClon);
  APrimaMasBPrima_lst.add(dParB.crearClon);
  lst_opers.add(TOperSuma_F_FF.Create);
  APrimaMasBPrima_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], APrimaMasBPrima_lst);

  // (A'+B')/2 //
  APrimaMasBPrimaSobreDos_lst := TExprLst.Create;
  APrimaMasBPrimaSobreDos_lst.add(APrimaMasBPrima_oper);
  APrimaMasBPrimaSobreDos_lst.add(dos);
  lst_opers.add(TOperDivision_F_FF.Create);
  APrimaMasBPrimaSobreDos_oper :=
    TOperProc.Create(lst_opers[lst_opers.Count - 1], APrimaMasBPrimaSobreDos_lst);

  ///////  sign(A-B)*(B'-A')/2+(A'+B')/2  //////
  signoDeAMenosBPorBPrimaMenosAPrimaSobreDosMasAPrimaMasBPrimaSobreDos_lst :=
    TExprLst.Create;
  signoDeAMenosBPorBPrimaMenosAPrimaSobreDosMasAPrimaMasBPrimaSobreDos_lst.add(
    signoDeAMenosBPorBPrimaMenosAPrimaSobreDos_oper);
  signoDeAMenosBPorBPrimaMenosAPrimaSobreDosMasAPrimaMasBPrimaSobreDos_lst.add(
    APrimaMasBPrimaSobreDos_oper);
  lst_opers.add(TOperSuma_F_FF.Create);
  signoDeAMenosBPorBPrimaMenosAPrimaSobreDosMasAPrimaMasBPrimaSobreDos_oper :=
    TOperProc.Create(lst_opers[lst_opers.Count - 1],
    signoDeAMenosBPorBPrimaMenosAPrimaSobreDosMasAPrimaMasBPrimaSobreDos_lst);

  Result:=signoDeAMenosBPorBPrimaMenosAPrimaSobreDosMasAPrimaMasBPrimaSobreDos_oper;
end;
{$ENDIF}

constructor TFuncMin_F_L.Create;
begin
  inherited Create('min', 'F', 'FL');
end;

procedure TFuncMax_F_L.evaluar(salida: TExpresion; entradas: TExprLst);
var
  m: NReal;
  k: integer;
  res, parA, parB: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  {
  parA := entradas[0];
  parB := entradas[1];
  res.val.val_F := max(parA.ValAsFloat, parB.ValAsFloat);
   }
  m:= entradas[0].ValAsFloat;
  for k:= 1 to entradas.lst.Count-1 do
  begin
    m:= min( m, entradas[k].ValAsFloat );
  end;
  res.val.val_F:= m;

end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncMax_F_FF.crearDerivada(variable: TNodoToken;
  parametros: TExprLst): TExpresion;
var
  parA, dParA, parB, dParB: TExpresion;
  AMenosB_lst, signoDeAMenosB_lst, APrimaMenosBPrima_lst,
  signoDeAMenosBPorAPrimaMenosBPrimaSobreDos_lst, APrimaMasBPrima_lst,
  APrimaMasBPrimaSobreDos_lst, APrimaMenosBPrimaSobreDos_lst,
  signoDeAMenosBPorAPrimaMenosBPrimaSobreDosMasAPrimaMasBPrimaSobreDos_lst: TExprLst;
  AMenosB_oper, signoDeAMenosB_oper, APrimaMenosBPrima_oper,
  signoDeAMenosBPorAPrimaMenosBPrimaSobreDos_oper, APrimaMasBPrima_oper,
  APrimaMasBPrimaSobreDos_oper, APrimaMenosBPrimaSobreDos_oper,
  signoDeAMenosBPorAPrimaMenosBPrimaSobreDosMasAPrimaMasBPrimaSobreDos_oper: TOperProc;
  dos: TConst_I;
begin

  ///////  (MAX(A,B))' = sign(A-B)*(A'-B')/2+(A'+B')/2  //////

  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'
  parB := parametros[1]; // B
  dParB := parB.crearDerivada(variable); // B'
  dos := TConst_I.Create(2); // 2


  // A - B //
  AMenosB_lst := TExprLst.Create;
  AMenosB_lst.add(parA.CrearClon);
  AMenosB_lst.add(parB.CrearClon);
  lst_opers.add(TOperResta_F_FF.Create);
  AMenosB_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], AMenosB_lst);

  // sign(A-B) //
  signoDeAMenosB_lst := TExprLst.Create;
  signoDeAMenosB_lst.add(AMenosB_oper);
  lst_opers.add(TFuncSign_I_F.Create);
  signoDeAMenosB_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], signoDeAMenosB_lst);

  // A' - B' //
  APrimaMenosBPrima_lst := TExprLst.Create;
  APrimaMenosBPrima_lst.add(dParA);
  APrimaMenosBPrima_lst.add(dParB);
  lst_opers.add(TOperResta_F_FF.Create);
  APrimaMenosBPrima_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], APrimaMenosBPrima_lst);

  // (A'-B')/2 //
  APrimaMenosBPrimaSobreDos_lst := TExprLst.Create;
  APrimaMenosBPrimaSobreDos_lst.add(APrimaMenosBPrima_oper);
  APrimaMenosBPrimaSobreDos_lst.add(dos);
  lst_opers.add(TOperDivision_F_FF.Create);
  APrimaMenosBPrimaSobreDos_oper :=
    TOperProc.Create(lst_opers[lst_opers.Count - 1], APrimaMenosBPrimaSobreDos_lst);

  // sign(A-B)*(A'-B')/2 //
  signoDeAMenosBPorAPrimaMenosBPrimaSobreDos_lst := TExprLst.Create;
  signoDeAMenosBPorAPrimaMenosBPrimaSobreDos_lst.add(signoDeAMenosB_oper);
  signoDeAMenosBPorAPrimaMenosBPrimaSobreDos_lst.add(APrimaMenosBPrimaSobreDos_oper);
  lst_opers.add(TOperProducto_F_FF.Create);
  signoDeAMenosBPorAPrimaMenosBPrimaSobreDos_oper :=
    TOperProc.Create(lst_opers[lst_opers.Count - 1],
    signoDeAMenosBPorAPrimaMenosBPrimaSobreDos_lst);

  // A'+B' //
  APrimaMasBPrima_lst := TExprLst.Create;
  APrimaMasBPrima_lst.add(dParA.crearClon);
  APrimaMasBPrima_lst.add(dParB.crearClon);
  lst_opers.add(TOperSuma_F_FF.Create);
  APrimaMasBPrima_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], APrimaMasBPrima_lst);

  // (A'+B')/2 //
  APrimaMasBPrimaSobreDos_lst := TExprLst.Create;
  APrimaMasBPrimaSobreDos_lst.add(APrimaMasBPrima_oper);
  APrimaMasBPrimaSobreDos_lst.add(dos);
  lst_opers.add(TOperDivision_F_FF.Create);
  APrimaMasBPrimaSobreDos_oper :=
    TOperProc.Create(lst_opers[lst_opers.Count - 1], APrimaMasBPrimaSobreDos_lst);

  ///////  sign(A-B)*(A'-B')/2+(A'+B')/2  //////
  signoDeAMenosBPorAPrimaMenosBPrimaSobreDosMasAPrimaMasBPrimaSobreDos_lst :=
    TExprLst.Create;
  signoDeAMenosBPorAPrimaMenosBPrimaSobreDosMasAPrimaMasBPrimaSobreDos_lst.add(
    signoDeAMenosBPorAPrimaMenosBPrimaSobreDos_oper);
  signoDeAMenosBPorAPrimaMenosBPrimaSobreDosMasAPrimaMasBPrimaSobreDos_lst.add(
    APrimaMasBPrimaSobreDos_oper);
  lst_opers.add(TOperSuma_F_FF.Create);
  signoDeAMenosBPorAPrimaMenosBPrimaSobreDosMasAPrimaMasBPrimaSobreDos_oper :=
    TOperProc.Create(lst_opers[lst_opers.Count - 1],
    signoDeAMenosBPorAPrimaMenosBPrimaSobreDosMasAPrimaMasBPrimaSobreDos_lst);

  Result:=signoDeAMenosBPorAPrimaMenosBPrimaSobreDosMasAPrimaMasBPrimaSobreDos_oper;
end;
{$ENDIF}

constructor TFuncMax_F_L.Create;
begin
  inherited Create('max', 'F', 'L');
end;

procedure TFuncLn_F_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := ln(parA.ValAsFloat);
end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncLn_F_F.crearDerivada(variable: TNodoToken;
  parametros: TExprLst): TExpresion;
var
  parA, dParA: TExpresion;
  cociente_lst: TExprLst;
  cociente_oper: TOperProc;
begin

  ///////  (LN(A))' = A'/A  //////
  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'

  cociente_lst := TExprLst.Create;
  cociente_lst.add(dParA);
  cociente_lst.add(parA.crearClon);
  lst_opers.add(TOperDivision_F_FF.Create);
  cociente_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], cociente_lst);

  Result := cociente_oper;

end;
{$ENDIF}


constructor TFuncLn_F_F.Create;
begin
  inherited Create('ln', 'F', 'F');
end;

procedure TFuncInv_F_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := 1.0 / parA.ValAsFloat;
end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncInv_F_F.crearDerivada(variable: TNodoToken; parametros: TExprLst
  ): TExpresion;
var
  parA, dParA: TExpresion;
  dos, menosUno: TConst_I;
  aCuadrado_lst, menosAPrima_lst,
    menosAPrimaSobreACuadrado_lst: TExprLst;
  aCuadrado_oper, menosAPrima_oper, menosAPrimaSobreACuadrado_oper: TOperProc;
begin

  ///////  (1/A)' = -A'/A^2  //////
  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'
  dos:=TConst_I.Create(2); // 2
  menosUno:=TConst_I.Create(-1); // -1

  // -A' //
  menosAPrima_lst := TExprLst.Create;
  menosAPrima_lst.add(menosUno);
  menosAPrima_lst.add(dParA);
  lst_opers.add(TOperProducto_F_FF.Create);
  menosAPrima_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], menosAPrima_lst);

  // A^2 //
  aCuadrado_lst:= TExprLst.Create;
  aCuadrado_lst.add(parA.crearClon);
  aCuadrado_lst.add(dos);
  lst_opers.add(TOperPower_F_FF.Create);
  aCuadrado_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], aCuadrado_lst);

  // -A'/A2 //
  menosAPrimaSobreACuadrado_lst:= TExprLst.Create;
  menosAPrimaSobreACuadrado_lst.add(menosAPrima_oper);
  menosAPrimaSobreACuadrado_lst.add(aCuadrado_oper);
  lst_opers.add(TOperDivision_F_FF.Create);
  menosAPrimaSobreACuadrado_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], menosAPrimaSobreACuadrado_lst);

  Result := menosAPrimaSobreACuadrado_oper;

end;
{$ENDIF}


constructor TFuncInv_F_F.Create;
begin
  inherited Create('inv', 'F', 'F');
end;

procedure TFuncFloor_I_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_I := floor(parA.ValAsFloat);
end;

constructor TFuncFloor_I_F.Create;
begin
  inherited Create('floor', 'I', 'F');
end;

procedure TFuncCeil_I_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_I := ceil(parA.ValAsFloat);
end;

constructor TFuncCeil_I_F.Create;
begin
  inherited Create('ceil', 'I', 'F');
end;

procedure TFuncAbs_F_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := abs(parA.ValAsFloat);
end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncAbs_F_F.crearDerivada(variable: TNodoToken; parametros: TExprLst
  ): TExpresion;
var
  parA, dParA: TExpresion;
  signoDeAPorAPrima_lst, signoDeA_lst: TExprLst;
  signoDeA_oper, signoDeAPorAPrima_oper: TOperProc;
begin

  ///////  (ABS(A))' = sign(A)*A'  //////

  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'

  // sign(A) //
  signoDeA_lst := TExprLst.Create;
  signoDeA_lst.add(parA.crearClon);
  signoDeA_oper := TOperProc.Create(TFuncSign_I_F.Create, signoDeA_lst);

  // sign(A)*A' //
  signoDeAPorAPrima_lst := TExprLst.Create;
  signoDeAPorAPrima_lst.add(signoDeA_oper);
  signoDeAPorAPrima_lst.add(dParA);
  lst_opers.add(TOperProducto_F_FF.Create);
  signoDeAPorAPrima_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], signoDeAPorAPrima_lst);

  Result:= signoDeAPorAPrima_oper;
end;
{$ENDIF}


constructor TFuncAbs_F_F.Create;
begin
  inherited Create('abs', 'F', 'F');
end;


{ TFunc_F_F_OfObject }
procedure TFunc_F_F_OfObject.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := func_ptr(parA.ValAsFloat);
end;

constructor TFunc_F_F_OfObject.Create(nombre_: string; func_ptr_: TFun_F_F_OfObject);
begin
  inherited Create(nombre_, 'F', 'F');
  func_ptr := func_ptr_;
end;

{ TFunc_F_FF_OfObject }
procedure TFunc_F_FF_OfObject.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA, parB: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  parB := entradas[1];
  res.val.val_F := func_ptr(parA.ValAsFloat, parB.ValAsFloat);
end;

constructor TFunc_F_FF_OfObject.Create(nombre_: string; func_ptr_: TFun_F_FF_OfObject);
begin
  inherited Create(nombre_, 'F', 'FF');
  func_ptr := func_ptr_;
end;


// sin
procedure TFuncSin_F_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := sin(parA.ValAsFloat);
end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncSin_F_F.crearDerivada(variable: TNodoToken; parametros: TExprLst
  ): TExpresion;
var
  parA, dParA: TExpresion;
  cosA_lst, cosAPorAPrima_lst: TExprLst;
  cosA_oper, cosAPorAPrima_oper: TOperProc;
begin
  ///////  (SIN(A))' = COS(A)*A'  //////

  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'

  // cos(A) //
  cosA_lst := TExprLst.Create;
  cosA_lst.add(parA.crearClon);
  lst_opers.add(TFuncCos_F_F.Create);
  cosA_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], cosA_lst);

  // sign(A)*A' //
  cosAPorAPrima_lst := TExprLst.Create;
  cosAPorAPrima_lst.add(cosA_oper);
  cosAPorAPrima_lst.add(dParA);
  lst_opers.add(TOperProducto_F_FF.Create);
  cosAPorAPrima_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], cosAPorAPrima_lst);

  Result:= cosAPorAPrima_oper;
end;
{$ENDIF}

constructor TFuncSin_F_F.Create;
begin
  inherited Create('sin', 'F', 'F');
end;

// cos
procedure TFuncCos_F_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := cos(parA.ValAsFloat);
end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncCos_F_F.crearDerivada(variable: TNodoToken; parametros: TExprLst
  ): TExpresion;
var
  parA, dParA: TExpresion;
  menosUno: TConst_I;
  sinA_lst, menosSinA_lst, menosSinAPorAPrima_lst: TExprLst;
  sinA_oper, menosSinA_oper, menosSinAPorAPrima_oper: TOperProc;
begin

  ///////  (COS(A))' = -SIN(A)*A'  //////

  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'
  menosUno:=TConst_I.Create(-1); // -1

  // sin(A) //
  sinA_lst := TExprLst.Create;
  sinA_lst.add(parA.crearClon);
  lst_opers.add(TFuncSin_F_F.Create);
  sinA_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], sinA_lst);

  // -sin(A)' //
  menosSinA_lst := TExprLst.Create;
  menosSinA_lst.add(menosUno);
  menosSinA_lst.add(sinA_oper);
  lst_opers.add(TOperProducto_F_FF.Create);
  menosSinA_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], menosSinA_lst);

  // -sin(A)*A' //
  menosSinAPorAPrima_lst := TExprLst.Create;
  menosSinAPorAPrima_lst.add(menosSinA_oper);
  menosSinAPorAPrima_lst.add(dParA);
  lst_opers.add(TOperProducto_F_FF.Create);
  menosSinAPorAPrima_oper := TOperProc.Create(lst_opers[lst_opers.Count - 1], menosSinAPorAPrima_lst);

  Result:= menosSinAPorAPrima_oper;
end;
{$ENDIF}

constructor TFuncCos_F_F.Create;
begin
  inherited Create('cos', 'F', 'F');
end;

// exp
procedure TFuncExp_F_F.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  res.val.val_F := exp(parA.ValAsFloat);
end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncExp_F_F.crearDerivada(variable: TNodoToken; parametros: TExprLst
  ): TExpresion;
var
  parA, dParA: TExpresion;
  expA_lst, expAPorAPrima_lst: TExprLst;
  expA_oper, expAPorAPrima_oper: TOperProc;
begin
  ///////  (EXP(A))' = EXP(A)*A'  //////

  parA := parametros[0]; // A
  dParA := parA.crearDerivada(variable); // A'

  // exp(A) //
  expA_lst := TExprLst.Create;
  expA_lst.add(parA.crearClon);
  expA_oper := TOperProc.Create(TFuncExp_F_F.Create, expA_lst);

  // exp(A)*A' //
  expAPorAPrima_lst := TExprLst.Create;
  expAPorAPrima_lst.add(expA_oper);
  expAPorAPrima_lst.add(dParA);
  expAPorAPrima_oper := TOperProc.Create(TOperProducto_F_FF.Create, expAPorAPrima_lst);

  Result:= expAPorAPrima_oper;
end;
{$ENDIF}


constructor TFuncExp_F_F.Create;
begin
  inherited Create('exp', 'F', 'F');
end;



// pow
procedure TFuncPow_F_FF.evaluar(salida: TExpresion; entradas: TExprLst);
var
  res, parA, parB: TExpresion;
begin
  entradas.evaluar;
  res := salida;
  parA := entradas[0];
  parB := entradas[1];
  res.val.val_F := power(parA.ValAsFloat, parB.ValAsFloat);
end;

{$IFDEF CREAR_EXPRESION_DERIVADA}
function TFuncPow_F_FF.crearDerivada(variable: TNodoToken; parametros: TExprLst
  ): TExpresion;
var
  parA, dParA, parB, dParB: TExpresion;
  uno: TConst_I;
  LogNepA_lst, BMenosUno_lst, AAlaBMenosUno_lst, BPorAPrima_lst,
    APorBPrima_lst, APorBPrimaPorLNA_lst,
    BPorAPrimaMasAPorBPrimaPorLNA_lst,
    AAlaBMenosUnoPorBPorAPrimaMasAPorBPrimaPorLNA_lst: TExprLst;
  LogNepA_oper, BMenosUno_oper, AAlaBMenosUno_oper, BPorAPrima_oper,
    APorBPrima_oper, APorBPrimaPorLNA_oper,
    BPorAPrimaMasAPorBPrimaPorLNA_oper,
    AAlaBMenosUnoPorBPorAPrimaMasAPorBPrimaPorLNA_oper: TOperProc;
begin

  /////// pow(A,B)' = A^(B-1)*(B*A'+A*B'*LN(A))  //////

  parA:= parametros[0]; // A
  dParA:=parA.crearDerivada(variable); // A'
  parB:= parametros[1]; // B
  dParB:=parB.crearDerivada(variable); // B'
  uno:=TConst_I.Create(1); // 1

  // LN(A) //
  LogNepA_lst:=TExprLst.Create;
  LogNepA_lst.add(parA.crearClon);
  lst_opers.add(TFuncLn_F_F.Create);
  LogNepA_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],LogNepA_lst);

  // (B-1) //
  BMenosUno_lst:=TExprLst.Create;
  BMenosUno_lst.add(parB.crearClon);
  BMenosUno_lst.add(uno);
  lst_opers.add(TOperResta_F_FF.Create);
  BMenosUno_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],BMenosUno_lst);

  // A^(B-1) //
  AAlaBMenosUno_lst:=TExprLst.Create;
  AAlaBMenosUno_lst.add(parA.crearClon);
  AAlaBMenosUno_lst.add(BMenosUno_oper);
  lst_opers.add(TOperPower_F_FF.Create);
  AAlaBMenosUno_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],AAlaBMenosUno_lst);

  // B*A' //
  BPorAPrima_lst:=TExprLst.Create;
  BPorAPrima_lst.add(parB.crearClon);
  BPorAPrima_lst.add(dParA);
  lst_opers.add(TOperProducto_F_FF.Create);
  BPorAPrima_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],BPorAPrima_lst);

  // A*B' //
  APorBPrima_lst:=TExprLst.Create;
  APorBPrima_lst.add(parA.crearClon);
  APorBPrima_lst.add(dParB);
  lst_opers.add(TOperProducto_F_FF.Create);
  APorBPrima_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],APorBPrima_lst);

  // A*B'*LN(A) //
  APorBPrimaPorLNA_lst:=TExprLst.Create;
  APorBPrimaPorLNA_lst.add(APorBPrima_oper);
  APorBPrimaPorLNA_lst.add(LogNepA_oper);
  lst_opers.add(TOperProducto_F_FF.Create);
  APorBPrimaPorLNA_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],APorBPrimaPorLNA_lst);

  // B*A'+A*B'*LN(A) //
  BPorAPrimaMasAPorBPrimaPorLNA_lst:=TExprLst.Create;
  BPorAPrimaMasAPorBPrimaPorLNA_lst.add(BPorAPrima_oper);
  BPorAPrimaMasAPorBPrimaPorLNA_lst.add(APorBPrimaPorLNA_oper);
  lst_opers.add(TOperSuma_F_FF.Create);
  BPorAPrimaMasAPorBPrimaPorLNA_oper:=TOperProc.Create(lst_opers[lst_opers.Count - 1],
    BPorAPrimaMasAPorBPrimaPorLNA_lst);

  // A^(B-1)*(B*A'+A*B'*LN(A)) //

  AAlaBMenosUnoPorBPorAPrimaMasAPorBPrimaPorLNA_lst:=TExprLst.Create;
  AAlaBMenosUnoPorBPorAPrimaMasAPorBPrimaPorLNA_lst.add(AAlaBMenosUno_oper);
  AAlaBMenosUnoPorBPorAPrimaMasAPorBPrimaPorLNA_lst.add(BPorAPrimaMasAPorBPrimaPorLNA_oper);
  lst_opers.add(TOperProducto_F_FF.Create);
  AAlaBMenosUnoPorBPorAPrimaMasAPorBPrimaPorLNA_oper:=TOperProc.Create(
    lst_opers[lst_opers.Count - 1], AAlaBMenosUnoPorBPorAPrimaMasAPorBPrimaPorLNA_lst);

  Result:=AAlaBMenosUnoPorBPorAPrimaMasAPorBPrimaPorLNA_oper;

end;
{$ENDIF}

constructor TFuncPow_F_FF.Create;
begin
  inherited Create('pow', 'F', 'FF');
end;


procedure AgregarFunciones(Evaluador: TEvaluadorExpresionesSimples);
begin
  Evaluador.CatalogoFuncionesEstandar.add(TFuncSqrt_F_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncAbs_F_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncCeil_I_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncCos_F_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncExp_F_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncFloor_I_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncInv_F_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncLn_F_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncMax_F_L.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncMin_F_L.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncNeg_F_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncNeg_I_I.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncPow_F_FF.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncRound_I_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncRSqrt_F_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncSign_I_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncSign_I_I.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncSin_F_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncSqr_F_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncSqr_I_I.Create);

  Evaluador.CatalogoFuncionesEstandar.add(TFuncSi_F_FF.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncSigmoide_F_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncTanh_F_F.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncReLu_F_F.Create);

  Evaluador.CatalogoFuncionesEstandar.add(TFuncSumaProducto.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncSoftMax.Create);
  Evaluador.CatalogoFuncionesEstandar.add(TFuncPonderSoftMax.Create);

end;

end.


