public override void Learn(SequenceData trainingData, SequenceData validationData, SequenceData testData)
        {
            //HMMGraph graph = RandomGraph(trainingData.NumSymbols);
            HMMGraph graph;
            //bestHMM = ModelConverter.Graph2HMM(graph);
            bestHMM = SparseHiddenMarkovModel.FromCompleteGraph(trainingData.NumSymbols, trainingData.NumSymbols);

            bestHMM.Learn(trainingData.GetNonempty(), baumwelchThreshold);

            //while (bestHMM.States < maxStates)
            while (bestHMM.NumberOfStates < maxStates)
            {
                WriteLine("Taking one more iteration");

                //graph = ModelConverter.HMM2Graph(bestHMM);
                graph = bestHMM.ToGraph();

                Dictionary<int, double> nodePerformance = new Dictionary<int, double>();
                Dictionary<int, int> nodeOccurence = new Dictionary<int, int>();
                double hiddenStateSequenceProbability;
                foreach (int[] signal in validationData.GetNonempty())
                {
                    //int[] hiddenStateSequence = bestHMM.Decode(signal, out hiddenStateSequenceProbability);
                    int[] hiddenStateSequence = bestHMM.Viterby(signal, out hiddenStateSequenceProbability);

                    for (int j = 0; j < hiddenStateSequence.Length; j++)
                    {
                        if (nodePerformance.ContainsKey(hiddenStateSequence[j]))
                        {
                            //nodePerformance[hiddenStateSequence[j]] += (Math.Log(hiddenStateSequenceProbability) + Math.Log(bestHMM.Emissions[hiddenStateSequence[j], signal[j]]));
                            nodePerformance[hiddenStateSequence[j]] += (Math.Log(hiddenStateSequenceProbability) + Math.Log(bestHMM.EmissionProbability(hiddenStateSequence[j], signal[j])));
                            nodeOccurence[hiddenStateSequence[j]]++;
                        }
                        else
                        {
                            nodePerformance.Add(hiddenStateSequence[j], (Math.Log(hiddenStateSequenceProbability) + Math.Log(bestHMM.EmissionProbability(hiddenStateSequence[j], signal[j]))));
                            nodeOccurence.Add(hiddenStateSequence[j], 1);
                        }
                    }
                }

                foreach (int node in nodeOccurence.Keys)
                {
                    nodePerformance[node] /= nodeOccurence[node];
                }

                int weakPoint = nodePerformance.Keys.Aggregate((a, b) => ((nodePerformance[b] < nodePerformance[a]) ? b : a));
                SplitWorstPerformingNode(graph, weakPoint);

                //bestHMM = ModelConverter.Graph2HMM(graph);
                bestHMM = SparseHiddenMarkovModel.FromGraph(graph);

                WriteLine("Running BaumWelch");
                bestHMM.Learn(trainingData.GetNonempty(), baumwelchThreshold); //Run the BaumWelch algorithm

                WriteLine("");
                WriteLine("Log Likelihood: " + LogLikelihood(bestHMM, trainingData));
            }
        }
        public override void Learn(SequenceData trainingData, SequenceData validationData, SequenceData testData) {
            HMMGraph graph = new HMMGraph(trainingData.NumSymbols);

            //Add nodes and set initial and emission probabilities
            for (int i = 0; i < states; i++) {
                Node new_node = new Node();
                for (int s = 0; s < trainingData.NumSymbols; s++)
                    new_node.SetEmission(s, ran.NextDouble());
                new_node.InitialProbability = ran.NextDouble();
                graph.AddNode(new_node);
            }


            //Add random transmissions. Each node will have at most Log(n) edges in both directions
            //for (int i = 0; i < graph.Nodes.Count; i++)
            //{
            //    List<Node> shuffled = graph.Nodes.Select(e => e).ToList();
            //    Utilities.Shuffle(shuffled);
            //    int upperBound = (int)Math.Ceiling(Math.Log(graph.Nodes.Count));
            //    if (upperBound >= graph.Nodes.Count)
            //        upperBound = graph.Nodes.Count - 1;
            //    for (int p = 0; p <= upperBound; p++)
            //    {
            //        Node from = graph.Nodes[i];
            //        Node to = graph.Nodes[p];
            //        from.SetTransition(to, ran.NextDouble());
            //    }
            //}

            int numberOfTransitions = (int)Math.Ceiling(Math.Log(states));

            foreach (Node node in graph.Nodes)
            {
                for (int i = 0; i < numberOfTransitions; i++)
                {
                    Node target;
                    while (node.Transitions.ContainsKey(target = graph.Nodes[ran.Next(states)]));

                    node.SetTransition(target, ran.NextDouble());
                }
            }

            graph.Normalize();
			hmm = SparseHiddenMarkovModel.FromGraph(graph);
            hmm.Learn(trainingData.GetNonempty(), tolerance);
        }