NumCpp:Python NumPy库的一个Templatized Header Only C ++实现
NumCpp 是一个高性能的数学计算 C++ 库,它提供了一个简单的 Numpy/Matlab 类似的接口。
NumCpp中的主要数据结构是NdArray。它本质上是一个 2D 数组类,一维数组实现为1xN数组。还有一个DataCube类作为便利容器提供,用于存储2D数组NdArray,但它通过简单容器的用途有限。
地址 https://github.com/dpilger26/NumCpp
文档地址 https://dpilger26.github.io/NumCpp/doxygen/html/index.html
$ git clone https://github.com/dpilger26/NumCpp
源码中的src文件夹下的文件能够直接被项目使用:
# 拷贝到项目中
$ cp NumCpp/src/ /home/toson/project/pro1/
// 引用头文件即可使用
#include"src/NumCpp.hpp"
#include"NumCpp.hpp"
#include"boost/filesystem.hpp"
#include<iostream>
int main()
{
// Containers
nc::NdArray<int> a0 = { {1, 2}, {3, 4} };
nc::NdArray<int> a1 = { {1, 2}, {3, 4}, {5, 6} };
a1.reshape(2, 3);
auto a2 = a1.astype<double>();
// Initializers
auto a3 = nc::linspace<int>(1, 10, 5);
auto a4 = nc::arange<int>(3, 7);
auto a5 = nc::eye<int>(4);
auto a6 = nc::zeros<int>(3, 4);
auto a7 = nc::NdArray<int>(3, 4) = 0;
auto a8 = nc::ones<int>(3, 4);
auto a9 = nc::NdArray<int>(3, 4) = 1;
auto a10 = nc::nans(3, 4);
auto a11 = nc::NdArray<double>(3, 4) = nc::constants::nan;
auto a12 = nc::empty<int>(3, 4);
auto a13 = nc::NdArray<int>(3, 4);
// Slicing/Broadcasting
auto a14 = nc::Random<int>::randInt({ 10, 10 }, 0, 100);
auto value = a14(2, 3);
auto slice = a14({ 2, 5 }, { 2, 5 });
auto rowSlice = a14(a14.rSlice(), 7);
auto values = a14[a14 > 50];
a14.putMask(a14 > 50, 666);
// Random
nc::Random<>::seed(666);
auto a15 = nc::Random<double>::randN({3, 4});
auto a16 = nc::Random<int>::randInt({3, 4}, 0, 10);
auto a17 = nc::Random<double>::rand({3, 4});
auto a18 = nc::Random<double>::choice(a17, 3);
// Concatenation
auto a = nc::Random<int>::randInt({3, 4}, 0, 10);
auto b = nc::Random<int>::randInt({3, 4}, 0, 10);
auto c = nc::Random<int>::randInt({3, 4}, 0, 10);
auto a19 = nc::stack({ a, b, c }, nc::Axis::ROW);
auto a20 = nc::vstack({ a, b, c });
auto a21 = nc::hstack({ a, b, c });
auto a22 = nc::append(a, b, nc::Axis::COL);
// Diagonal, Traingular, and Flip
auto d = nc::Random<int>::randInt({5, 5}, 0, 10);
auto a23 = nc::diagonal(d);
auto a24 = nc::triu(a);
auto a25 = nc::tril(a);
auto a26 = nc::flip(d, nc::Axis::ROW);
auto a27 = nc::flipud(d);
auto a28 = nc::fliplr(d);
// iteration
for (auto it = a.begin(); it < a.end(); ++it)
{
std::cout << *it << " ";
}
std::cout << std::endl;
for (auto& arrayValue : a)
{
std::cout << arrayValue << " ";
}
std::cout << std::endl;
// Logical
auto a29 = nc::where(a > 5, a, b);
auto a30 = nc::any(a);
auto a31 = nc::all(a);
auto a32 = nc::logical_and(a, b);
auto a33 = nc::logical_or(a, b);
auto a34 = nc::isclose(a, b);
auto a35 = nc::allclose(a, b);
// Comparisons
auto a36 = nc::equal(a, b);
auto a37 = a == b;
auto a38 = nc::not_equal(a, b);
auto a39 = a != b;
auto a40 = nc::nonzero(a);
// Minimum, Maximum, Sorting
auto value1 = nc::min(a);
auto value2 = nc::max(a);
auto value3 = nc::argmin(a);
auto value4 = nc::argmax(a);
auto a41 = nc::sort(a, nc::Axis::ROW);
auto a42 = nc::argsort(a, nc::Axis::COL);
auto a43 = nc::unique(a);
auto a44 = nc::setdiff1d(a, b);
auto a45 = nc::diff(a);
// Reducers
auto value5 = nc::sum<int>(a);
auto a46 = nc::sum<int>(a, nc::Axis::ROW);
auto value6 = nc::prod<int>(a);
auto a47 = nc::prod<int>(a, nc::Axis::ROW);
auto value7 = nc::mean(a);
auto a48 = nc::mean(a, nc::Axis::ROW);
auto value8 = nc::count_nonzero(a);
auto a49 = nc::count_nonzero(a, nc::Axis::ROW);
// I/O
a.print();
std::cout << a << std::endl;
auto tempDir = boost::filesystem::temp_directory_path();
auto tempTxt = (tempDir / "temp.txt").string();
a.tofile(tempTxt, "\n");
auto a50 = nc::fromfile<int>(tempTxt, "\n");
auto tempBin = (tempDir / "temp.bin").string();
nc::dump(a, tempBin);
auto a51 = nc::load<int>(tempBin);
// Mathematical Functions
// Basic Functions
auto a52 = nc::abs(a);
auto a53 = nc::sign(a);
auto a54 = nc::remainder(a, b);
auto a55 = nc::clip(a, 3, 8);
auto xp = nc::linspace<double>(0.0, 2.0 * nc::constants::pi, 100);
auto fp = nc::sin(xp);
auto x = nc::linspace<double>(0.0, 2.0 * nc::constants::pi, 1000);
auto f = nc::interp(x, xp, fp);
// Exponential Functions
auto a56 = nc::exp(a);
auto a57 = nc::expm1(a);
auto a58 = nc::log(a);
auto a59 = nc::log1p(a);
// Power Functions
auto a60 = nc::power<int>(a, 4);
auto a61 = nc::sqrt(a);
auto a62 = nc::square(a);
auto a63 = nc::cbrt(a);
// Trigonometric Functions
auto a64 = nc::sin(a);
auto a65 = nc::cos(a);
auto a66 = nc::tan(a);
// Hyperbolic Functions
auto a67 = nc::sinh(a);
auto a68 = nc::cosh(a);
auto a69 = nc::tanh(a);
// Classification Functions
auto a70 = nc::isnan(a.astype<double>());
//nc::isinf(a);
// Linear Algebra
auto a71 = nc::norm<int>(a);
auto a72 = nc::dot<int>(a, b.transpose());
auto a73 = nc::Random<int>::randInt({3, 3}, 0, 10);
auto a74 = nc::Random<int>::randInt({4, 3}, 0, 10);
auto a75 = nc::Random<int>::randInt({1, 4}, 0, 10);
auto value9 = nc::linalg::det(a73);
auto a76 = nc::linalg::inv(a73);
auto a77 = nc::linalg::lstsq(a74, a75);
auto a78 = nc::linalg::matrix_power<int>(a73, 3);
auto a79 = nc::linalg::multi_dot<int>({ a, b.transpose(), c });
nc::NdArray<double> u;
nc::NdArray<double> s;
nc::NdArray<double> vt;
nc::linalg::svd(a.astype<double>(), u, s, vt);
return 0;
}
fatal error: NumCpp/Types.hpp: No such file or directory
#include"NumCpp/Types.hpp"
请检查CMakeLists.txt中:include_directories()中包含路径。
/usr/local/include/boost/math/special_functions/lanczos.hpp:104:25: note: use -std=gnu++11 or -fext-numeric-literals to enable more built-in suffixes
/usr/local/include/boost/math/special_functions/lanczos.hpp:105:25: error: unable to find numeric literal operator ‘operator""Q’
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 32.12388941444332003446077108933558534361)),
参照依赖项:
$ gcc -v
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11)
$ dpkg -S /usr/include/boost/version.hpp
libboost1.68-dev:amd64: /usr/include/boost/version.hpp
附:boost编译
下载boost1.68:https://dl.bintray.com/boostorg/release/1.68.0/source/
$ tar -zxvf boost_1_68_0.tar.gz
$ cd boost_1_68_0/
# 编译
$ ./bootstrap.sh --with-libraries=all --with-toolset=gcc
# 安装
$ ./b2 install --prefix=/usr
note: use -std=gnu++11 or -fext-numeric-literals to enable more built-in suffixes
error: unable to find numeric literal operator ‘operator""Q’
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 32.12388941444332003446077108933558534361)),
需要在项目中的CMake编译选项中增加:
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals")
In function `boost::system::generic_category()':
undefined reference to `boost::system::detail::generic_category_ncx()'
在CMake编译时需要依赖库:boost_system
基于:Ubuntu 16.04LTS,Core-i7 8700,Clion
1.nc::dot<double>
运算太耗时
auto mel = nc::dot<double>(mel_basis, mag); //20ms
//注:mel_basis为shape(80,1025),mag为shape(1025,109)
//我后来优化为使用opencv来实现的
cv::Mat cv_mel = cv_mel_basis * cv_mag; //2ms
2.nc::log10(nc::maximum(...))
运算还将就,不过opencv更快
// to decibel //2ms
mel = nc::log10(nc::maximum(mel, nc::NdArray<double>(mel.shape().rows, mel.shape().cols) = 1e-5)) * 20;
mag = nc::log10(nc::maximum(mag, nc::NdArray<double>(mag.shape().rows, mag.shape().cols) = 1e-5)) * 20;
//尝试使用opencv来实现 //0ms(<0.5ms)
cv::log(cv::max(cv_mel, 1e-5), cv_mel);
3.nc::pad()
的实现与numpy不一样:
numpy可以实现一维填充(一维数列),而numcpp会将每个维度都进行填充。
比如我想实现一维数列的填充,结果出来后成为了二维数列了。
并且无法完成reflect填充。
//注:ncbuffer的shape(1,43350)
auto ncbuffer_pad = nc::pad(ncbuffer, nc::uint16(pad_lenght), 0.0);
//nc::pad()会将二维也进行填充,成为2049*45398
我当初是自己写循环实现的,后来使用opencv里的copyMakeBorder来完成reflect填充:
cv::copyMakeBorder(cv_padbuffer, cv_padbuffer, 0, 0, pad_lenght, pad_lenght, cv::BORDER_REFLECT_101);//cv::BORDER_REFLECT
这里发现opencv里copyMakeBorder的BORDER_REFLECT
填充是这样的:
例:fedcba|abcdefgh|hgfedcb
我要实现numpy里的reflect填充,它的效果是这样的:
例:gfedcb|abcdefgh|gfedcba
所以应该使用BORDER_REFLECT_101
。
4.其他。。。