/// <summary>
        ///   Constructs a new potential function modeling Hidden Markov Models.
        /// </summary>
        ///
        /// <param name="states">The number of states.</param>
        /// <param name="symbols">The number of symbols.</param>
        /// <param name="outputClasses">The number of output classes.</param>
        ///
        public DiscreteMarkovClassifierFunction(int states, int symbols, int outputClasses)
        {
            this.Outputs = outputClasses;
            this.Symbols = symbols;

            int factorIndex    = 0;
            var factorParams   = new List <double>();
            var factorFeatures = new List <IFeature <int> >();

            this.Factors = new FactorPotential <int> [Outputs];

            // Create features for initial class probabilities
            for (int c = 0; c < outputClasses; c++)
            {
                var stateParams   = new List <double>();
                var stateFeatures = new List <IFeature <int> >();

                var edgeParams   = new List <double>();
                var edgeFeatures = new List <IFeature <int> >();

                var classParams   = new List <double>();
                var classFeatures = new List <IFeature <int> >();


                // Create features for class labels
                classParams.Add(Math.Log(1.0 / outputClasses));
                classFeatures.Add(new OutputFeature <int>(this, c, c));

                // Create features for initial state probabilities
                for (int i = 0; i < states; i++)
                {
                    edgeParams.Add((i == 0) ? Math.Log(1.0) : Math.Log(0.0));
                    edgeFeatures.Add(new InitialFeature <int>(this, c, i));
                }

                // Create features for state transition probabilities
                for (int i = 0; i < states; i++)
                {
                    for (int j = 0; j < states; j++)
                    {
                        edgeParams.Add(Math.Log(1.0 / states));
                        edgeFeatures.Add(new TransitionFeature <int>(this, c, i, j));
                    }
                }

                // Create features for symbol emission probabilities
                for (int i = 0; i < states; i++)
                {
                    for (int k = 0; k < symbols; k++)
                    {
                        stateParams.Add(Math.Log(1.0 / symbols));
                        stateFeatures.Add(new EmissionFeature(this, c, i, k));
                    }
                }

                int startClassIndex = factorIndex;
                int startEdgeIndex  = factorIndex + classParams.Count;
                int startStateIndex = factorIndex + classParams.Count + edgeParams.Count;

                // First features and params are always belonging to classes
                Factors[c] = new DiscreteMarkovModelFactor(this, states, c, symbols,
                                                           startClassIndex, classParams.Count,  // 1. classes
                                                           startEdgeIndex, edgeParams.Count,    // 2. edges
                                                           startStateIndex, stateParams.Count); // 3. states

                // 1. classes
                factorFeatures.AddRange(classFeatures);
                factorParams.AddRange(classParams);

                // 2. edges
                factorFeatures.AddRange(edgeFeatures);
                factorParams.AddRange(edgeParams);

                // 3. states
                factorFeatures.AddRange(stateFeatures);
                factorParams.AddRange(stateParams);

                factorIndex += classParams.Count + stateParams.Count + edgeParams.Count;
            }

            System.Diagnostics.Debug.Assert(factorIndex == factorParams.Count);
            System.Diagnostics.Debug.Assert(factorIndex == factorFeatures.Count);

            this.Weights  = factorParams.ToArray();
            this.Features = factorFeatures.ToArray();
        }
        /// <summary>
        ///   Constructs a new potential function modeling Hidden Markov Models.
        /// </summary>
        ///
        /// <param name="classifier">The classifier model.</param>
        /// <param name="includeClassFeatures">True to include class features (priors), false otherwise.</param>
        ///
        public DiscreteMarkovClassifierFunction(HiddenMarkovClassifier classifier, bool includeClassFeatures = true)
        {
            this.Symbols = classifier.Symbols;
            this.Outputs = classifier.Classes;

            int factorIndex    = 0;
            var factorParams   = new List <double>();
            var factorFeatures = new List <IFeature <int> >();

            this.Factors = new FactorPotential <int> [Outputs];

            // Create features for initial class probabilities
            for (int c = 0; c < classifier.Classes; c++)
            {
                var stateParams   = new List <double>();
                var stateFeatures = new List <IFeature <int> >();

                var edgeParams   = new List <double>();
                var edgeFeatures = new List <IFeature <int> >();

                var classParams   = new List <double>();
                var classFeatures = new List <IFeature <int> >();

                var model = classifier[c];

                if (includeClassFeatures)
                {
                    // Create features for class labels
                    classParams.Add(Math.Log(classifier.Priors[c]));
                    classFeatures.Add(new OutputFeature <int>(this, c, c));
                }

                // Create features for initial state probabilities
                for (int i = 0; i < model.States; i++)
                {
                    edgeParams.Add(model.Probabilities[i]);
                    edgeFeatures.Add(new InitialFeature <int>(this, c, i));
                }

                // Create features for state transition probabilities
                for (int i = 0; i < model.States; i++)
                {
                    for (int j = 0; j < model.States; j++)
                    {
                        edgeParams.Add(model.Transitions[i, j]);
                        edgeFeatures.Add(new TransitionFeature <int>(this, c, i, j));
                    }
                }

                // Create features for symbol emission probabilities
                for (int i = 0; i < model.States; i++)
                {
                    for (int k = 0; k < model.Symbols; k++)
                    {
                        stateParams.Add(model.Emissions[i, k]);
                        stateFeatures.Add(new EmissionFeature(this, c, i, k));
                    }
                }

                int startClassIndex = factorIndex;
                int startEdgeIndex  = factorIndex + classParams.Count;
                int startStateIndex = factorIndex + classParams.Count + edgeParams.Count;

                // First features and params are always belonging to classes
                Factors[c] = new DiscreteMarkovModelFactor(this, model.States, c, Symbols,
                                                           startClassIndex, classParams.Count,  // 1. classes
                                                           startEdgeIndex, edgeParams.Count,    // 2. edges
                                                           startStateIndex, stateParams.Count); // 3. states

                // 1. classes
                factorFeatures.AddRange(classFeatures);
                factorParams.AddRange(classParams);

                // 2. edges
                factorFeatures.AddRange(edgeFeatures);
                factorParams.AddRange(edgeParams);

                // 3. states
                factorFeatures.AddRange(stateFeatures);
                factorParams.AddRange(stateParams);

                factorIndex += classParams.Count + stateParams.Count + edgeParams.Count;
            }

            System.Diagnostics.Debug.Assert(factorIndex == factorParams.Count);
            System.Diagnostics.Debug.Assert(factorIndex == factorFeatures.Count);

            this.Weights  = factorParams.ToArray();
            this.Features = factorFeatures.ToArray();
        }