public Network(string name, int inputs, List<int> hiddens, int outputs, Termination termination, NetworkParameters parameters = null, int constants = 1)
        {
            Name = name;
            Termination = termination;
            if (parameters != null)
            {
                parameters.Assert();
                Parameters = parameters;
            }
            HiddensLayout = hiddens;

            List<List<Neuron>> levels = new List<List<Neuron>>();
            levels.Add(Enumerable.Range(0, inputs).Select(i => new Neuron(NeuronType.Input)).ToList());
            foreach (int hidden in hiddens)
                levels.Add(Enumerable.Range(0, hidden).Select(i => new Neuron(NeuronType.Hidden)).ToList());
            levels.Add(Enumerable.Range(0, outputs).Select(i => new Neuron(NeuronType.Output)).ToList());

            // Connects to all other neurons.. except input ones (this is used as the additive "constant" value attached to each sigmoid unit.)
            List<Neuron> connectToAll = Enumerable.Range(0, constants).Select(i => new Neuron(NeuronType.Constant) { Value = 1 }).ToList();

            for (int i = 0; i + 1 < levels.Count; ++i)
            {
                foreach (Neuron n in levels[i])
                    foreach (Neuron m in levels[i + 1])
                        n.Attach(m, new Weight(Parameters.InitialWeightInterval));

                foreach (Neuron c in connectToAll)
                    foreach (Neuron m in levels[i + 1])
                        c.Attach(m, new Weight(Parameters.InitialWeightInterval));
            }

            Neurons = levels.Aggregate<List<Neuron>>((aggregated, level) => { aggregated.AddRange(level); return aggregated; }).ToList();
            Neurons.AddRange(connectToAll);
        }
        private void btnStart_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (Status == TrainStatus.Running)
                {
                    Status = TrainStatus.Paused;
                    Save();
                    return;
                }

                if (Thread != null && Thread.IsAlive)
                   Thread.Join(); // Wait for last thread to finish working before starting again.

                Termination termination;
                if (cbTerminationType.Text == "ByValidationSet")
                    termination = Termination.ByValidationSet(DataParser.ValidationSet, ToInt(tbValidateCycle, x => x > 0, "Validation cycle must be > 0"));
                else if (cbTerminationType.Text == "ByIteration")
                    termination = Termination.ByIteration(ToInt(tbIterations, x => x > 0, "Iterations must be > 0"));
                else
                    throw new Exception("Did not recognize termination type: " + cbTerminationType.Text);

                NetworkParameters parameters = new NetworkParameters()
                {
                    InitialWeightInterval = new Tuple<double, double>(ToDouble(tbInitialWeightMin), ToDouble(tbInitialWeightMax)),
                    LearningRate = ToDouble(tbLearningRate, x => x > 0, "Learning rate must be > 0"),
                    LearningRateDecay = ToDouble(tbLearningRateDecay),
                    Momentum = ToDouble(tbMomentum, x => x >= 0 && x < 1, "Momentum must be in [0,1)"),
                    MomentumDecay = ToDouble(tbMomentumDecay)
                };

                string name = ToString(tbName, s => s.Trim() != string.Empty, "Network name cannot be empty.");
                if (Status == TrainStatus.Create && Directory.Exists(name))
                {
                    if (MessageBox.Show("Neural Net folder '" + name + "' already exists. Delete contents?\r\nIf not, use a unique name.", "Error", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
                        (new DirectoryInfo(name)).Delete(true);
                    else
                        return;
                }

                if (Status == TrainStatus.Create)
                {
                    Network = new Network(
                        name,
                        ToInt(tbInputs, x => x > 0, "Number of input nodes must be > 0"),
                        tbHiddens.Text.Split(new char[] { ' ', ',', ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => ToInt(x, tbHiddens, xx => xx > 0, "Number of hidden nodes must be > 0 per layer")).ToList<int>(),
                        ToInt(tbOutputs, x => x > 0, "Number of output nodes must be > 0"),
                        termination,
                        parameters);
                }
                else
                {
                    Network.Termination.Type = termination.Type;
                    Network.Termination.ValidationSet = termination.ValidationSet;
                    Network.Termination.ValidateCycle = termination.ValidateCycle;
                    Network.Termination.TotalIterations = termination.TotalIterations;
                    Network.Parameters = parameters;
                    Network.Name = name;
                }

                Status = TrainStatus.Running;
                Thread = new Thread(new ThreadStart(DoTrain)) { IsBackground = true };
                Thread.Start();
            }
            catch (Exception x)
            {
                MessageBox.Show(x.Message, "Error");
            }
        }
        public void New()
        {
            Save();

            if (Thread != null && Thread.IsAlive)
                Thread.Join(); // Wait for last thread to finish working before starting again.

            tbName.Text = "";
            tbInputs.Text = "82";
            tbHiddens.Text = "100";
            tbOutputs.Text = "1";
            NetworkParameters parameters = new NetworkParameters();
            tbLearningRate.Text = parameters.LearningRate.ToString();
            tbLearningRateDecay.Text = parameters.LearningRateDecay.ToString();
            tbMomentum.Text = parameters.Momentum.ToString();
            tbMomentumDecay.Text = parameters.MomentumDecay.ToString();
            tbInitialWeightMin.Text = parameters.InitialWeightInterval.Item1.ToString();
            tbInitialWeightMax.Text = parameters.InitialWeightInterval.Item2.ToString();
            cbTerminationType.Text = "ByValidationSet";
            tbIterations.Text = "20000";
            tbValidateCycle.Text = "500";
            ValidationPlot.Collection.Clear();
            TrainingPlot.Collection.Clear();
            CurrentErrorHistoryIndex = 0;
            Status = TrainStatus.Create;
            lbError.Content = lbIteration.Content = lbTimeElapsed.Content = "0";
        }
 public Network(string name, int inputs, int hiddens, int outputs, Termination termination, NetworkParameters parameters = null)
     : this(name, inputs, new List<int>(){hiddens}, outputs, termination, parameters)
 {
 }