Skip to content

mrdcvlsc/cyfre

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

91 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cyfre

a Templated C++ matrix library


ubuntu windows

cyfre aims to provide an easy to use c++ matrix library with basic matrix operations.

started : Dec 2020

  • To use, include the main header in your code

    • #include "cyfre/cyfre.hpp"
  • compilation -D flags

    • CHECK_RANGE_DISABLE - Disable internal range checking, slightly speeds up the program (do not use in development)
    • CHECK_SHAPE_DISABLE - Disable internal shape checking of matricies in matrix operations, slightly speeds up the program (do not use in development)
    • OMPTHREAD - Enable OpenMP multi-threading / must include the openmp library -fopenmp
  • compile with OpenMP multi-threading :

    • -DOMPTHREAD -fopenmp
  • for full performance you can disable checks and enable OpenMP multi-threading :

    • -DCHECK_RANGE_DISABLE -DCHECK_SHAPE_DISABLE -DOMPTHREAD -fopenmp
  • Don't forget the optimization flags for more speed-up :

    • -O3 -march=native

Documentation

CREATING MATRIX (CONSTRUCTORS)
    identity matrix

      construct an identity matrix

      cyfre::mat<int> mat_object(cyfre::TYPE::IDENTITY,3);  /*
      
      mat_object = [[1,0,0],
                    [0,1,0],
                    [0,0,1]]
      
      */
    scalar matrix

      construct an scalar matrix

      cyfre::mat<int> mat_object(cyfre::TYPE::SCALARMATRIX,3,7);  /*
      
      mat_object = [[7,0,0],
                    [0,7,0],
                    [0,0,7]]
      
      */
    zero/null matrix

      construct an zero/null matrix

      cyfre::mat<int> mat_object(cyfre::TYPE::NULLZERO,3);  /*
      
      mat_object = [[0,0,0],
                    [0,0,0],
                    [0,0,0]]
      
      */
    shaped matrix with initial value

      construct an costum shaped matrix, with initial values

      cyfre::mat<int> mat_object(3,2,5);  /*
      
      mat_object = [[5,5],
                    [5,5],
                    [5,5]]
      
      */
    shaped matrix with random values

      ex. constructs a 4x5 matrix with random integer values ranging from 10-99

      cyfre::mat<int> INT_MATRIX(4,5,cyfre::RANDOM::INTEGER,10,99);

      ex. constructs a 3x3 matrix with random real values ranging from 0.0-1.0

      cyfre::mat<double> FLOAT_MATRIX(4,5,cyfre::RANDOM::REAL,0,1);
    defined matrix (row)

      construct and define a matrix

      cyfre::mat<int> mat_object({5,10,15,20,25});
      
      // mat_object = [[5,10,15,20,25]] <-- (1x5 matrix)
    defined matrix (2D)

      construct and define a matrix

      cyfre::mat<int> mat_object({
        {1,2,3},
        {4,5,6},
        {7,8,9}
      });
      
      /*
        mat_object = [[1,2,3],
                      [4,5,6],
                      [7,8,9]]
      */
    read matrix from a txt file

      matrix1.txt

      23 12 53 34 23
      33 77 53 90 28
      87 26 11 24 31
      84 32 73 64 26
      77 88 45 97 86
      cyfre::mat<int> mat_object("matrix1.txt",' ');  /*
      
      mat_object = [
        [23,12,53,34,23]
        [33,77,53,90,28]
        [87,26,11,24,31]
        [84,32,73,64,26]
        [77,88,45,97,86]
      ]
      
      */
ELEMENTARY ROW/COLUMN OPERATIONS
    • basic elementary row/column operations
      swaping rows/columns

        row_swap(row1,row2)

        cyfre::mat<int> mat_object({
          {1,2,3},
          {4,5,6},
          {7,8,9}
        });
        
        mat_object.row_swap(1,2);  /*
        
        mat_object = [[ 1, 2, 3],
                      [ 7, 8, 9],
                      [ 4, 5, 6]]
        
        */
      scaling rows/columns

        row_scale(scalar_value,row_to_scale)

        cyfre::mat<int> mat_object({
          {1,2,3},
          {4,5,6},
          {7,8,9}
        });
        
        mat_object.row_scale(5,0);  /*
        
        mat_object = [[ 5,10,15],
                      [ 4, 5, 6],
                      [ 7, 8, 9]]
        
        */
      scale a row/column then add the products to another row/column

        row_scale(scalar_value,row_to_scale,base_row)

        cyfre::mat<int> mat_object({
          {1,2,3},
          {4,5,6},
          {0,0,0}
        });
        
        mat_object.row_scale(7,0,2);  /*
        
        mat_object = [[ 1, 2, 3],
                      [ 4, 5, 6],
                      [ 7,14,21]]
        
        */

    • costum row/column operations

      : NOTE - anything these methods can do, the 3 elementary basic row/column operations can also do, just keep this in mind... the following methods are just more straigth forward

      row scalar operation

        scales all the elements of the row using a scalar value [changes the matrix itself]

        cyfre::mat<int> mat_object({
          {1,2},
          {3,4}
        });
        
        mat_object.scale_row(0,cyfre::SCALAR::MUL,2);  /*
        
        mat_object = [[2,4],
                      [3,4]]
        
        */

        multiply all elements of the row '0' to 3, changes the original matrix

      column scalar operation

        scales all the elements of the column using a scalar value [changes the matrix itself]

        cyfre::mat<int> mat_object({
          {2,4},
          {6,8}
        });
        
        mat_object.scale_column(1,cyfre::SCALAR::DIV,2);  /*
        
        mat_object = [[2,2],
                      [6,4]]
        
        */

        divides all elements of the column '1' to 2, changes the original matrix

      row to row operation

        scale a row using another row [changes the matrix itself]

        cyfre::mat<int> mat_object({
          {1,2,3},
          {4,5,6},
          {7,8,9}
        });
        
        mat_object.row_operation(1,cyfre::SCALAR::MUL,2);  /*
        
        mat_object = [[ 1, 2, 3],
                      [28,40,54],
                      [ 7, 8, 9]]
        
        */

        int mat_object(0,1) we multiply the value of mat_object(0,2) which is 7, into the previous value of mat_object(0,1) which is 4, the answer is 4*7 = 28, hench the 28 in mat_object(0,1)

      column to column operation

        scale a column using another column [changes the matrix itself]

        cyfre::mat<int> mat_object({
          {1,2,3},
          {4,5,6},
          {7,8,9}
        });
        
        mat_object.column_operation(1,cyfre::SCALAR::DIV,2); /*
        
        mat_object = [[1, 0, 3],
                      [4, 0, 6],
                      [7, 0, 9]]
        
        */
SCALAR OPERATIONS
    matrix scalar operation

      returns a copy scaled matrix of the original one

      cyfre::mat<int> mat_object({
        {1,2},
        {3,4}
      });
      
      cyfre::mat<int> a = mat_object+2;  /*
      
      a = [[3,4],
           [5,6]]
      
      NOTE : cyfre::mat<int> a = 2+mat_object;  <-- is also a valid expression
      
      */
    matrix scalar operation [self]

      scales all the elements of the matrix using a scalar value [changes the matrix itself]

      cyfre::mat<int> mat_object({
        {1,2},
        {3,4}
      });
      
      mat_object-=2;  /*
      
      mat_object = [[-1,0],
                    [ 1,2]]
      
      */
MATRIX OPERATIONS
    matrix addition
      cyfre::mat<int> A({{ 1, 2, 3},
                         { 4, 5, 6}});
      
      cyfre::mat<int> B({{-1,-2,-3},
                         {-4,-5,-6}});
      
      cyfre::mat<int> C = A+B; /*
      
      C = [[ 0, 0, 0],
           [ 0, 0, 0]]
      
      */
    matrix subtraction
      cyfre::mat<int> A({{10, 1,33},
                         {44,50,12}});
      
      cyfre::mat<int> B({{ 7,19, 5},
                         { 7, 6, 5}});
      
      cyfre::mat<int> C = A-B; /*
      
      C = [[ 3,-18,28],
           [37, 44, 7]]
      
      */
    matrix element-by-element division
      cyfre::mat<int> A({{2,4,6},
                         {8,2,4}});
      
      cyfre::mat<int> B({{1,4,3},
                         {2,2,1}});
      
      cyfre::mat<int> C = A/B; /*
      
      C = [[2,1,2],
           [4,1,4]]
      
      */
    hadamard product
      cyfre::mat<int> A({{2,4,6},
                         {8,2,4}});
      
      cyfre::mat<int> B({{1,4,3},
                         {2,2,1}});
      
      cyfre::mat<int> C = cyfre::hadamard(A,B); /*
      
      C = [[ 2,16,18],
           [16, 4, 4]]
      
      */
      
      A.hadamard(B); /* faster in some cases because of direct operation on the A matrix
      
      A = [[ 2,16,18],
           [16, 4, 4]]
      
      */
    multiplying matrices (dot product)
      cyfre::mat<int> X({
        { 7,12,13},
        {14, 5,20},
        {66,42,-4}
      });
      
      cyfre::mat<int> W({{-3,4,56}});
      
      cyfre::mat<int> Y = X*W;
      
      // C = [[3731,2336,-183]]
SCALAR METHODS

    methods that returns a single/scalar value

    min & max
      cyfre::mat<int> X({
        { 1, 2, 3},
        { 4, 5,-6},
        {17, 8, 9}
      });
      
      int min = X.min();  // -6
      int max = X.max();  // 17
    sum of all elements
      cyfre::mat<int> X({
        {1,2,3},
        {4,5,6},
        {7,8,9}
      });
      
      int sum = X.total();
      
      // sum = 45
      
    sum of the main-diagonal
      cyfre::mat<int> X({
        {1,2,3},
        {4,5,6},
        {7,8,9}
      });
      
      int diag_sum = X.trace();
      
      // diag_sum = 15
      
    Determinant of a Matrix
      cyfre::mat<long double> X({
        { 5, 10,-15,  20},
        {30,-35,-40, -45},
        {55, 60, 75, -80},
        {90, 95,100,-105}
      });
      
      long double determinant = cyfre::det(X);  /*
      
      determiant = -720000
      
      */
      
TRANSFOM METHODS

    methods that transforms/changes the values, shape orientation of a matrix

    Applying functions to all elements of the matrix

      .apply() is a shortcut method for applying a function to all elements of a matrix

      int square(int x) { return x*x; }
      
      cyfre::mat<int> X({
        {23,12,53,34,23},
        {33,77,53,90,28},
        {87,26,11,24,31},
        {84,32,73,64,26},
        {77,88,45,97,86}
      });
      
      X.apply(square);  /*
      
      X = [[529 144  2809 1156 529],
          [1089 5929 2809 8100 784],
          [7569 676  121  576  961],
          [7056 1024 5329 4096 676],
          [5929 7744 2025 9409 7396]]
      
      */

      NOTE:

      • the function should only have one parameter
      • the function's return type, and parameter type should be the same as the matrix type
    Transpose of a Matrix
      cyfre::mat<int> X({
        {1,2,3,4},
        {5,6,7,8},
      });
      
      X.transpose();
      
      /*
      
      X = [[1,5],
           [2,6],
           [3,7],
           [4,8]]
      
      */
      
    rasing a matrix to a certain power
      cyfre::mat<int> X({
        { 7,12,13},
        {14, 5,20},
        {66,42,-4}
      });
      
      
      cyfre::mat<int> X_cubed = cyfre::power(X,3);  /*
      
      X_cubed = [[35599	28068	26659],
                [38210	31505	39196],
                [130302	85590	20042]]
      
      */
      
      cyfre::mat<int> X_squared = X;
      X_squared.power(2); /*
      
      X_squared = [[1075 690	 279],
                  [1488	1033	 202],
                  [786	 834	1714]]
      
      */
      
    Inverse of a Matrix
      cyfre::mat<long double> X({
        {23,12,53},
        {33,77,53},
        {87,26,11}
      });
      
      X.inv();  /* or  X = cyfre::inv(X);
      
      X = [[0.00196078 -0.00460101 0.0127211],
           [-0.0156863 0.0160925 -0.00195709],
           [0.0215686 -0.00164691 -0.00507736]]
      
      */
      
    Echelon Forms (ref & rref)

      Reduce Row Echelon Form

      cyfre::mat<int> X({
        {1,2,3,4},
        {5,6,7,8},
        {-2,3,-4,1}
      });
      
      X = cyfre::rref(X);
      
      /* or
      
      X.rref();
      
      X = [[1 0 0 -1],
          [0 1 0 1],
          [0 0 1 1]]
      
      */

      Row Eechelon Form : X.ref() or X = cyfre::ref(X)

    Padding

      increase the size of matrix by padding zeros

      cyfre::mat<int> X({
        {1,2,3,4},
        {5,6,7,8},
        {-2,3,-4,1}
      });
      
      X = cyfre::padding(X,1); /*
      
      each one of the 3 methods given below has also
      the same effect with the method given above
      
      X = cyfre::padding(X,1,1);
      X.padding(1);
      X.padding(1,1);
      
      outputs:
      
      X = [[0, 0, 0, 0, 0, 0],
           [0, 1, 2, 3, 4, 0],
           [0, 5, 6, 7, 8, 0],
           [0,-2, 3,-4, 1, 0],
           [0, 0, 0, 0, 0, 0]]
      */
CYFRE::MAT MEMBERS
    .height
    .width
    matrix
    

    you can access the matrix values using the operator ()

    operator(i,j) - performs check of indices, terminates program if indices are out of range

      cyfre::mat<int> nums(
        {{1,2,3},
         {4,5,6},
         {7,8,9}
      });
      
      for(size_t i=0; i<nums.height; ++i)
      {
        for(size_t j=0; j<nums.width; ++j)
        {
          /* use the operator() for matrix indexing */
    
          nums(i,j)*=2;
          std::cout<<nums(i,j)<<'\t';
    
        }
        std::cout<<'\n';
      }
    

    output :

    2       4       6
    8       10      12
    14      16      18
    
STATISTICS
    mean, median, mode
      cyfre::mat<short> X({
        {7,2,4},
        {4,7,6},
        {7,4,9}
      });
      
      long double mean   = cyfre::sts::mean(X);
      long double median = cyfre::sts::median(X);
      
      std::pair<size_t,std::vector<short>> getmode = cyfre::sts::mode(X);
      
      size_t numbers_of_modes  = getmode.second.size();
      size_t modes_occurrence  = getmode.first;
      
      std::vector<short> modes = getmode.second;
      
      /*
        mean = 5.55556
        median = 7
        numbers_of_modes = 2
        modes_occurrence = 3
        modes = [7,4]
      */
      
    sum of squares, variance, standard deviation
      cyfre::mat<short> X({7,2,4,3,9});
      
      long double
      sum_of_square      = cyfre::sts::sofs(X),
      variance           = cyfre::sts::variance(X,cyfre::sts::SAMPLE),
      standard_deviation = cyfre::sts::stddvn(X,cyfre::sts::SAMPLE);;
      
      /*
        sum_of_square = 34
        variance = 8.5
        standard_deviation = 2.91548
      
        for population use 'cyfre::POPULATION' instead
      */