├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── numpycpp.h ├── numpycppTest.cpp ├── numpycppTest.py └── test_run.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | *.smod 19 | 20 | # Compiled Static libraries 21 | *.lai 22 | *.la 23 | *.a 24 | *.lib 25 | 26 | # Executables 27 | *.exe 28 | *.out 29 | *.app 30 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | compiler: 3 | - g++ 4 | before_install: 5 | - sudo apt-get update 6 | - sudo apt-get install libgtest-dev 7 | - "cd /usr/src/gtest && sudo cmake . && sudo cmake --build . && sudo mv libg* /usr/local/lib/ ; cd -" 8 | - hg clone https://bitbucket.org/eigen/eigen#3.2 9 | before_script: 10 | - pwd 11 | script: "sh ./test_run.sh" 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Atsushi Sakai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # numpycpp 2 | [![Build Status](https://travis-ci.org/AtsushiSakai/numpycpp.svg?branch=master)](https://travis-ci.org/AtsushiSakai/numpycpp) 3 | 4 | A c++ header library for matrix operation inspired Numpy, Scipy and MATLAB only using Eigen. 5 | 6 | This library has some APIs which Numpy, Scipy, MATLAB has, but Eigen doesn't. 7 | 8 | You can use it with only Eigen, and only include it. 9 | 10 | # Requrements 11 | 12 | - [Eigen](http://eigen.tuxfamily.org/index.php?title=Main_Page) 13 | 14 | # How to use 15 | 16 | Just add a compile option to add the Eigen path, and include numpycpp.h in your code. 17 | 18 | # APIs 19 | 20 | The test code: numpycppTest.cpp helps to understand APIs. 21 | 22 | ## reshape 23 | 24 | Gives a new shape to an array without changing its data. 25 | 26 | This function is based on numpy.reshape 27 | 28 | see: https://docs.scipy.org/doc/numpy/reference/generated/numpy.reshape.html 29 | 30 | Eigen::MatrixXf x(6,1); 31 | x<<1.0,2.0,3.0,4.0,5.0,6.0; 32 | PRINT(x); 33 | 34 | Eigen::MatrixXf rx = reshape(x,2,3); 35 | PRINT(rx); 36 | //rx: 37 | //1 3 5 38 | //2 4 6 39 | 40 | Eigen::MatrixXf rx2 = reshape(x,3,2); 41 | PRINT(rx2); 42 | //rx2: 43 | //1 4 44 | //2 5 45 | //3 6 46 | 47 | 48 | ## isdiag 49 | 50 | Detemine if matrix is diagonal 51 | 52 | If matrix is not square, return false 53 | 54 | It is inspired by MATLAB isdiag function. 55 | 56 | see: https://www.mathworks.com/help/matlab/ref/isdiag.html 57 | 58 | 59 | 60 | Eigen::MatrixXf x(3,1); 61 | x<<5.0,6.0,7.0; 62 | bool flag = isdiag(x);//return false 63 | 64 | Eigen::MatrixXf x2(2,2); 65 | x2<<5.0,6.0,7.0,1.0; 66 | bool flag2 = isdiag(x2);//return false 67 | 68 | Eigen::MatrixXf x3(3,3); 69 | x3<<1.0,0.0,0.0, 70 | 0.0,1.0,0.0, 71 | 0.0,0.0,1.0; 72 | bool flag3 = isdiag(x3);//return true 73 | 74 | 75 | 76 | ## vstack 77 | 78 | Stack matrix in sequence vertically 79 | 80 | imspired by numpy.vstack 81 | 82 | see :https://docs.scipy.org/doc/numpy/reference/generated/numpy.vstack.html 83 | 84 | Eigen::MatrixXf x(3,1); 85 | x<<5.0, 86 | 6.0, 87 | 7.0; 88 | 89 | Eigen::MatrixXf y(3,1); 90 | y<<1.0, 91 | 10.0, 92 | 100.0; 93 | 94 | Eigen::MatrixXf a = vstack(x,y); 95 | //ans<<5, 96 | // 6, 97 | // 7, 98 | // 1, 99 | // 10, 100 | // 100; 101 | 102 | ## hstack 103 | 104 | Stack matrix in sequence horizontally 105 | 106 | imspired by numpy.hstack 107 | 108 | see: https://docs.scipy.org/doc/numpy/reference/generated/numpy.hstack.html 109 | 110 | 111 | Eigen::MatrixXf x(3,1); 112 | x<<5.0, 113 | 6.0, 114 | 7.0; 115 | 116 | Eigen::MatrixXf y(3,1); 117 | y<<1.0, 118 | 10.0, 119 | 100.0; 120 | 121 | Eigen::MatrixXf a = hstack(x,y); 122 | //a= 123 | //5 1 124 | //6 10 125 | //7 100 126 | 127 | ## kron 128 | 129 | Compute the Kronecker product 130 | 131 | A composite array made of blocks of the second array scaled by the first. 132 | 133 | Inspired numpy.kron. 134 | 135 | see: https://docs.scipy.org/doc/numpy/reference/generated/numpy.kron.html 136 | 137 | 138 | Eigen::MatrixXf x(1,3); 139 | x<<1.0,10.0,100.0; 140 | 141 | Eigen::MatrixXf y(1,3); 142 | y<<5.0,6.0,7.0; 143 | 144 | Eigen::MatrixXf a = kron(x,y); 145 | // a = [5 50 500 6 60 600 7 70 700] 146 | 147 | 148 | ## block_diag 149 | 150 | Create a block diagonal matrix from provided matrices 151 | 152 | inspired scipy.linalg.block_diag 153 | 154 | see: https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.linalg.block_diag.html 155 | 156 | 157 | Eigen::MatrixXf x(3,1); 158 | x<<5.0, 159 | 6.0, 160 | 7.0; 161 | 162 | Eigen::MatrixXf y(1,3); 163 | y<<1.0,10.0,100.0; 164 | 165 | Eigen::MatrixXf a = block_diag(x,y); 166 | //a= 5, 0, 0, 0, 167 | // 6, 0, 0, 0, 168 | // 7, 0, 0, 0, 169 | // 0, 1, 10,100; 170 | 171 | 172 | # License 173 | 174 | MIT 175 | 176 | # Author 177 | 178 | Atsushi Sakai ([@Atsushi_twi](https://twitter.com/Atsushi_twi)) 179 | 180 | -------------------------------------------------------------------------------- /numpycpp.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief C++ header library for matrix operation inspired numpy and scipy 3 | * 4 | * @author Atsushi Sakai 5 | * 6 | * @license MIT 7 | * 8 | **/ 9 | #include "Eigen/Core" 10 | 11 | #define PRINT(X) std::cout << #X << ":\n" << X << std::endl << std::endl 12 | 13 | /** 14 | * @brief Gives a new shape to an array without changing its data. 15 | * This function is based on numpy.reshape 16 | * see: https://docs.scipy.org/doc/numpy/reference/generated/numpy.reshape.html 17 | * 18 | * @param x input matrix 19 | * @param r the number of row elements 20 | * @param c the number of collum elements 21 | * 22 | * @return The new shape matrix 23 | */ 24 | Eigen::MatrixXf reshape( 25 | Eigen::MatrixXf &x, 26 | uint32_t r, 27 | uint32_t c 28 | ){ 29 | 30 | Eigen::Map rx(x.data(), r, c); 31 | 32 | return rx; 33 | } 34 | 35 | 36 | 37 | /** 38 | * @brief Detemine if matrix is diagonal 39 | * if matrix is not square, return false 40 | * 41 | * It is inspired by MATLAB isdiag function. 42 | * see: https://www.mathworks.com/help/matlab/ref/isdiag.html 43 | * 44 | * @param x input matrix 45 | * 46 | * @return matrix is diagonal (true) or not (false) 47 | */ 48 | bool isdiag(const Eigen::MatrixXf &x){ 49 | 50 | if(x.cols()!=x.rows()){ 51 | return false;//not square matrix 52 | } 53 | 54 | Eigen::MatrixXf t = x.diagonal().asDiagonal(); 55 | // PRINT(t); 56 | 57 | // std::cout<=0.00001){ 59 | return false; 60 | } 61 | 62 | return true; 63 | 64 | } 65 | 66 | 67 | /** 68 | * @brief Stack matrix in sequence vertically 69 | * imspired by numpy.vstack 70 | * https://docs.scipy.org/doc/numpy/reference/generated/numpy.vstack.html 71 | * 72 | * @param m1 first matrix 73 | * @param m2 second matrix 74 | * 75 | * @return stacked matrix 76 | */ 77 | Eigen::MatrixXf vstack( 78 | const Eigen::MatrixXf &m1, 79 | const Eigen::MatrixXf &m2 80 | ){ 81 | 82 | if(m1.rows() == 0){ 83 | return m2; 84 | } 85 | else if(m2.rows() == 0){ 86 | return m1; 87 | } 88 | 89 | uint32_t ncol = m1.cols(); 90 | if(ncol == 0){ 91 | ncol = m2.cols(); 92 | } 93 | 94 | Eigen::MatrixXf rm(m1.rows()+m2.rows(), ncol); 95 | rm << m1, m2; 96 | 97 | return rm; 98 | } 99 | 100 | 101 | /** 102 | * @brief Stack matrix in sequence horizontally 103 | * imspired by numpy.hstack 104 | * https://docs.scipy.org/doc/numpy/reference/generated/numpy.hstack.html 105 | * 106 | * @param m1 first matrix 107 | * @param m2 second matrix 108 | * 109 | * @return stacked matrix 110 | */ 111 | Eigen::MatrixXf hstack( 112 | const Eigen::MatrixXf &m1, 113 | const Eigen::MatrixXf &m2 114 | ){ 115 | 116 | if(m1.cols() == 0){ 117 | return m2; 118 | } 119 | else if(m2.cols() == 0){ 120 | return m1; 121 | } 122 | 123 | uint32_t nrow = m1.rows(); 124 | if(nrow == 0){ 125 | nrow = m2.rows(); 126 | } 127 | 128 | Eigen::MatrixXf rm(nrow, m1.cols()+m2.cols()); 129 | rm << m1, m2; 130 | 131 | return rm; 132 | } 133 | 134 | 135 | 136 | /** 137 | * @brief Create a block diagonal matrix from provided matrices 138 | * 3 input version 139 | * inspired scipy.linalg.block_diag 140 | * https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.linalg.block_diag.html 141 | * 142 | * @param m1 first matrix 143 | * @param m2 second matrix 144 | * 145 | * @return Created a block diagonal matrix 146 | */ 147 | Eigen::MatrixXf block_diag( 148 | const Eigen::MatrixXf &m1, 149 | const Eigen::MatrixXf &m2 150 | ){ 151 | 152 | uint32_t m1r=m1.rows(); 153 | uint32_t m1c=m1.cols(); 154 | uint32_t m2r=m2.rows(); 155 | uint32_t m2c=m2.cols(); 156 | 157 | Eigen::MatrixXf mf = Eigen::MatrixXf::Zero(m1r + m2r , m1c + m2c); 158 | mf.block(0, 0, m1r, m1c) = m1; 159 | mf.block(m1r, m1c, m2r, m2c) = m2; 160 | 161 | return mf; 162 | } 163 | 164 | /** 165 | * @brief Create a block diagonal matrix from provided matrices 166 | * 3 input version 167 | * 168 | * @param m1 first matrix 169 | * @param m2 second matrix 170 | * @param m3 third matrix 171 | * 172 | * @return Created a block diagonal matrix 173 | */ 174 | Eigen::MatrixXf block_diag( 175 | const Eigen::MatrixXf &m1, 176 | const Eigen::MatrixXf &m2, 177 | const Eigen::MatrixXf &m3 178 | ){ 179 | 180 | uint32_t m1r=m1.rows(); 181 | uint32_t m1c=m1.cols(); 182 | uint32_t m2r=m2.rows(); 183 | uint32_t m2c=m2.cols(); 184 | uint32_t m3r=m3.rows(); 185 | uint32_t m3c=m3.cols(); 186 | 187 | Eigen::MatrixXf bdm = Eigen::MatrixXf::Zero(m1r + m2r + m3r , m1c + m2c + m3c); 188 | bdm.block(0, 0, m1r, m1c) = m1; 189 | bdm.block(m1r, m1c, m2r, m2c) = m2; 190 | bdm.block(m1r+m2r, m1c+m2c, m3r, m3c) = m3; 191 | 192 | return bdm; 193 | } 194 | 195 | 196 | 197 | /** 198 | * @brief Compute the Kronecker product 199 | * A composite array made of blocks of the second array scaled by the first 200 | * Inspired numpy.kron 201 | * see: https://docs.scipy.org/doc/numpy/reference/generated/numpy.kron.html 202 | * 203 | * @param m1 first matrix 204 | * @param m2 second matrix 205 | * 206 | * @return A result of the Kronecker product 207 | */ 208 | Eigen::MatrixXf kron( 209 | const Eigen::MatrixXf &m1, 210 | const Eigen::MatrixXf &m2 211 | ){ 212 | 213 | uint32_t m1r=m1.rows(); 214 | uint32_t m1c=m1.cols(); 215 | uint32_t m2r=m2.rows(); 216 | uint32_t m2c=m2.cols(); 217 | 218 | 219 | Eigen::MatrixXf m3(m1r*m2r, m1c*m2c); 220 | // PRINT(m3); 221 | 222 | 223 | for (int i = 0; i < m1r; i++) { 224 | for (int j = 0; j < m1c; j++) { 225 | m3.block(i*m2r, j*m2c, m2r, m2c) = m1(i,j)*m2; 226 | } 227 | } 228 | 229 | return m3; 230 | } 231 | -------------------------------------------------------------------------------- /numpycppTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "gtest/gtest.h" 4 | #include "numpycpp.h" 5 | 6 | 7 | TEST(numpycpp, test1) { 8 | Eigen::MatrixXf x(1,3); 9 | x<<1.0,10.0,100.0; 10 | PRINT(x); 11 | 12 | Eigen::MatrixXf y(1,3); 13 | y<<5.0,6.0,7.0; 14 | PRINT(y); 15 | 16 | Eigen::MatrixXf z = kron(x,y); 17 | PRINT(z); 18 | 19 | 20 | Eigen::VectorXf ans(9); 21 | ans<< 5, 6, 7, 50, 60, 70, 500, 600, 700; 22 | PRINT(ans); 23 | 24 | for(uint32_t i=0;i