// https://www.tutorialspoint.com/artificial_neural_network/artificial_neural_network_hopfield.htm
        public string GetResult(string input)
        {
            if (_curentWeightsMatrix.Size != input.Length)
            {
                throw new ArgumentException("Wrong image size");
            }

            OnItemProcessed?.Invoke(this,
                                    new ProcessEventArgs(int.MaxValue)
            {
                CurrentItem = ++_iteration
            });

            _inputVector = input;
            var savedEnergyState = CurrentEnergyState;
            var output           = new StringBuilder(input);

            var nodeToUpdate = NodeToUpdate;

            output[nodeToUpdate] = ApplyActivationFunction(input, nodeToUpdate);
            _outputVector        = output.ToString();

            if (CurrentEnergyState < _localMinimum.Key)
            {
                _localMinimum = new KeyValuePair <double, string>(CurrentEnergyState, _outputVector);
            }

            if (CurrentEnergyState > savedEnergyState ||
                _nodesToUpdate.Count > 0 &&
                !FinalCheck(_outputVector))
            {
                GetResult(_outputVector);
            }

            return(_localMinimum.Value);
        }
        private void HebbianLearning(List <string> inputVectors)
        {
            var trainEventArgs = new ProcessEventArgs(_curentWeightsMatrix.Size);

            // Hebbian Rule
            for (int i = 0; i < _curentWeightsMatrix.Size; i++)
            {
                for (int j = 0; j < _curentWeightsMatrix.Size; j++)
                {
                    var weights = 0.0;
                    if (i != j)
                    {
                        foreach (string vector in inputVectors)
                        {
                            weights += (2 * double.Parse(vector[i].ToString()) - 1) *
                                       (2 * double.Parse(vector[j].ToString()) - 1);
                        }
                    }
                    _curentWeightsMatrix[i, j] = weights / _curentWeightsMatrix.Size;
                }
                trainEventArgs.CurrentItem = i + 1;
                OnItemProcessed?.Invoke(this, trainEventArgs);
            }
        }