C# Independent Streams Example

← All NMath Code Examples

 

using System;

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

namespace CenterSpace.NMath.Core.Examples.CSharp
{
  /// <summary>
  /// A .NET example in C# showing how to create streams of independent random numbers.
  /// </summary>
  class IndependentStreamsExample
  {

    static void Main( string[] args )
    {
      // NMath provides classes for generating several independent streams of random
      // numbers using the leapfrog and skip-ahead (blocksplitting) methods.

      // IMPORTANT NOTE:
      // Skip-ahead and leapfrog streams are only supported for basic random number
      // generator types which provide a more efficient algorithm than generation
      // of that full sequence to pick out a required subsequence. The static variable
      // SkipAheadStream.SupportedGeneratorTypes contains a list of the supported
      // types for SkipAheadStream.

      int seed = 0x124;
      var genType = RandomNumberStream.BasicRandGenType.MultiplicativeCongruent31;

      // Create a SkipAheadRandomStreams object for generating 10 independent random number streams, 
      // each of length 100, using the Skip Ahead method.
      int numberOfStreams = 5;
      int streamLength = 1000;
      var indStreams = new SkipAheadRandomStreams( seed, genType, numberOfStreams, streamLength );

      // Create a streamLength x numberOfStreams matrix A and use the SkipAheadRandomStreams object 
      // created above to fill it with random numbers. Each of the numberOfStreams columns 
      // in the resulting matrix will contain streamLength random deviates distributed 
      // uniformly in the interval (0, 1). Each column of random numbers will 
      // be independent from the others.
      var dist = new DoubleRandomUniformDistribution();
      var A = new DoubleMatrix( streamLength, numberOfStreams );
      indStreams.Fill( dist, A );

      // Print out the correlation matrix for the sample to test
      // independence. Correlations should be near zero for independent
      // samples.
      DoubleSymmetricMatrix correlationMatrix = RankCorrelation( A, true );

      Console.WriteLine();

      Console.WriteLine( "Spearmans Rank Correlation for independent random samples:" );
      for ( int i = 0; i < correlationMatrix.Rows; i++ )
      {
        for ( int j = 0; j < i; j++ )
        {
          Console.WriteLine( "Correlation between column {0} and row {1} is {2}", i, j, correlationMatrix[i, j].ToString( "G6" ) );
        }
      }

      // You can also generate independent streams from different probability
      // distributions. Here we generate 3 streams each with a different
      // distribution using the leapfrog technique.
      numberOfStreams = 3;
      var leapfrogIndStreams = new LeapfrogRandomStreams( seed, genType, numberOfStreams, streamLength );
      var distributions = new IRandomNumberDistribution<double>[numberOfStreams];
      distributions[0] = new DoubleRandomBetaDistribution();
      distributions[1] = new DoubleRandomExponentialDistribution();
      distributions[2] = new DoubleRandomLogNormalDistribution();
      DoubleMatrix C = leapfrogIndStreams.Next( distributions );

      // Print out the rank correlation matrix for the sample to test
      // independence. Correlations should be near zero for independent
      // samples.
      correlationMatrix = RankCorrelation( C, true );
      Console.WriteLine( "\nSpearmans Rank Correlation for samples from different distributions:" );
      for ( int i = 0; i < correlationMatrix.Rows; i++ )
      {
        for ( int j = 0; j < i; j++ )
        {
          Console.WriteLine( "Correlation between column {0} and row {1} is {2}", i, j, correlationMatrix[i, j].ToString( "G6" ) );
        }
      }

      // Independent streams from discrete distributions are also supported.
      streamLength = 5;
      genType = RandomNumberStream.BasicRandGenType.WinchannHillCombined;
      leapfrogIndStreams = new LeapfrogRandomStreams( genType, numberOfStreams, streamLength );
      var discreteDistributions = new IRandomNumberDistribution<int>[numberOfStreams];
      discreteDistributions[0] = new IntRandomBernoulliDistribution( .6 );
      discreteDistributions[1] = new IntRandomGeometricDistribution( .2 );
      discreteDistributions[2] = new IntRandomPoissonDistribution( .8 );
      int[][] discreteRandomSamples = leapfrogIndStreams.Next<int>( discreteDistributions );
      // The ith independent stream is in the array discreteRandomSamples[i].
      for ( int i = 0; i < numberOfStreams; i++ )
      {
        Console.WriteLine( "\nDistribution: {0}", discreteDistributions[i].GetType() );
        for ( int j = 0; j < discreteRandomSamples[i].Length; j++ )
        {
          Console.Write( discreteRandomSamples[i][j] );
          Console.WriteLine();
        }
      }

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

    /// <summary>
    /// Computes the Spearman rank correlation matrix for a set of random inputs. The random 
    /// inputs are taken to be the columns of the input matrix. The symmetric,
    /// positive definite matrix whose i,j entry is the Spearman correlation coefficient
    /// between the inputs in column i and column j is computed and returned.
    /// </summary>
    /// <param name="A">Matrix whose columns are the inputs whose Spearman rank correlation
    /// coefficient is computed.</param>
    /// <param name="useMidRankForTies">If true mid ranks are used for ranking ties.
    /// </param>
    /// <returns>The symmetric, positive definite matrix whose row i, column j 
    /// entry is  the correlation coefficient between the inputs in column i and column j
    /// </returns>
    static DoubleSymmetricMatrix RankCorrelation( DoubleMatrix A, bool useMidRankForTies )
    {
      int N = A.Rows;
      var sortedData = new double[N];
      var indices = new int[N];
      var xRanks = new DoubleVector( N );
      var yRanks = new DoubleVector( N );

      var R = new DoubleSymmetricMatrix( A.Cols );
      for ( int i = 0; i < A.Cols; i++ )
      {
        for ( int j = i; j < A.Cols; j++ )
        {
          if ( i == j )
          {
            R[i, j] = 1.0;
          }
          else
          {
            RankData( A.Col( i ), sortedData, indices, xRanks, useMidRankForTies );
            RankData( A.Col( j ), sortedData, indices, yRanks, useMidRankForTies );
            R[i, j] = RankCorrelationFromRanks( xRanks, yRanks );
          }
        }
      }
      return R;
    }

    static void RankData( DoubleVector data, double[] sortedData, int[] Indices,
      DoubleVector ranks, bool useMidRankForTies )
    {
      if ( data.Length != sortedData.Length )
      {
        throw new InvalidArgumentException( "data and sortedData arrays do not have the same length in RankData" );
      }

      if ( data.Length != Indices.Length )
      {
        throw new InvalidArgumentException( "data and Indices arrays do not have the same length in RankData" );
      }

      for ( int i = 0; i < Indices.Length; i++ )
      {
        sortedData[i] = data[i];
        Indices[i] = i;
      }
      Array.Sort<double, int>( sortedData, Indices );
      for ( int i = 0; i < sortedData.Length; i++ )
      {
        ranks[i] = Array.IndexOf<int>( Indices, i ) + 1;
      }
      if ( useMidRankForTies )
      {
        ApplyMidranks( sortedData, ranks );
      }
    }

    static void ApplyMidranks( double[] data, DoubleVector ranks )
    {
      for ( int i = 1; i < data.Length; i++ )
      {
        if ( data[i] == data[i - 1] )
        {
          int start = i - 1;
          int count = 0;
          double rankSum = 0;
          while ( start + count < data.Length && data[start] == data[start + count] )
          {
            rankSum += ranks[start + count];
            ++count;
          }
          double midrank = rankSum / (double) count;
          for ( int s = 0; s < count; s++ )
          {
            ranks[start + s] = midrank;
          }
          i = start + count;
        }
      }
    }

    static double RankCorrelationFromRanks( DoubleVector xRanks, DoubleVector yRanks )
    {
      int N = xRanks.Length;
      if ( yRanks.Length != N )
      {
        throw new InvalidArgumentException( "All arrays must have same length in RankCorreleation" );
      }

      double sum = 0;
      for ( int i = 0; i < N; i++ )
      {
        double d = xRanks[i] - yRanks[i];
        sum += ( d * d );
      }
      return ( 1.0 - ( ( 6 * sum ) / ( N * ( N * N - 1 ) ) ) );
    }

  } // class

} // namespace

← All NMath Code Examples
Top