     with A83_014_Vector; use A83_014_Vector;
     with A83_017_Random; use A83_017_Random;
     with ConsAKD; use ConsAKD;
     with FloaAKD; use FloaAKD;
     with InteAKD; use InteAKD;
     with MathAK ;
     with MathAKD; use MathAKD;
     with TextAKD; use TextAKD;
     with TTY    ;

     package body FISL is
     ----------------------------------------------------------------------
     ----------------------------------------------------------------------

     procedure Delayed is
     ----------------------------------------------------------------------
       Status      : Status_Type;
       Soma        : Soma_Type;
       I_Syn_Total : float;
       Synapses    : Synapses_Type ( 1..32 );
       Phase_Shift : float;
       G_Syn       : float;
       Freq        : float := 20.0; -- formerly Frequency_Def;
       Data        : Vector_Type ( Synapses'range ) := ( others => 0.0 );
       Time        : float := 0.0;
       Print_Now   : boolean := true;
       Print_Last  : float := 0.0;
       Print_Delay : constant float := 0.001;
       Weight_Init : float := 5.0e-6;
	 -- formerly Weight_Def / float ( Synapses'last );
       Time_Max    : float := 1.0;
       Syn_Show    : natural := 1;
       Threshold   : float := Threshold_Def;
       Learn_Rate  : float := Learn_Rate_Def;
       Sharpness   : positive := 1;
     begin
       Sharpness := Ask_Pos ( "Sharpness ", Sharpness );
       Learn_Rate := Ask ( "Learn Rate ", Learn_Rate );
       Freq := Ask ( "Frequency ", Freq );
       Threshold := Ask ( "Threshold ", Threshold );
       Time_Max := Ask ( "Time_Max ", Time_Max );
       Weight_Init := Ask ( "Initial Weight ", Weight_Init );
       for Synapse in Synapses'range loop
	 Synapses ( Synapse ).W := Weight_Init;
       end loop;
       Initialize ( Soma, V_Rest_Default );
       loop
	 for Synapse in Synapses'range loop
	   Phase_Shift :=
	     MathAK.Pi * float ( Synapse - ( Synapses'last / 2 ) )
	     / float ( Synapses'last / 2 );
	   G_Syn :=
	     Sin ( 2.0 * MathAK.Pi * Freq * Time + Phase_Shift ) / 2.0
	     + 0.5;
	   G_Syn := G_Syn ** Sharpness;
	   G_Syn := G_Syn * Synapses ( Synapse ).W;
--         Put ( G_Syn ); Put ( " " );
	   Synapses ( Synapse).I
	     := ( Soma.V_Memb - V_Na_Default ) * G_Syn;
	 end loop;
	 I_Syn_Total := 0.0;
	 for Synapse in Synapses'range loop
	   I_Syn_Total := I_Syn_Total + Synapses ( Synapse).I;
	 end loop;
	 Soma_HH ( Status, Soma, -I_Syn_Total );
	 for Synapse in Synapses'range loop
	   Synapses ( Synapse ).W := Learn (
	     Synapses ( Synapse ).W, Synapses ( Synapse ).I, Soma.V_Memb,
	     Learn_Rate => Learn_Rate, Threshold => Threshold );
--         if Print_Now then
--           Put ( Synapses ( Synapse ).W, 2, 4 );  Put ( " " );
--         end if;
	 end loop;
	 if Print_Now then
	   Put ( Time ); Put ( " " );
	   Put ( Syn_Show ); Put ( " " );
	   Put ( Synapses ( Syn_Show ).W, 2, 6 ); Put ( " " );
	   if Syn_Show = Synapses'last then
	     Syn_Show := Synapses'first;
	   else
	     Syn_Show := Syn_Show + 1;
	   end if;
	   Put ( I_Syn_Total ); Put ( " " );
	   for Synapse in Synapses'range loop
	     Data ( Synapse ) := Synapses ( Synapse ).W;
	   end loop;
	   Put ( Variance ( Data ), 2, 4 ); Put ( " " );
	   Put_Line ( Soma.V_Memb, 2, 4 );
	 end if;
	 exit when Time >= Time_Max;
	 Time := Time + Time_Delta_Default;
	 if Print_Last >= Print_Delay then
	   Print_Now := true;
	   Print_Last := 0.0;
	 else
	   Print_Now := false;
	   Print_Last := Print_Last + Time_Delta_Default;
	 end if;
	 exit when TTY.Char_Ready;
       end loop;
       for Synapse in Synapses'range loop
	 Data ( Synapse ) := Synapses ( Synapse ).W;
       end loop;
       Save ( Data, "FISL_Del.Dat" );
       Data := Data - Min ( Data );
       Save ( Data, "FISL_Del.Sub" );
     end Delayed;

     procedure Demo is
     ----------------------------------------------------------------------
     begin
       Put_Line ( Copyright );
       Put_Line ( Description );
       New_Line;
       Delayed;
     end Demo;

     procedure Fixed_Demo is
     ----------------------------------------------------------------------
       Data : Vector_Type ( 0..16 ) := ( others => 0.0 );
     begin
       for Index in Data'range loop
	 Data ( Index )
	   := Fixed ( MathAK.Pi * float ( Index - ( Data'last / 2 ) )
	   / float ( Data'last / 2 ) );
	 Put_Line ( Data );
       end loop;
       Save ( Data, "FISL_Fix.Dat" );
     end Fixed_Demo;

     function Fixed (
       Phase_Shift  : in     float := 0.0;
       Weight_Float : in     float := Weight_Def * 0.1;
       Weight_Fixed : in     float := Weight_Def * 0.9;
       Time_Max     : in     float := 1.0 )
       return float is
     ----------------------------------------------------------------------
       Status       :          Status_Type;
       Soma         :          Soma_Type;
       G_Syn_Fixed  :          float;
       G_Syn_Float  :          float;
       I_Syn_Fixed  :          float;
       I_Syn_Float  :          float;
       Firing       :          boolean := false;
       Spikes       :          natural := 0;
       Time         :          float := 0.0;
       Freq         : constant float := 40.0; -- Hz
       Sum          :          float := 0.0;
       Last_Print   :          float := 0.0;
       Print_Step   : constant float := 1.0e-2; -- seconds
       Temp         :          float := Weight_Float;
       Time_Delta   : constant float := Time_Delta_Default;
     begin
       Initialize ( Soma, V_Rest_Default );
       loop
	 G_Syn_Fixed := Weight_Fixed
	   * Sin ( 2.0 * MathAK.Pi * Freq * Time ) / 2.0
	   + Weight_Fixed / 2.0;
	 G_Syn_Float := Temp
	   * Sin ( ( 2.0 * MathAK.Pi + Phase_Shift ) * Freq * Time ) / 2.0
	   + Temp / 2.0;
	 I_Syn_Fixed := ( Soma.V_Memb - V_Na_Default ) * G_Syn_Fixed;
	 I_Syn_Float := ( Soma.V_Memb - V_Na_Default ) * G_Syn_Float;
	 Soma_HH ( Status, Soma, -( I_Syn_Fixed + I_Syn_Float ) );
	 if Soma.V_Memb > 0.0 then
	   if not Firing then
	     Firing := true;
	     Spikes := Spikes + 1;
	   end if;
	 else
	   Firing := false;
	 end if;
	 Temp := Learn ( Temp, I_Syn_Float, Soma.V_Memb );
	 Sum := Sum + Temp;
	 if Last_Print > Print_Step then
	   Last_Print := 0.0;
	   Put ( Temp           , 2, 8 ); Put ( "  " );
	   Put ( Sum * Time_Delta / Time, 2, 8 ); Put ( "  " );
	   Put ( Spikes                        ); Put ( "  " );
	   Put ( float ( Spikes ) / Time       ); Put ( "  " );
	   Put ( Soma.V_Memb                   ); New_Line;
	 else
	   Last_Print := Last_Print + Time_Delta;
	 end if;
	 exit when Time >= Time_Max;
	 Time := Time + Time_Delta;
       end loop;
       return Sum * Time_Delta / Time;
     end Fixed;

     function Learn (
       Weight     : float;
       I_Syn      : float;
       Vm         : float;
       Time_Delta : float := Time_Delta_Default;
       Learn_Rate : float := Learn_Rate_Def;
       Threshold  : float := Threshold_Def;
       Weight_Min : float := Weight_Min_Def;
       Weight_Max : float := Weight_Max_Def )
       return float is
     ----------------------------------------------------------------------
       Temp : float;
     begin
       if Weight = 0.0 then
	 return 0.0;
       end if;
       Temp := Weight - Time_Delta * Learn_Rate * ( I_Syn / Weight )
	 * ( Vm - Threshold );
       if Temp < Weight_Min then
--       if Temp > 0.0 then
--         Temp := -Weight_Min;
--       else
--         Temp := +Weight_Min;
--       end if;
	 Temp := 0.0;
--       Temp := Weight_Min;
       elsif Temp > Weight_Max then
	 Temp := Weight_Max;
       end if;
       return Temp;
     end Learn;

     procedure Single is
     ----------------------------------------------------------------------
       Status : Status_Type;
       Soma   : Soma_Type;
       Freq   : float := 40.0; -- Hz
       Time   : float := 0.0;
       Time_Delta : constant float := Time_Delta_Default;
       G_Syn  : float;
       I_Syn : float;
       Weight : float := 4.45148e-5;
       Learn_Rate : float := 1.0e-1;
       Last_Print : float := 0.0;
       Print_Step : float := ( 1.0 / Freq ) / 10.0;
       Last_Stim  : float := 0.0;
       Max : float := Weight;
       Threshold : float := -63.0e-3;
       Sum : float := 0.0;
       Spikes : natural := 0;
       Firing : boolean := false;
     begin
       Threshold := Ask ( "Threshold ", Threshold );
       Weight := Ask ( "Weight ", Weight );
       Freq := Ask ( "Frequency ", Freq );
       Learn_Rate := Ask ( "Learn Rate ", Learn_Rate );
       Print_Step := Ask ( "Print Step ", Print_Step );
       Initialize ( Soma, V_Rest_Default );
       loop
	 G_Syn := Weight * Sin ( 2.0 * MathAK.Pi * Freq * Time ) / 2.0
	   + Weight / 2.0;
	 if G_Syn < 0.0 then
	   G_Syn := 0.0;
	 end if;
	 I_Syn := ( Soma.V_Memb - V_Na_Default ) * G_Syn;
	 Soma_HH ( Status, Soma, -I_Syn );
	 if Soma.V_Memb > 0.0 then
	   if not Firing then
	     Firing := true;
	     Spikes := Spikes + 1;
	   end if;
	 else
	   Firing := false;
	 end if;
	 Weight := Learn (
	   Weight, I_Syn, Soma.V_Memb, Time_Delta, Learn_Rate, Threshold );
	 if Weight > Max then
	   Max := Weight;
	 end if;
	 if Last_Print >= Print_Step then
	   Put ( Weight, 2, 8 ); Put ( "  " );
	   Put ( Sum * Time_Delta / Time, 2, 8 ); Put ( "  " );
--         Put ( Max   , 2, 8 ); Put ( "  " );
--         Put ( G_Syn ); Put ( "  " );
--         Put ( I_Syn ); Put ( "  " );
	   Put ( Spikes ); Put ( "  " );
	   Put ( float ( Spikes ) / Time ); Put ( "  " );
	   Put_Line ( Soma.V_Memb );
	   Last_Print := 0.0;
	 end if;
	 Time := Time + Time_Delta;
	 Last_Print := Last_Print + Time_Delta;
	 Sum := Sum + Weight;
       end loop;
     end Single;

     ----------------------------------------------------------------------
     ----------------------------------------------------------------------
     end FISL;
