     with A83_014_Vector; use A83_014_Vector;
     with A83_015_Matrix; use A83_015_Matrix;
     with A83_017_Random; use A83_017_Random;
     with FloaAK; use FloaAK;
     with InteAK; use InteAK;
     with MathAK; use MathAK;
     with Text_IO; use Text_IO;

     procedure Associate is
     ----------------------------------------------------------------------
     ----------------------------------------------------------------------
       u : Vector_Type ( 1..100 ) := ( others => 0.0 );  -- neurons
       T : Matrix_Type ( u'range, u'range )              -- weights
	 := ( others => ( others => 0.0 ) );
       M : character;                                    -- last pattern
       dt : float;                                       -- time delta

     procedure Hopfield (
       u    : in out Vector_Type;            -- neurons
       dt   : in     float := 0.001;         -- time delta
       Beta : in     float := 10.0;          -- gain (should be >= 1.0)
       Tau  : in     float := 1.0 ) is       -- RC time constant
     ----------------------------------------------------------------------
       du_dt : Vector_Type ( u'range );                  -- derivative of u
       V : Vector_Type ( u'range );                      -- outputs
     begin
       V := TanH ( Beta * u );
       du_dt := -u / Tau + T * V;
       u := u + dt * du_dt;
     end Hopfield;

     procedure Neurons_Init (
       u    :    out Vector_Type;
       Seed : in     positive ) is
     ----------------------------------------------------------------------
       Random      :  float;
       Random_Seed :  Random_Seed_Type;
     begin
       Random_Seed.IDum := long_integer ( -Seed );
       for Index in u'range loop
	 Random_1 ( Random, Random_Seed );
	 if Random >= 0.5 then
	   u ( Index ) := +0.05;
	 else
	   u ( Index ) := -0.05;
	 end if;
       end loop;
     end Neurons_Init;

     procedure Neurons_Show (
       u : in     Vector_Type ) is
     ----------------------------------------------------------------------
     begin
       for Index in u'range loop
	 if u ( Index ) < 0.0 then
	   Put ( '*' );
	 else
	   Put ( ' ' );
	 end if;
	 Put ( ' ' );
	 if Index mod 10 = 0 then
	   New_Line;
	 end if;
       end loop;
       New_Line;
       for Index in u'range loop
	 Put ( u ( Index ), Fore => 2, Aft => 4, Exp => 0 );
	 Put ( ' ' );
       end loop;
       New_Line;
     end Neurons_Show;

     procedure Patterns_Load (
       M : in     character := '0' ) is       -- last pattern to load
     ----------------------------------------------------------------------
       A : array ( '0'..M ) of Vector_Type ( u'range );
       Pattern_File : File_Type;
       S : integer; -- +1 or -1
     begin
     -- Read the patterns from disk
       for K in '0'..M loop
	 Open ( Pattern_File, In_File, "PS3\Pat" & K );
	 for I in A ( K )'range loop
	   InteAK.Get ( Pattern_File, S );
	   A ( K ) ( I ) := float ( S );
	 end loop;
	 Close ( Pattern_File );
       end loop;
     -- Store the patterns in the weights
       for I in u'range loop
	 for J in u'range loop
	   for K in '0'..M loop
	     T ( I, J ) := T ( I, J ) + A ( K ) ( I ) * A ( K ) ( J );
	   end loop;
	 end loop;
       end loop;
     -- Zero the diagonal
       for I in u'range loop
	 T ( I, I ) := 0.0;
       end loop;
     end Patterns_Load;

     ----------------------------------------------------------------------
     ----------------------------------------------------------------------
     begin
       Neurons_Init ( u, Ask_Pos ( "Random Seed " ) );
       Neurons_Show ( u );
       M := natural'image ( Ask_Nat ( "Last pattern ", 2, 0, 9 ) ) ( 2 );
       Patterns_Load ( M );
       dt := Ask ( "Time delta ", 1.0e-3, 1.0e-9, 1.0, Aft => 2 );
       for Time in 1..100 loop
	 Hopfield ( u, dt );
	 Neurons_Show ( u );
       end loop;
     end Associate;
