/// <summary>
 /// Setup the network logic, read parameters from the network.
 /// </summary>
 /// <param name="network">The network that this logic class belongs to.</param>
 public override void Init(BasicNetwork network)
 {
     base.Init(network);
     // hold references to parts of the network we will need later
     this.thermalLayer = this.Network.GetLayer(BasicNetwork.TAG_INPUT);
     this.thermalSynapse = this.Network.Structure.FindSynapse(this.thermalLayer, this.thermalLayer, true);
     this.currentState = new BiPolarNeuralData(this.thermalLayer.NeuronCount);
 }
        /// <summary>
        /// Setup the network logic, read parameters from the network.
        /// </summary>
        /// <param name="network">The network that this logic class belongs to.</param>
        public override void Init(BasicNetwork network)
        {
            base.Init(network);

            this.layerF1 = this.Network.GetLayer(ART1Pattern.TAG_F1);
            this.layerF2 = this.Network.GetLayer(ART1Pattern.TAG_F2);
            this.inhibitF2 = new bool[this.layerF2.NeuronCount];
            this.synapseF1toF2 = this.Network.Structure.FindSynapse(this.layerF1, this.layerF2, true);
            this.synapseF2toF1 = this.Network.Structure.FindSynapse(this.layerF2, this.layerF1, true);
            this.outputF1 = new BiPolarNeuralData(this.layerF1.NeuronCount);
            this.outputF2 = new BiPolarNeuralData(this.layerF2.NeuronCount);

            this.a1 = this.Network.GetPropertyDouble(ARTLogic.PROPERTY_A1);
            this.b1 = this.Network.GetPropertyDouble(ARTLogic.PROPERTY_B1);
            this.c1 = this.Network.GetPropertyDouble(ARTLogic.PROPERTY_C1);
            this.d1 = this.Network.GetPropertyDouble(ARTLogic.PROPERTY_D1);
            this.l = this.Network.GetPropertyDouble(ARTLogic.PROPERTY_L);
            this.vigilance = this.Network.GetPropertyDouble(ARTLogic.PROPERTY_VIGILANCE);

            this.noWinner = this.layerF2.NeuronCount;
            Reset();

        }
        /// <summary>
        /// Compute the output for the BasicNetwork class.
        /// </summary>
        /// <param name="input">The input to the network.</param>
        /// <param name="useHolder">The NeuralOutputHolder to use.</param>
        /// <returns>The output from the network.</returns>
        public override INeuralData Compute(INeuralData input, NeuralOutputHolder useHolder)
        {
            if (!(input is BiPolarNeuralData))
            {
                String str = "Input to ART1 logic network must be BiPolarNeuralData.";
#if logging  
                if (logger.IsErrorEnabled)
                {
                    logger.Error(str);
                }
#endif
                throw new NeuralNetworkError(str);
            }

            BiPolarNeuralData output = new BiPolarNeuralData(this.layerF1.NeuronCount);
            Compute((BiPolarNeuralData)input, output);
            return output;
        }
        /// <summary>
        /// Set the input to the neural network.
        /// </summary>
        /// <param name="input">The input.</param>
        private void SetInput(BiPolarNeuralData input)
        {
            double activation;

            for (int i = 0; i < this.layerF1.NeuronCount; i++)
            {
                activation = (input.GetBoolean(i) ? 1 : 0)
                        / (1 + this.a1 * ((input.GetBoolean(i) ? 1 : 0) + this.b1) + this.c1);
                this.outputF1.SetBoolean(i, (activation > 0));
            }
        }
        /// <summary>
        /// Get the magnitude of the specified input.
        /// </summary>
        /// <param name="input">The input to calculate the magnitude for.</param>
        /// <returns>The magnitude of the specified pattern.</returns>
        public double Magnitude(BiPolarNeuralData input)
        {
            double result;

            result = 0;
            for (int i = 0; i < this.layerF1.NeuronCount; i++)
            {
                result += input.GetBoolean(i) ? 1 : 0;
            }
            return result;
        }
 /// <summary>
 /// Copy the output from the network to another object.
 /// </summary>
 /// <param name="output">The target object for the output from the network.</param>
 private void GetOutput(BiPolarNeuralData output)
 {
     for (int i = 0; i < this.layerF2.NeuronCount; i++)
     {
         output.SetBoolean(i, this.outputF2.GetBoolean(i));
     }
 }
        /// <summary>
        /// Compute the output from the F1 layer.
        /// </summary>
        /// <param name="input">The input to the F1 layer.</param>
        private void ComputeF1(BiPolarNeuralData input)
        {
            double sum, activation;

            for (int i = 0; i < this.layerF1.NeuronCount; i++)
            {
                sum = this.synapseF1toF2.WeightMatrix[i, this.winner]
                        * (this.outputF2.GetBoolean(this.winner) ? 1 : 0);
                activation = ((input.GetBoolean(i) ? 1 : 0) + this.d1 * sum - this.b1)
                        / (1 + this.a1
                                * ((input.GetBoolean(i) ? 1 : 0) + this.d1 * sum) + this.c1);
                this.outputF1.SetBoolean(i, activation > 0);
            }
        }
        /// <summary>
        /// Compute the output from the ART1 network.  This can be called directly
        /// or used by the BasicNetwork class.  Both input and output should be
        /// bipolar numbers.
        /// </summary>
        /// <param name="input">The input to the network.</param>
        /// <param name="output">The output from the network.</param>
        public void Compute(BiPolarNeuralData input,
                 BiPolarNeuralData output)
        {
            int i;
            bool resonance, exhausted;
            double magnitudeInput1, magnitudeInput2;

            for (i = 0; i < this.layerF2.NeuronCount; i++)
            {
                this.inhibitF2[i] = false;
            }
            resonance = false;
            exhausted = false;
            do
            {
                SetInput(input);
                ComputeF2();
                GetOutput(output);
                if (this.winner != this.noWinner)
                {
                    ComputeF1(input);
                    magnitudeInput1 = Magnitude(input);
                    magnitudeInput2 = Magnitude(this.outputF1);
                    if ((magnitudeInput2 / magnitudeInput1) < this.vigilance)
                    {
                        this.inhibitF2[this.winner] = true;
                    }
                    else
                    {
                        resonance = true;
                    }
                }
                else
                {
                    exhausted = true;
                }
            } while (!(resonance || exhausted));
            if (resonance)
            {
                AdjustWeights();
            }
        }