with DC_Math, DC_Keyb, DC_Scrn;
use                    DC_Scrn;

package body DC_Neur is
---------------------------------------------------------------------------
---------------------------------------------------------------------------

procedure Array_Float_Show
	    ( Array_Float_Shown: in Array_Float ) is
---------------------------------------------------------------------------
begin
  for index in Array_Float_Shown'range loop
    Put ( Array_Float_Shown ( index ), 2, 1, 2 );
    Put ( ' ' );
  end loop;
end Array_Float_Show;

procedure Neuron_Resolve
	    ( Excitation       : in     float;
	      Neuron           : in out Neuron_Type;
	      Weighted_Outputs :    out Array_Float;
	      Is_Firing        :    out boolean
	    ) is
---------------------------------------------------------------------------
  Temp_Outputs : Array_Float ( Weighted_Outputs'range )
    := ( others => 0.0 );
begin
  Neuron.Excitation := Excitation + Neuron.Excitation;
  Is_Firing := false;
  if ( Neuron.Excitation >= Threshhold ) and ( Neuron.Charge >= 1.0 ) then
    for index in Temp_Outputs'range loop
      Temp_Outputs ( index ) := Neuron.Weights ( index );
    end loop;
    Neuron.Charge := 0.0;
    Neuron.Excitation := 0.0;
    Is_Firing := true;
  end if;
  Weighted_Outputs := Temp_Outputs;
end Neuron_Resolve;

procedure Neuron_Train
	    ( Is_Trained         : in     boolean;
	      Was_Fired          : in     boolean;
	      Net_Inputs         : in     Array_Float;
	      Net_Excitations    : in     Array_Float;
	      Targets_Charged    : in     Array_Boolean;
	      Weights_Growth     : in out Array_Float;
	      Weights            : in out Array_Float
	    ) is
---------------------------------------------------------------------------
  Weight_Trained : boolean := false;
begin
  if not Was_Fired or not Is_Trained then
    return;
  end if;
  for index in Weights'range loop
    Weights_Growth ( index ) := Weights_Growth ( index ) + 0.5;
----if fired, target is charged, target will fire,
----weight to target high, previously fired to target, then add
----??? then exit???
    if Targets_Charged ( index ) then
      if Net_Inputs ( index ) + Net_Excitations ( index )
	>= Threshhold then
	  if Weights ( index ) > 0.0 then
	    if Weights_Growth ( index ) >= 1.0 then
	      Weights ( index ) := Weight_Strengthen ( Weights ( index ) );
	      Weights_Growth ( index ) := 0.0;
	      Weight_Trained := true;
	    end if;
	  end if;
      end if;
    end if;
----if fired,
----target will not fire because not charged,
----???weighted output to target not inhibitor,
----then subtract, alter no others, set growth rate to zero
    if not Targets_Charged ( index ) then
--      if Weights ( index ) >= 0.0 then
	if not Weight_Trained or ( index mod 2 = 1 ) then
	  Weights ( index ) := Weight_Weaken ( Weights ( index ) );
	  Weight_Trained := true;
	end if;
	Weights_Growth ( index ) := 0.0;
--      end if;
    end if;
----if fired, target fully charged, input is zero or less,
----weight is not exciter, then add
    if Targets_Charged ( index ) then
      if Net_Inputs ( index ) <= 0.0 then
	if Weights ( index ) <= 0.0 then
	  Weights ( index ) := Weight_Strengthen ( Weights ( index ) );
	end if;
      end if;
    end if;
    if abs ( Weights ( index ) ) < 1.0E-3 then
      Weights ( index ) := 0.0;
    end if;
    if Weights ( index ) > 0.999 then
      Weights ( index ) := 1.0;
    end if;
    if Weights ( index ) < -0.999 then
      Weights ( index ) := -1.0;
    end if;
    exit when Weight_Trained;
  end loop;
end Neuron_Train;

procedure Neuron_Show ( Neuron: in Neuron_Type ) is
---------------------------------------------------------------------------
begin
  Weights_Show ( Neuron.Weights );
  Put ( " E:" );
  Put ( Neuron.Excitation, 2, 2, 2 );
  Put ( " C:" );
  Put ( Neuron.Charge, 2, 2, 2 );
end Neuron_Show;

function  Prompt ( Prompt_Str: in string ) return character is
---------------------------------------------------------------------------
  DumNat : natural;
  Prompt_Char_Str : string ( 1..1 );
begin
  Put ( Prompt_Str );
  Prompt_Char_Str ( 1 ) := ASCII.Nul;
  DC_Keyb.Get_Line ( Prompt_Char_Str );
  return Prompt_Char_Str ( 1 );
end Prompt;

function  Weight_Strengthen ( Weight : in float ) return float is
---------------------------------------------------------------------------
  Temp: float;
begin
  Temp := Weight + 0.5;
  if Temp > 1.0 then
    Temp := 1.0;
  end if;
  return Temp;
end Weight_Strengthen;

function  Weight_Weaken ( Weight : in float ) return float is
---------------------------------------------------------------------------
  Temp: float;
begin
  Temp := Weight - 0.5;
  if Temp < -0.5 then
    Temp := -0.5;
  end if;
  return Temp;
end Weight_Weaken;

----function  Weight_Strengthen ( Weight : in float ) return float is
-------------------------------------------------------------------------------
----  X : float;
----begin
----  X := DC_Math.Sigmoid (
----                 InFloat  => ( Weight / 2.0 ) + 0.5,
----                 Reversed => true );
----  return ( DC_Math.Sigmoid (
----    InFloat => X + 0.1 ) -- + DC_Math.Random_Uniform ( -0.01, +0.01 ) )
----      - 0.5 ) * 2.0;
--end Weight_Strengthen;
--
--function  Weight_Weaken ( Weight : in float ) return float is
-----------------------------------------------------------------------------
--  X : float;
--begin
--  X := DC_Math.Sigmoid (
--                 InFloat  => ( Weight / 2.0 ) + 0.5,
--                 Reversed => true );
--  return ( DC_Math.Sigmoid (
--    InFloat => X - 0.1 ) -- + DC_Math.Random_Uniform ( -0.01, +0.01 ) )
--      - 0.5 ) * 2.0;
--end Weight_Weaken;

procedure Weights_Show ( Weights : in Array_Float ) is
---------------------------------------------------------------------------
begin
  for index in Weights'range loop
    if Weights ( index ) /= 0.0 then
      Put ( Weights ( index ), 2, 2, 2 );
    else
      Put ( "........" );
    end if;
    Put ( ' ' );
  end loop;
end;

---------------------------------------------------------------------------
---------------------------------------------------------------------------
end DC_Neur;
