with DC_Curs, DC_Neur, DC_Scrn, DC_Text;
use  DC_Curs, DC_Neur, DC_Scrn, DC_Text;

procedure XOR_Net is
---------------------------------------------------------------------------
---------------------------------------------------------------------------
---------------------------------------------------------------------------
Neuron_Count : constant := 5;
Sets_Count : constant := 4;
type Training_Inputs_Type is array ( 1..Sets_Count )
       of Float_Array ( 1..Neuron_Count );
Training_Inputs : constant Training_Inputs_Type
  := ( ( 0.0, 0.0, others => 0.0 ),
       ( 0.0, 1.0, others => 0.0 ),
       ( 1.0, 0.0, others => 0.0 ),
       ( 1.0, 1.0, others => 0.0 ) );
subtype Training_Outputs_Type is Float_Array ( 1..Sets_Count );
Training_Outputs : constant Training_Outputs_Type
  := ( 0.0, 1.0, 1.0, 0.0 );
type Training_Sets_Type is
       record
	 Training_Inputs  : Training_Inputs_Type;
	 Training_Outputs : Training_Outputs_Type;
       end record;
Training_Sets : constant Training_Sets_Type
  := ( Training_Inputs  => Training_Inputs,
       Training_Outputs => Training_Outputs );

procedure Net (
	    Neuron_Count  : in positive;
	    Training_Sets : in Training_Sets_Type ) is
---------------------------------------------------------------------------
---------------------------------------------------------------------------
  Neuron_Init : Neuron_Type :=
    ( Outputs_Count => Neuron_Count,
      Weights       => ( others => 0.5 ),
      Excitation    => 0.0,
      Charge        => 1.0,
      Is_Trained    => true );
  type Net_Type is array ( 1..Neuron_Count )
    of Neuron_Type ( Neuron_Count );
  Net : Net_Type := ( others => Neuron_Init );
  States : Float_Array ( 1..Neuron_Count );
  Next_States : Float_Array ( States'range ) := States;
  Layer : positive;
  Not_Trained : boolean;
  Old_Net : Net_Type;
  Output_Time : constant := 2;    -- := Layers!
  Propagation : integer;
  Weights_Unchanged : boolean;
---------------------------------------------------------------------------
---------------------------------------------------------------------------
begin
  for Main_Loop in 1..100 loop
    Not_Trained := true;
    Weights_Unchanged := true;
    for index in Net'range loop
      Weights_Unchanged := Weights_Unchanged and
	( Old_Net ( index ).Weights = Net ( index ).Weights );
      exit when not Weights_Unchanged;
    end loop;
    if Weights_Unchanged and then ( Main_Loop /= 1 ) then
      Put_Line ( "Weights unchanged." );
      Pause;
      DC_Scrn.ClrScr;
    end if;
    Old_Net := Net;
    for index3 in 1..Sets_Count loop
--      DC_Scrn.ClrScr;
      States := Training_Sets.Training_Inputs ( index3 );
--      for index in Net'range loop
--        Net ( index ).Is_Trained := false;
--      end loop;
      Propagation := 0;
      loop
	Propagation := Propagation + 1;
--        DC_Scrn.ClrScr;
	DC_Curs.Move ( 0, 0 );
	Put_Line ( "Main Loop" & integer'image ( Main_Loop )
	  & " Training Set" & integer'image ( index3 )
	  & " Propagation" & integer'image ( Propagation ) & " " );
	Put_Line ( "" );
	Put_Line ( "Input States" );
	Float_Array_Show ( States );
	Put_Line ( "" );
	Put_Line ( "" );
	Put_Line ( "Original Weights" );
	for index in Net'range loop
	  Neuron_Show ( Net ( index ) );
	  Put_Line ( "" );
	end loop;
	Put_Line ( "" );
	for index in Net'range loop
	  for index8 in index..Neuron_Count loop
	    Net ( index ).Weights ( index8 ) := 0.0;
	  end loop;
	  Neuron_Resolve ( States, Net ( index ), Next_States ( index ) );
	  if Net ( index ).Charge < 1.0 then
	    if index = 5 then
	      Layer := 2;
	    else
	      Layer := 1;
	    end if;
	    Net ( index ).Charge := Net ( index ).Charge
	      + ( 0.25 / float ( Layer ) );
	  end if;
	  if index in ( 1..2 ) then
	    Net ( index ).Weights := ( others => 0.0 );
	  end if;
	end loop;
	States := Next_States;
	Put_Line ( "Output States" );
	Float_Array_Show ( States );
	Put_Line ( "" );
	Put_Line ( "" );
	if Propagation mod Output_Time = 0 then
	  for index in 1..2 loop
	    States ( index )
	      := Training_Sets.Training_Inputs ( index3 ) ( index );
	    Net ( index ).Is_Trained := false;
	  end loop;
	end if;
	Put_Line ( "Adjusted Weights" );
	Net ( 4 ).Weights ( 3 ) := 0.0;
	Net ( 5 ).Weights ( 1 ) := 0.0;
	Net ( 5 ).Weights ( 2 ) := 0.0;
	for index in Net'range loop
	  for index11 in index..Net'last loop
	    Net ( index ).Weights ( index11 ) := 0.0;
	  end loop;
	  Neuron_Show ( Net ( index ) );
	  Put_Line ( "" );
	end loop;
	Put_Line ( "" );
	if Weights_Unchanged or else ( Main_Loop >= 20 ) then
	  Pause;
	end if;
--        Pause;
	exit when ( Propagation mod Output_Time = 0 ) and then
	  (
	    ( States ( Neuron_Count )
	      = Training_Sets.Training_Outputs ( index3 )
	    ) and then
	    (
	      ( Net ( Neuron_Count ).Charge >= 1.0 ) or else
	      ( States ( Neuron_Count ) >= 1.0 )
	    )
	  );
	Not_Trained := false;
      end loop;
      for index in Net'range loop
	Net ( index ).Excitation := 0.0;
	Net ( index ).Charge := 1.0;
      end loop;
    end loop;
    exit when Not_Trained;
  end loop;
end Net;

begin
  DC_Scrn.ClrScr;
  Net ( Neuron_Count => Neuron_Count,
	Training_Sets => Training_Sets );
  Put_Line ( "" );
  Put_Line ( "Network trained." );
  Pause;
---------------------------------------------------------------------------
---------------------------------------------------------------------------
---------------------------------------------------------------------------
end XOR_Net;
