1 /***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht          *
3 * Copyright (c) QuantStack                                                 *
4 *                                                                          *
5 * Distributed under the terms of the BSD 3-Clause License.                 *
6 *                                                                          *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9 
10 #include "test_common_macros.hpp"
11 
12 #include "xtensor/xnpy.hpp"
13 #include "xtensor/xarray.hpp"
14 
15 #include <fstream>
16 #include <cstdint>
17 
18 namespace xt
19 {
get_load_filename(std::string const & npy_prefix,layout_type lt=layout_type::row_major)20     std::string get_load_filename(std::string const& npy_prefix, layout_type lt = layout_type::row_major)
21     {
22         std::string lts = lt == layout_type::row_major ? "" : "_fortran";
23         std::string endianness;
24         switch(xtl::endianness())
25         {
26         case xtl::endian::big_endian:
27             endianness = ".be";
28             break;
29         case xtl::endian::little_endian:
30             endianness = ".le";
31             break;
32         case xtl::endian::mixed:
33             endianness = ".unsupported";
34             break;
35         }
36         return npy_prefix + lts + endianness + ".npy";
37     }
38 
TEST(xnpy,load)39     TEST(xnpy, load)
40     {
41         xarray<double> darr = {{{ 0.29731723,  0.04380157,  0.94748308},
42                                 { 0.85020643,  0.52958618,  0.0598172 },
43                                 { 0.77253259,  0.47564231,  0.70274005}},
44                                {{ 0.85998447,  0.61160158,  0.44432939},
45                                 { 0.25506765,  0.97420976,  0.15455842},
46                                 { 0.05873659,  0.66191764,  0.01448838}},
47                                {{ 0.175919  ,  0.13850365,  0.94059426},
48                                 { 0.79941809,  0.5124432 ,  0.51364796},
49                                 { 0.25721979,  0.41608858,  0.06255319}}};
50 
51         xarray<bool> barr = {{{ 0, 0, 1},
52                               { 1, 1, 0},
53                               { 1, 0, 1}},
54                              {{ 1, 1, 0},
55                               { 0, 1, 0},
56                               { 0, 1, 0}},
57                              {{ 0, 0, 1},
58                               { 1, 1, 1},
59                               { 0, 0, 0}}};
60 
61         xarray<int> iarr1d = {3, 4, 5, 6, 7};
62 
63         auto darr_loaded = load_npy<double>(get_load_filename("files/xnpy_files/double"));
64         EXPECT_TRUE(all(isclose(darr, darr_loaded)));
65 
66         std::ifstream dstream(get_load_filename("files/xnpy_files/double"));
67         auto darr_loaded_stream = load_npy<double>(dstream);
68         CHECK_MESSAGE(all(isclose(darr, darr_loaded_stream)),"Loading double numpy array from stream failed");
69         dstream.close();
70 
71         auto barr_loaded = load_npy<bool>(get_load_filename("files/xnpy_files/bool"));
72         EXPECT_TRUE(all(equal(barr, barr_loaded)));
73 
74         std::ifstream bstream(get_load_filename("files/xnpy_files/bool"));
75         auto barr_loaded_stream = load_npy<bool>(bstream);
76         CHECK_MESSAGE(all(equal(barr, barr_loaded_stream)),"Loading boolean numpy array from stream failed");
77         bstream.close();
78 
79         auto dfarr_loaded = load_npy<double, layout_type::column_major>(get_load_filename("files/xnpy_files/double_fortran"));
80         EXPECT_TRUE(all(isclose(darr, dfarr_loaded)));
81 
82         auto iarr1d_loaded = load_npy<int>(get_load_filename("files/xnpy_files/int"));
83         EXPECT_TRUE(all(equal(iarr1d, iarr1d_loaded)));
84     }
85 
compare_binary_files(std::string fn1,std::string fn2)86     bool compare_binary_files(std::string fn1, std::string fn2)
87     {
88         std::ifstream stream1(fn1, std::ios::in | std::ios::binary);
89         std::vector<uint8_t> fn1_contents((std::istreambuf_iterator<char>(stream1)),
90                                           std::istreambuf_iterator<char>());
91 
92         std::ifstream stream2(fn2, std::ios::in | std::ios::binary);
93         std::vector<uint8_t> fn2_contents((std::istreambuf_iterator<char>(stream2)),
94                                           std::istreambuf_iterator<char>());
95         return std::equal(fn1_contents.begin(), fn1_contents.end(), fn2_contents.begin()) &&
96             fn1_contents.size() == fn2_contents.size();
97     }
98 
99 
get_dump_filename(int n)100     std::string get_dump_filename(int n)
101     {
102         std::string filename = "files/xnpy_files/test_dump_" + std::to_string(n) + ".npy";
103         return filename;
104     }
105 
read_file(const std::string & name)106     std::string read_file(const std::string& name)
107     {
108         return static_cast<std::stringstream const&>(std::stringstream() << std::ifstream(name).rdbuf()).str();
109     }
110 
TEST(xnpy,dump)111     TEST(xnpy, dump)
112     {
113         std::string filename = get_dump_filename(0);
114         xarray<bool> barr = {{{0, 0, 1},
115                               {1, 1, 0},
116                               {1, 0, 1}},
117                              {{1, 1, 0},
118                               {0, 1, 0},
119                               {0, 1, 0}},
120                              {{0, 0, 1},
121                               {1, 1, 1},
122                               {0, 0, 0}}};
123 
124         xtensor<uint64_t, 1> ularr = {12ul, 14ul, 16ul, 18ul, 1234321ul};
125         dump_npy(filename, barr);
126 
127         std::string compare_name = get_load_filename("files/xnpy_files/bool", barr.layout());
128 
129         EXPECT_TRUE(compare_binary_files(filename, compare_name));
130 
131         std::string barr_str = dump_npy(barr);
132         std::string barr_disk = read_file(compare_name);
133         CHECK_MESSAGE(barr_str==barr_disk,"Dumping boolean numpy file to string failed");
134 
135         std::remove(filename.c_str());
136 
137         filename = get_dump_filename(1);
138         dump_npy(filename, ularr);
139         auto ularrcpy = load_npy<uint64_t>(filename);
140         EXPECT_TRUE(all(equal(ularr, ularrcpy)));
141 
142         compare_name = get_load_filename("files/xnpy_files/unsignedlong", barr.layout());
143 
144         EXPECT_TRUE(compare_binary_files(filename, compare_name));
145 
146         std::string ularr_str = dump_npy(ularr);
147         std::string ularr_disk = read_file(compare_name);
148         CHECK_MESSAGE(ularr_str==ularr_disk,"Dumping boolean numpy file to string failed");
149 
150         std::remove(filename.c_str());
151     }
152 
TEST(xnpy,xfunction_cast)153     TEST(xnpy, xfunction_cast)
154     {
155         // compilation test, cf: https://github.com/xtensor-stack/xtensor/issues/1070
156         auto dc = cast<char>(load_npy<double>(get_load_filename("files/xnpy_files/double")));
157         EXPECT_EQ(dc(0, 0), 0);
158         xarray<char> adc = dc;
159         EXPECT_EQ(adc(0, 0), 0);
160     }
161 }
162