C# QR Decomp Example

[TOC]

using System;

using CenterSpace.NMath.Core;
using CenterSpace.NMath.Matrix;

namespace CenterSpace.NMath.Matrix.Examples.CSharp
{
  /// <summary>
  /// A .NET example in C# demonstrating the features of the QR decomposition classes.
  /// </summary>
  class QRDecompExample
  {

    static void Main(string[] args)
    {
      // A general m x n system with random entries.
      RandGenUniform rng = new RandGenUniform(-1, 1);
      rng.Reset(0x124);
      int rows = 6;
      int cols = 3;
      DoubleMatrix A = new DoubleMatrix(rows, cols, rng);

      // Construct a QR decomposition of A.
      DoubleQRDecomp decomp = new DoubleQRDecomp(A);

      // Look at the components of the factorization AP = QR.
      Console.WriteLine();
      Console.WriteLine("Q = {0}", decomp.Q.ToString("F4"));

      Console.WriteLine();
      Console.WriteLine("R = {0}", decomp.R.ToString("F4"));

      Console.WriteLine();
      Console.WriteLine("P = {0}", decomp.P);

      // Q = 6x3 [ -0.1871  0.5159  0.0534  
      //            0.0654 -0.3618  0.0361 
      //            0.1424  0.3315 -0.4280
      //            0.2198 -0.5969 -0.5066
      //            0.7840  0.0122  0.5601  
      //           -0.5267 -0.3695  0.4922 ]
      //
      // R = 3x3 [ -1.1782  0.2637 0.1833 
      //            0.0000 -0.8685 -0.0966
      //            0.0000  0.0000 0.7454 ]
      //
      // P = 3x3 [ 0 1 0 
      //           0 0 1 
      //           1 0 0 ]

      // Usually, you do not need to access the components of the 
      // decomposition explicitly. There are member functions for
      // multiplying by the decomposition components without 
      // explicitly constructing them. As an example, let's solve
      // the least squares problem Ax = b using a QR decomposition.
      // To do this we write A = QR, compute the vector QTb 
      // (QT is the transpose of the matrix Q), and solve the upper-
      // triagular system Rx = QTb for x. (NOTE: the NMath Matrix library
      // contains class DoubleQRLeastSq for solving least squares problems
      // using a QR decomposition).
      DoubleVector b = new DoubleVector(A.Rows, rng);
      DoubleVector w = decomp.QTx(b);
      DoubleVector x = decomp.Px(decomp.RInvx(w));

      Console.WriteLine();
      Console.WriteLine("Least squares solution = {0}", x.ToString());

      // Note that we had to multiply by the permutation matrix to 
      // get the components of the solution back in the right order
      // since pivoting was done.
      //
      // Suppose that you wanted to compute a QR decomposition without pivoting.
      // The class DoubleQRDecompServer provides control over the pivoting 
      // stategy used by the QR decomposition algorithm.
      DoubleQRDecompServer decompServer = new DoubleQRDecompServer();
      decompServer.Pivoting = false;

      // Use the server to get a decomposition that was computed without pivoting.
      decomp = decompServer.GetDecomp(A);

      // The permutation matrix should be I, the identity matrix.
      Console.WriteLine();
      Console.WriteLine("P with no pivoting: {0}", decomp.P.ToString());

      // Use the decomposition to solve the least squares problem again. This
      // time we do not need to multiply by P.
      w = decomp.QTx(b);
      x = decomp.RInvx(w);

      Console.WriteLine();
      Console.WriteLine("Solution to the least squares problem with no pivoting:");
      Console.WriteLine(x.ToString());

      // You can also set the columns of A to be 'initial' columns. If the ith column
      // of A is set to be an intial column, it is moved to the beginning of AP 
      // before the computation, and fixed in place during the computation. If a 
      // column of A is set to be a 'free' column, it may be interchanged during the
      // computation with any other free column.
      decompServer.SetInitialColumn(0); // Do not move the first column of A.
      decomp = decompServer.GetDecomp(A);
      decompServer.SetFreeColumn(0); // Set the first column back to a free column.

      Console.WriteLine();
      Console.WriteLine("Press Enter Key");
      Console.Read();
    }
  }
}

[TOC]