     with ConsAKD; use ConsAKD;
     with FloaAKD; use FloaAKD;
     with InteAKD; use InteAKD;
     with MathAKD; use MathAKD; -- for Tanh
     with SounAKD;
     with TextAKD; use TextAKD;
     with TTY; -- for Char_Ready

     package body Network is
     ----------------------------------------------------------------------
     ----------------------------------------------------------------------

     procedure Demo is
     ----------------------------------------------------------------------
       Neuron_Count : positive := Neuron_Count_Default;
       Stimuli_Init : float    := Stimulus_Default;
       Max          : constant positive := 10;
       Weights      : Weights_Type ( 1..Max, 1..Max )
	 := ( others => ( others => Weight_Default ) );
       Learn_On     : boolean := Learn_On_Default;
       Learn_Rate   : float   := Learn_Rate_Default;
       Speaker_On   : boolean := Speaker_On_Default;
     begin
       loop
	 New_Line;
	 Put_Line ( Copyright );
	 New_Line;
	 Put_Line ( " 0 = Exit" );
	 Put_Line ( " 1 = Run network simulation" );
	 Put_Line ( " 2 = Set Neuron_Count ("
	   & positive'image ( Neuron_Count ) & ")" );
	 Put ( " 3 = Set Stimuli_Init (" );
	 Put ( Stimuli_Init, 2, 3 );
	 Put_Line ( ")" );
	 Put ( " 4 = Set Weights (" );
	 Put ( Weight_Default, 2, 3 );
	 Put_Line ( ")" );
	 Put_Line ( " 5 = Learn_On (" & boolean'image ( Learn_On ) & ")" );
	 Put ( " 6 = Learning Rate (" );
	 Put ( Learn_Rate, 2, 3 );
	 Put_Line ( ")" );
	 Put_Line ( " 7 = Speaker_On ("
	   & boolean'image ( Speaker_On ) & ")" );
	 case Ask_Nat ( "Your option:  ", 1, 0, 7 ) is
	   when 0 =>
	     exit;
	   when 1 =>
	     declare
	       Subset :  Weights_Type ( 1..Neuron_Count, 1..Neuron_Count );
	     begin
	       for Neuron in 1..Neuron_Count loop
		 for Weight in 1..Neuron_Count loop
		   Subset ( Neuron, Weight ) := Weights ( Neuron, Weight );
		 end loop;
	       end loop;
	       Simulate ( Subset, Stimuli_Init, Learn_On, Learn_Rate,
		 Speaker_On );
	       if Learn_On then
		 for Neuron in 1..Neuron_Count loop
		   for Weight in 1..Neuron_Count loop
		     Put ( Subset ( Neuron, Weight ), 2, 3, 3 );
		   end loop;
		   New_Line;
		 end loop;
		 Pause;
	       end if;
	     end;
	   when 2 =>
	     Neuron_Count
	       := Ask_Pos ( "Neuron_Count ", Neuron_Count, 1, Max );
	   when 3 =>
	     Stimuli_Init := Ask ( "Stimuli_Init ", Stimuli_Init );
	   when 4 =>
	     for Neuron in 1..Neuron_Count loop
	       for Weight in 1..Neuron_Count loop
		 Weights ( Neuron, Weight )
		   := Ask ( "Weight to neuron" & positive'image ( Neuron )
		   & " from neuron" & positive'image ( Weight ) & " ",
		   Weights ( Neuron, Weight ), 0.0, 1.0, 1, 1, 2 );
	       end loop;
	     end loop;
	   when 5 =>
	     Learn_On := not Learn_On;
	   when 6 =>
	     Learn_Rate
	       := Ask ( "Learning Rate ", Learn_Rate, 0.0, 1.0, 2, 3, 0 );
	   when 7 =>
	     Speaker_On := not Speaker_On;
	   when others =>
	     Put_Line ( "That option is currently not available." );
	     Pause;
	 end case;
       end loop;
     end Demo;

     procedure Learn (
       Weights    : in out Weights_Type;
       Neurons    : in     Neurons_Type;
       Learn_Rate : in     float := Learn_Rate_Default ) is
     ----------------------------------------------------------------------
     begin
       for Neuron in Neurons'range loop
	 for Weight in Weights'range loop
	   Weights ( Neuron, Weight ) := Weights ( Neuron, Weight )
	     + ( Neurons ( Neuron ).V_Memb - V_Rest_Default )
	     * Neurons ( Weight ).V_Memb * Learn_Rate;
	 end loop;
       end loop;
     end Learn;

     procedure Simulate (
       Weights      : in out Weights_Type;
       Stimuli_Init : in     float        := Stimulus_Default;
       Learn_On     : in     boolean      := Learn_On_Default;
       Learn_Rate   : in     float        := Learn_Rate_Default;
       Speaker_On   : in     boolean      := Speaker_On_Default ) is
     ----------------------------------------------------------------------
       Spikes  :  natural := 0;
       Status  :  Status_Type;
       Time    :  float;
       V_Old   :  float;
       Neurons :  Neurons_Type ( Weights'range );
       Stimuli :  Stimuli_Type ( Weights'range )
	 := ( others => Stimuli_Init );
     begin
       loop
	 Stimulate ( Stimuli, Neurons, Weights );
	 for Neuron in Neurons'range loop
	   V_Old := Neurons ( Neuron ).V_Memb;
	   HH ( Status, Neurons ( Neuron ), Stimuli ( Neuron ) );
	   if ( V_Old < 0.0 ) and ( Neurons ( Neuron ).V_Memb >= 0.0 ) then
	     Spikes := Spikes + 1;
	     if Speaker_On then
	       SounAKD.Speaker_Thump;
	     end if;
	     Put ( Time ); Put ( "  " ); Put_Line ( Spikes );
	   end if;
	   if Neurons ( Neuron ).V_Memb > 1.0 then
	     Put_Line ( "Neuron popped!  Reset and weights set to half." );
	     Initialize ( Neurons ( Neuron ) );
	     for Weight in Weights'range loop
	       Weights ( Neuron, Weight )
		 := Weights ( Neuron, Weight ) * 0.5;
	     end loop;
	   end if;
--         Put ( Stimuli ( Neuron ) );
--         Put ( "  " );
--         Put_Line ( Neurons ( Neuron ).V_Memb );
	 end loop;
	 if Learn_On then
	   Learn ( Weights, Neurons, Learn_Rate );
	 end if;
	 Time := Time + Time_Delta_Default;
	 if TTY.Char_Ready then
	   declare
	     Dummy : character;
	   begin
	     Get ( Dummy );
	   end;
	   exit;
	 end if;
       end loop;
     end Simulate;

     procedure Stimulate (
       Stimuli :    out Stimuli_Type;
       Neurons : in     Neurons_Type;
       Weights : in     Weights_Type ) is
     ----------------------------------------------------------------------
       Temp : float := 0.0;
     begin
       for Neuron in Neurons'range loop
	 Temp := 0.0;
	 for Pre_Neuron in Neurons'range loop
	   Temp := Temp + ( Neurons ( Neuron ).V_Memb - V_Rest_Default )
	     * Weights ( Neuron, Pre_Neuron );
	 end loop;
	 Stimuli ( Neuron )
	   := Tanh ( Temp / Stimulus_Default ) * Stimulus_Default;
       end loop;
     end Stimulate;

     ----------------------------------------------------------------------
     ----------------------------------------------------------------------
     end Network;
