1 #ifndef _LDAPLUSPLUS_NUMPY_FORMAT_HPP_ 2 #define _LDAPLUSPLUS_NUMPY_FORMAT_HPP_ 14 namespace numpy_format {
15 template <
typename Scalar>
16 inline const char * dtype_for_scalar() {
24 inline const char * dtype_for_scalar<int8_t>() {
return "i1"; }
26 inline const char * dtype_for_scalar<int16_t>() {
return "i2"; }
28 inline const char * dtype_for_scalar<int32_t>() {
return "i4"; }
30 inline const char * dtype_for_scalar<int64_t>() {
return "i8"; }
32 inline const char * dtype_for_scalar<uint8_t>() {
return "u1"; }
34 inline const char * dtype_for_scalar<uint16_t>() {
return "u2"; }
36 inline const char * dtype_for_scalar<uint32_t>() {
return "u4"; }
38 inline const char * dtype_for_scalar<uint64_t>() {
return "u8"; }
40 inline const char * dtype_for_scalar<float>() {
return "f4"; }
42 inline const char * dtype_for_scalar<double>() {
return "f8"; }
45 inline bool is_big_endian() {
51 ByteOrder b = {0x01234567};
53 return b.c[0] == 0x01;
57 template <
typename Scalar>
58 void swap_endianess(Scalar * data,
size_t N) {
62 uint8_t c[
sizeof(Scalar)];
66 for (
size_t i=0; i<N; i++) {
69 for (
size_t j=0; j<
sizeof(Scalar)/2; j++) {
70 std::swap(d.c[j], d.c[
sizeof(Scalar)-j-1]);
85 template <
typename Scalar>
98 std::vector<size_t> shape,
110 template <
int Rows,
int Cols,
int Options>
111 NumpyOutput(
const Eigen::Matrix<Scalar, Rows, Cols, Options> &matrix)
115 static_cast<size_t>(matrix.rows()),
116 static_cast<size_t>(matrix.cols())
118 ! Eigen::Matrix<Scalar, Rows, Cols, Options>::IsRowMajor
126 return std::string(is_big_endian() ?
">" :
"<") +
127 dtype_for_scalar<Scalar>();
133 const char *
data()
const {
return reinterpret_cast<const char *
>(data_); }
139 const std::vector<size_t> &
shape()
const {
return shape_; }
153 const uint8_t MAGIC_AND_VERSION[] = {
154 0x93, 0x4e, 0x55, 0x4d, 0x50, 0x59, 0x01, 0x00
159 std::ostringstream header;
160 header <<
"{'descr': '" << data.
dtype() <<
"'," 163 for (
auto d : data.
shape()) {
170 while ((static_cast<size_t>(header.tellp()) + 11) % 16) {
176 os.write(reinterpret_cast<const char *>(MAGIC_AND_VERSION), 8);
179 uint16_t header_len = header.tellp();
180 if (!is_big_endian()) {
181 os.write(reinterpret_cast<const char *>(&header_len), 2);
183 os.write(reinterpret_cast<const char *>(&header_len) + 1, 1);
184 os.write(reinterpret_cast<const char *>(&header_len), 1);
192 for (
auto d : data.
shape()) {
195 os.write(data.
data(), N*
sizeof(Scalar));
200 const Scalar * data_;
201 std::vector<size_t> shape_;
216 template <
typename Scalar>
222 const bool fortran_contiguous()
const {
return fortran_; }
223 const Scalar * data()
const {
return data_.data(); }
224 const std::vector<size_t> & shape()
const {
return shape_; }
234 template <
int Rows,
int Cols,
int Options>
235 operator Eigen::Matrix<Scalar, Rows, Cols, Options>()
const {
237 int rows = shape_[0];
239 for (
size_t i=1; i<shape_.size(); i++) {
243 Eigen::Matrix<Scalar, Rows, Cols, Options> matrix(
249 for (
int i=0; i<cols; i++) {
250 for (
int j=0; j<rows; j++) {
251 int idx = (fortran_) ? i*rows + j : j*cols + i;
253 matrix(j, i) = data_[idx];
278 char MAGIC_AND_VERSION[8];
279 is.read(MAGIC_AND_VERSION, 8);
280 if (MAGIC_AND_VERSION[6] > 1) {
281 throw std::runtime_error(
282 "Only version 1 of the numpy format is supported" 288 if (is.gcount() == 0) {
289 throw std::runtime_error(
290 "The file is empty and cannot be read" 296 is.read(reinterpret_cast<char *>(&header_len), 2);
297 if (is_big_endian()) {
298 swap_endianess(&header_len, 1);
302 std::vector<char> buffer(header_len+1);
303 is.read(&buffer[0], header_len);
304 buffer[header_len] = 0;
305 std::string header(&buffer[0]);
312 std::string dtype = header.substr(11, 3);
313 bool endianness = dtype[0] ==
'>';
314 if (dtype.substr(1) != dtype_for_scalar<Scalar>()) {
315 throw std::runtime_error(
317 "The type of the array is not the " +
318 "one requested: " + dtype.substr(1) +
319 " != " + dtype_for_scalar<Scalar>()
324 data.fortran_ = header[34] ==
'T';
327 std::string shape = header.substr(
328 header.find_last_of(
'(')+1,
329 header.find_last_of(
')')
334 data.shape_.push_back(std::stoi(shape, &processed));
337 shape = shape.substr(processed + 2);
339 }
catch (
const std::invalid_argument&) {
345 for (
auto c : data.shape_) {
350 data.data_.resize(N);
351 is.read(reinterpret_cast<char *>(&data.data_[0]), N*
sizeof(Scalar));
354 if (endianness != is_big_endian()) {
355 swap_endianess(&data.data_[0], N);
361 std::vector<Scalar> data_;
362 std::vector<size_t> shape_;
370 template <
typename Scalar,
int Rows,
int Cols,
int Options>
371 void save(std::ostream &out_stream,
const Eigen::Matrix<Scalar, Rows, Cols, Options> &matrix) {
372 out_stream << NumpyOutput<Scalar>(matrix);
379 template <
typename Scalar,
int Rows,
int Cols,
int Options>
380 void save(std::string save_path,
const Eigen::Matrix<Scalar, Rows, Cols, Options> &matrix) {
381 std::fstream out_stream(
383 std::ios::out | std::ios::binary
386 save(out_stream, matrix);
395 int Rows=Eigen::Dynamic,
396 int Cols=Eigen::Dynamic,
397 int Options=Eigen::ColMajor | Eigen::AutoAlign
399 Eigen::Matrix<Scalar, Rows, Cols, Options> load(std::istream &in_stream) {
412 int Rows=Eigen::Dynamic,
413 int Cols=Eigen::Dynamic,
414 int Options=Eigen::ColMajor | Eigen::AutoAlign
416 Eigen::Matrix<Scalar, Rows, Cols, Options> load(std::string data_path) {
417 std::fstream in_stream(
419 std::ios::in | std::ios::binary
422 return load<Scalar>(in_stream);
428 #endif // _LDAPLUSPLUS_NUMPY_FORMAT_HPP_
Definition: Document.hpp:11