public void RunTest2()
        {
            // Example from Edwin Chen, Introduction to Restricted Boltzmann Machines
            // http://blog.echen.me/2011/07/18/introduction-to-restricted-Boltzmann-machines/

            double[][] inputs =
            {
                new double[] { 1, 1, 1, 0, 0, 0 },
                new double[] { 1, 0, 1, 0, 0, 0 },
                new double[] { 1, 1, 1, 0, 0, 0 },
                new double[] { 0, 0, 1, 1, 1, 0 },
                new double[] { 0, 0, 1, 1, 0, 0 },
                new double[] { 0, 0, 1, 1, 1, 0 }
            };

            Accord.Math.Tools.SetupGenerator(0);
            BernoulliFunction.Random = new ThreadSafeRandom(0);
            GaussianFunction.Random.SetSeed(0);

            RestrictedBoltzmannMachine network =
                RestrictedBoltzmannMachine.CreateGaussianBernoulli(6, 2);

            new GaussianWeights(network).Randomize();
            network.UpdateVisibleWeights();


            ContrastiveDivergenceLearning target = new ContrastiveDivergenceLearning(network);

            target.Momentum     = 0;
            target.LearningRate = 0.1;
            target.Decay        = 0;

            int iterations = 5000;

            double[] errors = new double[iterations];
            for (int i = 0; i < iterations; i++)
            {
                errors[i] = target.RunEpoch(inputs);
            }

            double startError = errors[0];
            double lastError  = errors[iterations - 1];

            Assert.IsTrue(startError > lastError);

            {
                double[] output = network.GenerateOutput(new double[] { 0, 0, 0, 1, 1, 0 });
                Assert.AreEqual(2, output.Length);
                Assert.AreEqual(1, output[0]);
                Assert.AreEqual(0, output[1]);
            }

            {
                double[] output = network.GenerateOutput(new double[] { 1, 1, 1, 0, 0, 0 });
                Assert.AreEqual(2, output.Length);
                Assert.AreEqual(1, output[0]);
                Assert.AreEqual(1, output[1]);
            }
        }
        private static RestrictedBoltzmannMachine createNetwork(double[][] inputs)
        {
            RestrictedBoltzmannMachine network = new RestrictedBoltzmannMachine(6, 2);

            network.Hidden.Neurons[0].Weights[0] = 0.00461421;
            network.Hidden.Neurons[0].Weights[1] = 0.04337112;
            network.Hidden.Neurons[0].Weights[2] = -0.10839599;
            network.Hidden.Neurons[0].Weights[3] = -0.06234004;
            network.Hidden.Neurons[0].Weights[4] = -0.03017057;
            network.Hidden.Neurons[0].Weights[5] = 0.09520391;
            network.Hidden.Neurons[0].Threshold  = 0;

            network.Hidden.Neurons[1].Weights[0] = 0.08263872;
            network.Hidden.Neurons[1].Weights[1] = -0.118437;
            network.Hidden.Neurons[1].Weights[2] = -0.21710971;
            network.Hidden.Neurons[1].Weights[3] = 0.02332903;
            network.Hidden.Neurons[1].Weights[4] = 0.00953116;
            network.Hidden.Neurons[1].Weights[5] = 0.09870652;
            network.Hidden.Neurons[1].Threshold  = 0;

            network.Visible.Neurons[0].Threshold = 0;
            network.Visible.Neurons[1].Threshold = 0;
            network.Visible.Neurons[2].Threshold = 0;
            network.Visible.Neurons[3].Threshold = 0;
            network.Visible.Neurons[4].Threshold = 0;
            network.Visible.Neurons[5].Threshold = 0;

            network.Visible.CopyReversedWeightsFrom(network.Hidden);


            ContrastiveDivergenceLearning target = new ContrastiveDivergenceLearning(network);

            int iterations = 5000;

            double[] errors = new double[iterations];
            for (int i = 0; i < iterations; i++)
            {
                errors[i] = target.RunEpoch(inputs);
            }

            return(network);
        }
        public void RunTest()
        {
            Accord.Math.Tools.SetupGenerator(0);

            // Example from Edwin Chen, Introduction to Restricted Boltzmann Machines
            // http://blog.echen.me/2011/07/18/introduction-to-restricted-Boltzmann-machines/

            double[][] inputs =
            {
                new double[] { 1, 1, 1, 0, 0, 0 },
                new double[] { 1, 0, 1, 0, 0, 0 },
                new double[] { 1, 1, 1, 0, 0, 0 },
                new double[] { 0, 0, 1, 1, 1, 0 },
                new double[] { 0, 0, 1, 1, 0, 0 },
                new double[] { 0, 0, 1, 1, 1, 0 }
            };

            BernoulliFunction activation = new BernoulliFunction();

            BernoulliFunction.Random = new ThreadSafeRandom(2);
            RestrictedBoltzmannMachine network = new RestrictedBoltzmannMachine(activation, 6, 2);

            network.Hidden.Neurons[0].Weights[0] = 0.00461421;
            network.Hidden.Neurons[0].Weights[1] = 0.04337112;
            network.Hidden.Neurons[0].Weights[2] = -0.10839599;
            network.Hidden.Neurons[0].Weights[3] = -0.06234004;
            network.Hidden.Neurons[0].Weights[4] = -0.03017057;
            network.Hidden.Neurons[0].Weights[5] = 0.09520391;
            network.Hidden.Neurons[0].Threshold  = 0;

            network.Hidden.Neurons[1].Weights[0] = 0.08263872;
            network.Hidden.Neurons[1].Weights[1] = -0.118437;
            network.Hidden.Neurons[1].Weights[2] = -0.21710971;
            network.Hidden.Neurons[1].Weights[3] = 0.02332903;
            network.Hidden.Neurons[1].Weights[4] = 0.00953116;
            network.Hidden.Neurons[1].Weights[5] = 0.09870652;
            network.Hidden.Neurons[1].Threshold  = 0;

            network.Visible.Neurons[0].Threshold = 0;
            network.Visible.Neurons[1].Threshold = 0;
            network.Visible.Neurons[2].Threshold = 0;
            network.Visible.Neurons[3].Threshold = 0;
            network.Visible.Neurons[4].Threshold = 0;
            network.Visible.Neurons[5].Threshold = 0;

            network.Visible.CopyReversedWeightsFrom(network.Hidden);

            ContrastiveDivergenceLearning target = new ContrastiveDivergenceLearning(network);

            target.Momentum     = 0;
            target.LearningRate = 0.1;
            target.Decay        = 0;

            int iterations = 5000;

            double[] errors = new double[iterations];
            for (int i = 0; i < iterations; i++)
            {
                errors[i] = target.RunEpoch(inputs);
            }

            double startError = errors[0];
            double lastError  = errors[iterations - 1];

            Assert.IsTrue(startError > lastError);

            Assert.AreEqual(9.5400234262580224, startError, 0.1);
            Assert.AreEqual(1.3364496250348414, lastError, 0.3);

            {
                double[] output = network.GenerateOutput(new double[] { 0, 0, 0, 1, 1, 0 });
                Assert.AreEqual(2, output.Length);
                Assert.AreEqual(0, output[0]);
                Assert.AreEqual(1, output[1]);
            }

            {
                double[] output = network.GenerateOutput(new double[] { 1, 1, 1, 0, 0, 0 });
                Assert.AreEqual(2, output.Length);
                Assert.AreEqual(1, output[0]);
                Assert.AreEqual(0, output[1]);
            }
        }
        private static RestrictedBoltzmannMachine createNetwork(double[][] inputs)
        {
            RestrictedBoltzmannMachine network = new RestrictedBoltzmannMachine(6, 2);

            network.Hidden.Neurons[0].Weights[0] = 0.00461421;
            network.Hidden.Neurons[0].Weights[1] = 0.04337112;
            network.Hidden.Neurons[0].Weights[2] = -0.10839599;
            network.Hidden.Neurons[0].Weights[3] = -0.06234004;
            network.Hidden.Neurons[0].Weights[4] = -0.03017057;
            network.Hidden.Neurons[0].Weights[5] = 0.09520391;
            network.Hidden.Neurons[0].Threshold = 0;

            network.Hidden.Neurons[1].Weights[0] = 0.08263872;
            network.Hidden.Neurons[1].Weights[1] = -0.118437;
            network.Hidden.Neurons[1].Weights[2] = -0.21710971;
            network.Hidden.Neurons[1].Weights[3] = 0.02332903;
            network.Hidden.Neurons[1].Weights[4] = 0.00953116;
            network.Hidden.Neurons[1].Weights[5] = 0.09870652;
            network.Hidden.Neurons[1].Threshold = 0;

            network.Visible.Neurons[0].Threshold = 0;
            network.Visible.Neurons[1].Threshold = 0;
            network.Visible.Neurons[2].Threshold = 0;
            network.Visible.Neurons[3].Threshold = 0;
            network.Visible.Neurons[4].Threshold = 0;
            network.Visible.Neurons[5].Threshold = 0;

            network.Visible.CopyReversedWeightsFrom(network.Hidden);


            ContrastiveDivergenceLearning target = new ContrastiveDivergenceLearning(network);

            int iterations = 5000;
            double[] errors = new double[iterations];
            for (int i = 0; i < iterations; i++)
                errors[i] = target.RunEpoch(inputs);

            return network;
        }
        public void NetworkTest2()
        {
            // Create some sample inputs and outputs. Note that the
            // first four vectors belong to one class, and the other
            // four belong to another (you should see that the 1s
            // accumulate on the beginning for the first four vectors
            // and on the end for the second four).

            double[][] inputs =
            {
                new double[] { 1,1,1,0,0,0 }, // class a
                new double[] { 1,0,1,0,0,0 }, // class a
                new double[] { 1,1,1,0,0,0 }, // class a
                new double[] { 0,0,1,1,1,0 }, // class b
                new double[] { 0,0,1,1,0,0 }, // class b
                new double[] { 0,0,1,1,1,0 }, // class b
            };

            double[][] outputs =
            {
                new double[] { 1, 0 }, // indicates the inputs at this
                new double[] { 1, 0 }, // position belongs to class a
                new double[] { 1, 0 },
                new double[] { 0, 1 }, // indicates the inputs at this
                new double[] { 0, 1 }, // position belongs to class b
                new double[] { 0, 1 },
            };

            // Create a Bernoulli activation function
            var function = new BernoulliFunction(alpha: 0.5);

            // Create a Restricted Boltzmann Machine for 6 inputs and with 1 hidden neuron
            var rbm = new RestrictedBoltzmannMachine(function, inputsCount: 6, hiddenNeurons: 2);

            // Create the learning algorithm for RBMs
            var teacher = new ContrastiveDivergenceLearning(rbm)
            {
                Momentum = 0,
                LearningRate = 0.1,
                Decay = 0
            };

            // learn 5000 iterations
            for (int i = 0; i < 5000; i++)
                teacher.RunEpoch(inputs);

            // Compute the machine answers for the given inputs:
            double[] a = rbm.Compute(new double[] { 1, 1, 1, 0, 0, 0 }); // { 0.99, 0.00 }
            double[] b = rbm.Compute(new double[] { 0, 0, 0, 1, 1, 1 }); // { 0.00, 0.99 }

            // As we can see, the first neuron responds to vectors belonging
            // to the first class, firing 0.99 when we feed vectors which 
            // have 1s at the beginning. Likewise, the second neuron fires 
            // when the vector belongs to the second class.

            // We can also generate input vectors given the classes:
            double[] xa = rbm.GenerateInput(new double[] { 1, 0 }); // { 1, 1, 1, 0, 0, 0 }
            double[] xb = rbm.GenerateInput(new double[] { 0, 1 }); // { 0, 0, 1, 1, 1, 0 }

            // As we can see, if we feed an output pattern where the first neuron
            // is firing and the second isn't, the network generates an example of
            // a vector belonging to the first class. The same goes for the second
            // neuron and the second class.

            Assert.IsTrue(((a[0] > a[1]) && (b[0] < b[1])) 
                        ^ ((a[0] < a[1]) && (b[0] > b[1])));
        }
        public void NetworkTest2()
        {
            // Create some sample inputs and outputs. Note that the
            // first four vectors belong to one class, and the other
            // four belong to another (you should see that the 1s
            // accumulate on the beginning for the first four vectors
            // and on the end for the second four).

            double[][] inputs =
            {
                new double[] { 1, 1, 1, 0, 0, 0 }, // class a
                new double[] { 1, 0, 1, 0, 0, 0 }, // class a
                new double[] { 1, 1, 1, 0, 0, 0 }, // class a
                new double[] { 0, 0, 1, 1, 1, 0 }, // class b
                new double[] { 0, 0, 1, 1, 0, 0 }, // class b
                new double[] { 0, 0, 1, 1, 1, 0 }, // class b
            };

            double[][] outputs =
            {
                new double[] { 1, 0 }, // indicates the inputs at this
                new double[] { 1, 0 }, // position belongs to class a
                new double[] { 1, 0 },
                new double[] { 0, 1 }, // indicates the inputs at this
                new double[] { 0, 1 }, // position belongs to class b
                new double[] { 0, 1 },
            };

            // Create a Bernoulli activation function
            var function = new BernoulliFunction(alpha: 0.5);

            // Create a Restricted Boltzmann Machine for 6 inputs and with 1 hidden neuron
            var rbm = new RestrictedBoltzmannMachine(function, inputsCount: 6, hiddenNeurons: 2);

            // Create the learning algorithm for RBMs
            var teacher = new ContrastiveDivergenceLearning(rbm)
            {
                Momentum     = 0,
                LearningRate = 0.1,
                Decay        = 0
            };

            // learn 5000 iterations
            for (int i = 0; i < 5000; i++)
            {
                teacher.RunEpoch(inputs);
            }

            // Compute the machine answers for the given inputs:
            double[] a = rbm.Compute(new double[] { 1, 1, 1, 0, 0, 0 }); // { 0.99, 0.00 }
            double[] b = rbm.Compute(new double[] { 0, 0, 0, 1, 1, 1 }); // { 0.00, 0.99 }

            // As we can see, the first neuron responds to vectors belonging
            // to the first class, firing 0.99 when we feed vectors which
            // have 1s at the beginning. Likewise, the second neuron fires
            // when the vector belongs to the second class.

            // We can also generate input vectors given the classes:
            double[] xa = rbm.GenerateInput(new double[] { 1, 0 }); // { 1, 1, 1, 0, 0, 0 }
            double[] xb = rbm.GenerateInput(new double[] { 0, 1 }); // { 0, 0, 1, 1, 1, 0 }

            // As we can see, if we feed an output pattern where the first neuron
            // is firing and the second isn't, the network generates an example of
            // a vector belonging to the first class. The same goes for the second
            // neuron and the second class.

            Assert.IsTrue(((a[0] > a[1]) && (b[0] < b[1]))
                          ^ ((a[0] < a[1]) && (b[0] > b[1])));
        }
        public void RunTest()
        {
            // Example from Edwin Chen, Introduction to Restricted Boltzmann Machines
            // http://blog.echen.me/2011/07/18/introduction-to-restricted-boltzmann-machines/

            double[][] inputs =
            {
                new double[] { 1,1,1,0,0,0 },
                new double[] { 1,0,1,0,0,0 },
                new double[] { 1,1,1,0,0,0 },
                new double[] { 0,0,1,1,1,0 },
                new double[] { 0,0,1,1,0,0 },
                new double[] { 0,0,1,1,1,0 }
            };

            BernoulliFunction activation = new BernoulliFunction();
            BernoulliFunction.Random = new ThreadSafeRandom(2);
            RestrictedBoltzmannMachine network = new RestrictedBoltzmannMachine(activation, 6, 2);

            network.Hidden.Neurons[0].Weights[0] = 0.00461421;
            network.Hidden.Neurons[0].Weights[1] = 0.04337112;
            network.Hidden.Neurons[0].Weights[2] = -0.10839599;
            network.Hidden.Neurons[0].Weights[3] = -0.06234004;
            network.Hidden.Neurons[0].Weights[4] = -0.03017057;
            network.Hidden.Neurons[0].Weights[5] = 0.09520391;
            network.Hidden.Neurons[0].Threshold = 0;

            network.Hidden.Neurons[1].Weights[0] = 0.08263872;
            network.Hidden.Neurons[1].Weights[1] = -0.118437;
            network.Hidden.Neurons[1].Weights[2] = -0.21710971;
            network.Hidden.Neurons[1].Weights[3] = 0.02332903;
            network.Hidden.Neurons[1].Weights[4] = 0.00953116;
            network.Hidden.Neurons[1].Weights[5] = 0.09870652;
            network.Hidden.Neurons[1].Threshold = 0;

            network.Visible.Neurons[0].Threshold = 0;
            network.Visible.Neurons[1].Threshold = 0;
            network.Visible.Neurons[2].Threshold = 0;
            network.Visible.Neurons[3].Threshold = 0;
            network.Visible.Neurons[4].Threshold = 0;
            network.Visible.Neurons[5].Threshold = 0;

            network.Visible.CopyReversedWeightsFrom(network.Hidden);

            ContrastiveDivergenceLearning target = new ContrastiveDivergenceLearning(network);

            target.Momentum = 0;
            target.LearningRate = 0.1;
            target.Decay = 0;

            int iterations = 5000;
            double[] errors = new double[iterations];
            for (int i = 0; i < iterations; i++)
                errors[i] = target.RunEpoch(inputs);

            double startError = errors[0];
            double lastError = errors[iterations - 1];
            Assert.IsTrue(startError > lastError);

            Assert.AreEqual(9.5400234262580224, startError);
            Assert.AreEqual(1.3364496250348414, lastError, 1e-10);

            {
                double[] output = network.GenerateOutput(new double[] { 0, 0, 0, 1, 1, 0 });
                Assert.AreEqual(2, output.Length);
                Assert.AreEqual(0, output[0]);
                Assert.AreEqual(1, output[1]);
            }

            {
                double[] output = network.GenerateOutput(new double[] { 1, 1, 1, 0, 0, 0 });
                Assert.AreEqual(2, output.Length);
                Assert.AreEqual(1, output[0]);
                Assert.AreEqual(0, output[1]);
            }
        }
        public void RunTest2()
        {
            // Example from Edwin Chen, Introduction to Restricted Boltzmann Machines
            // http://blog.echen.me/2011/07/18/introduction-to-restricted-boltzmann-machines/

            double[][] inputs =
            {
                new double[] { 1,1,1,0,0,0 },
                new double[] { 1,0,1,0,0,0 },
                new double[] { 1,1,1,0,0,0 },
                new double[] { 0,0,1,1,1,0 },
                new double[] { 0,0,1,1,0,0 },
                new double[] { 0,0,1,1,1,0 }
            };

            Accord.Math.Tools.SetupGenerator(0);
            BernoulliFunction.Random = new ThreadSafeRandom(0);
            GaussianFunction.Random.SetSeed(0);

            RestrictedBoltzmannMachine network = 
                RestrictedBoltzmannMachine.CreateGaussianBernoulli(6, 2);

            new GaussianWeights(network).Randomize();
            network.UpdateVisibleWeights();
            

            ContrastiveDivergenceLearning target = new ContrastiveDivergenceLearning(network);

            target.Momentum = 0;
            target.LearningRate = 0.1;
            target.Decay = 0;

            int iterations = 5000;
            double[] errors = new double[iterations];
            for (int i = 0; i < iterations; i++)
                errors[i] = target.RunEpoch(inputs);

            double startError = errors[0];
            double lastError = errors[iterations - 1];
            Assert.IsTrue(startError > lastError);

            {
                double[] output = network.GenerateOutput(new double[] { 0, 0, 0, 1, 1, 0 });
                Assert.AreEqual(2, output.Length);
                Assert.AreEqual(1, output[0]);
                Assert.AreEqual(0, output[1]);
            }

            {
                double[] output = network.GenerateOutput(new double[] { 1, 1, 1, 0, 0, 0 });
                Assert.AreEqual(2, output.Length);
                Assert.AreEqual(1, output[0]);
                Assert.AreEqual(1, output[1]);
            }


        }