/// <summary>
        /// Creates a new Discrete Time Kalman Filter with the given values for
        /// the initial state and the covariance of that state.
        /// </summary>
        /// <param name="x0">The best estimate of the initial state of the estimate.</param>
        /// <param name="P0">The covariance of the initial state estimate. If unsure
        /// about initial state, set to a large value</param>
        public DiscreteKalmanFilter(Matrix <double> x0, Matrix <double> P0)
        {
            KalmanFilter.CheckInitialParameters(x0, P0);

            x = x0;
            P = P0;
        }
        /// <summary>
        /// Perform a discrete time prediction of the system state.
        /// </summary>
        /// <param name="F">State transition matrix.</param>
        /// <exception cref="System.ArgumentException">Thrown when the given state
        /// transition matrix does not have the same number of row/columns as there
        /// are variables in the state vector.</exception>
        public void Predict(Matrix <double> F)
        {
            KalmanFilter.CheckPredictParameters(F, this);

            x = F * x;
            P = F * P * F.Transpose();
        }
        /// <summary>
        /// Preform a discrete time prediction of the system state.
        /// </summary>
        /// <param name="F">State transition matrix.</param>
        /// <param name="Q">A plant noise covariance matrix.</param>
        /// <exception cref="System.ArgumentException">Thrown when F and Q are not
        /// square matrices with the same number of rows and columns as there are
        /// rows in the state matrix.</exception>
        /// <remarks>Performs a prediction of the next state of the Kalman Filter,
        /// where there is plant noise. The covariance matrix of the plant noise, in
        /// this case, is a square matrix corresponding to the state transition and
        /// the state of the system.</remarks>
        public void Predict(Matrix <double> F, Matrix <double> Q)
        {
            KalmanFilter.CheckPredictParameters(F, Q, this);

            // Predict the state
            x = F * x;
            P = (F * P * F.Transpose()) + Q;
        }
        /// <summary>
        /// Creates an Information filter with the given initial state.
        /// </summary>
        /// <param name="x0">Initial estimate of state variables.</param>
        /// <param name="P0">Covariance of state variable estimates.</param>
        public InformationFilter(Matrix <double> x0, Matrix <double> P0)
        {
            KalmanFilter.CheckInitialParameters(x0, P0);

            J = P0.Inverse();
            y = J * x0;
            I = Matrix <double> .Build.DenseIdentity(y.RowCount, y.RowCount);
        }
        /// <summary>
        /// Performs a prediction of the state of the system after a given transition.
        /// </summary>
        /// <param name="F">State transition matrix.</param>
        /// <exception cref="System.ArgumentException">Thrown when the given state
        /// transition matrix does not have the same number of row/columns as there
        /// are variables in the state vector.</exception>
        public void Predict(Matrix <double> F)
        {
            KalmanFilter.CheckPredictParameters(F, this);

            Matrix <double> tmpG = Matrix <double> .Build.Dense(x.RowCount, 1);

            Matrix <double> tmpQ = Matrix <double> .Build.Dense(1, 1, 1.0d);

            Predict(F, tmpG, tmpQ);
        }
        /// <summary>
        /// Creates a square root filter with given initial state.
        /// </summary>
        /// <param name="x0">Initial state estimate.</param>
        /// <param name="P0">Covariance of initial state estimate.</param>
        public SquareRootFilter(Matrix <double> x0, Matrix <double> P0)
        {
            KalmanFilter.CheckInitialParameters(x0, P0);

            // Decompose the covariance matrix
            Matrix <double>[] UDU = UDUDecomposition(P0);
            U = UDU[0];
            D = UDU[1];
            x = x0;
        }
        /// <summary>
        /// Perform a discrete time prediction of the system state.
        /// </summary>
        /// <param name="F">State transition matrix.</param>
        /// <param name="G">Noise coupling matrix.</param>
        /// <param name="Q">Plant noise covariance.</param>
        /// <exception cref="System.ArgumentException">Thrown when the column and row
        /// counts for the given matrices are incorrect.</exception>
        /// <remarks>
        /// Performs a prediction of the next state of the Kalman Filter, given
        /// a description of the dynamic equations of the system, the covariance of
        /// the plant noise affecting the system and the equations that describe
        /// the effect on the system of that plant noise.
        /// </remarks>
        public void Predict(Matrix <double> F, Matrix <double> G, Matrix <double> Q)
        {
            KalmanFilter.CheckPredictParameters(F, G, Q, this);

            // State prediction
            x = F * x;

            // Covariance update
            P = (F * P * F.Transpose()) + (G * Q * G.Transpose());
        }
        /// <summary>
        /// Updates the state of the system based on the given noisy measurements,
        /// a description of how those measurements relate to the system, and a
        /// covariance <c>Matrix</c> to describe the noise of the system.
        /// </summary>
        /// <param name="z">The measurements of the system.</param>
        /// <param name="H">Measurement model.</param>
        /// <param name="R">Covariance of measurements.</param>
        /// <exception cref="System.ArgumentException">Thrown when given matrices
        /// are of the incorrect size.</exception>
        public void Update(Matrix <double> z, Matrix <double> H, Matrix <double> R)
        {
            KalmanFilter.CheckUpdateParameters(z, H, R, this);

            // Fiddle with the matrices
            Matrix <double> HT = H.Transpose();
            Matrix <double> RI = R.Inverse();

            // Perform the update
            y = y + (HT * RI * z);
            J = J + (HT * RI * H);
        }
        /// <summary>
        /// Updates the state of the system based on the given noisy measurements,
        /// a description of how those measurements relate to the system, and a
        /// covariance <c>Matrix</c> to describe the noise of the system.
        /// </summary>
        /// <param name="z">The measurements of the system.</param>
        /// <param name="H">Measurement model.</param>
        /// <param name="R">Covariance of measurements.</param>
        /// <exception cref="System.ArgumentException">Thrown when given matrices
        /// are of the incorrect size.</exception>
        public void Update(Matrix <double> z, Matrix <double> H, Matrix <double> R)
        {
            KalmanFilter.CheckUpdateParameters(z, H, R, this);

            // We need to use transpose of H a couple of times.
            Matrix <double> Ht = H.Transpose();
            Matrix <double> I  = Matrix <double> .Build.DenseIdentity(x.RowCount, x.RowCount);

            Matrix <double> S = (H * P * Ht) + R;     // Measurement covariance
            Matrix <double> K = P * Ht * S.Inverse(); // Kalman Gain

            P = (I - (K * H)) * P;                    // Covariance update
            x = x + (K * (z - (H * x)));              // State update
        }
        /// <summary>
        /// Perform a discrete time prediction of the system state.
        /// </summary>
        /// <param name="F">State transition matrix.</param>
        /// <exception cref="System.ArgumentException">Thrown when the given state
        /// transition matrix does not have the same number of row/columns as there
        /// are variables in the state vector.</exception>
        public void Predict(Matrix <double> F)
        {
            KalmanFilter.CheckPredictParameters(F, this);

            // Easier just to convert back to discrete form....
            Matrix <double> p = J.Inverse();
            Matrix <double> x = p * y;

            x = F * x;
            p = F * p * F.Transpose();

            J = p.Inverse();
            y = J * x;
        }
        /// <summary>
        /// Creates an Information filter specifying whether the covariance and state
        /// have been 'inverted'.
        /// </summary>
        /// <param name="state">The initial estimate of the state of the system.</param>
        /// <param name="cov">The covariance of the initial state estimate.</param>
        /// <param name="inverted">Has covariance/state been converted to information
        /// filter form?</param>
        /// <remarks>This behaves the same as other constructors if the given boolean is false.
        /// Otherwise, in relation to the given state/covariance should satisfy:<BR></BR>
        /// <C>cov = J = P0 ^ -1, state = y = J * x0.</C></remarks>
        public InformationFilter(Matrix <double> state, Matrix <double> cov, bool inverted)
        {
            KalmanFilter.CheckInitialParameters(state, cov);

            if (inverted)
            {
                J = cov;
                y = state;
            }
            else
            {
                J = cov.Inverse();
                y = J * state;
            }

            I = Matrix <double> .Build.DenseIdentity(state.RowCount, state.RowCount);
        }
        /// <summary>
        /// Performs a prediction of the state of the system after a given transition.
        /// </summary>
        /// <param name="F">State transition matrix.</param>
        /// <param name="G">Noise coupling matrix.</param>
        /// <param name="Q">Noise covariance matrix.</param>
        /// <exception cref="System.ArgumentException">Thrown when the given matrices
        /// are not the correct dimensions.</exception>
        public void Predict(Matrix <double> F, Matrix <double> G, Matrix <double> Q)
        {
            KalmanFilter.CheckPredictParameters(F, G, Q, this);

            // Update the state.. that is easy!!
            x = F * x;

            // Get all the sized and create storage
            int             n    = x.RowCount;
            int             p    = G.ColumnCount;
            Matrix <double> outD = Matrix <double> .Build.Dense(n, n);         // Updated diagonal matrix

            Matrix <double> outU = Matrix <double> .Build.DenseIdentity(n, n); // Updated upper unit triangular

            // Get the UD Decomposition of the process noise matrix
            Matrix <double>[] UDU = UDUDecomposition(Q);
            Matrix <double>   Uq  = UDU[0];
            Matrix <double>   Dq  = UDU[1];

            // Combine it with the noise coupling matrix
            Matrix <double> Gh = G * Uq;

            // Convert state transition matrix
            Matrix <double> PhiU = F * U;

            // Ready to go..
            for (int i = n - 1; i >= 0; i--)
            {
                // Update the i'th diagonal of the covariance matrix
                double sigma = 0.0d;

                for (int j = 0; j < n; j++)
                {
                    sigma = sigma + (PhiU[i, j] * PhiU[i, j] * D[j, j]);
                }

                for (int j = 0; j < p; j++)
                {
                    sigma = sigma + (Gh[i, j] * Gh[i, j] * Dq[j, j]);
                }

                outD[i, i] = sigma;

                // Update the i'th row of the upper triangular of covariance
                for (int j = 0; j < i; j++)
                {
                    sigma = 0.0d;

                    for (int k = 0; k < n; k++)
                    {
                        sigma = sigma + (PhiU[i, k] * D[k, k] * PhiU[j, k]);
                    }

                    for (int k = 0; k < p; k++)
                    {
                        sigma = sigma + (Gh[i, k] * Dq[k, k] * Gh[j, k]);
                    }

                    outU[j, i] = sigma / outD[i, i];

                    for (int k = 0; k < n; k++)
                    {
                        PhiU[j, k] = PhiU[j, k] - (outU[j, i] * PhiU[i, k]);
                    }

                    for (int k = 0; k < p; k++)
                    {
                        Gh[j, k] = Gh[j, k] - (outU[j, i] * Gh[i, k]);
                    }
                }
            }

            // Update the covariance
            U = outU;
            D = outD;
        }