Distributed Ranges
Loading...
Searching...
No Matches
matrix_io.hpp
1// SPDX-FileCopyrightText: Intel Corporation
2//
3// SPDX-License-Identifier: BSD-3-Clause
4
5#pragma once
6
7#include <algorithm>
8#include <cassert>
9#include <fstream>
10#include <sstream>
11#include <string>
12#include <tuple>
13#include <vector>
14
15#include <dr/detail/csr_matrix_base.hpp>
16#include <dr/views/csr_matrix_view.hpp>
17
18namespace dr {
19
20namespace __detail {
21
22// Preconditions:
23// 1) `tuples` sorted by row, column
24// 2) `tuples` has shape `shape`
25// 3) `tuples` has `nnz` elements
26template <typename Tuples, typename Allocator>
27auto convert_to_csr(Tuples &&tuples, dr::index<> shape, std::size_t nnz,
28 Allocator &&allocator) {
29 auto &&[index, v] = *tuples.begin();
30 auto &&[i, j] = index;
31
32 using T = std::remove_reference_t<decltype(v)>;
33 using I = std::remove_reference_t<decltype(i)>;
34
35 typename std::allocator_traits<Allocator>::template rebind_alloc<I>
36 i_allocator(allocator);
37
38 T *values = allocator.allocate(nnz);
39 I *rowptr = i_allocator.allocate(shape[0] + 1);
40 I *colind = i_allocator.allocate(nnz);
41
42 rowptr[0] = 0;
43
44 std::size_t r = 0;
45 std::size_t c = 0;
46 for (auto iter = tuples.begin(); iter != tuples.end(); ++iter) {
47 auto &&[index, value] = *iter;
48
49 auto &&[i, j] = index;
50
51 values[c] = value;
52 colind[c] = j;
53
54 while (r < i) {
55 assert(r + 1 <= shape[0]);
56 // throw std::runtime_error("csr_matrix_impl_: given invalid matrix");
57 rowptr[r + 1] = c;
58 r++;
59 }
60 c++;
61
62 assert(c <= nnz);
63 // throw std::runtime_error("csr_matrix_impl_: given invalid matrix");
64 }
65
66 for (; r < shape[0]; r++) {
67 rowptr[r + 1] = nnz;
68 }
69
70 return dr::views::csr_matrix_view(values, rowptr, colind,
71 dr::index<I>(shape[0], shape[1]), nnz, 0);
72}
73
74template <typename Tuples, typename Allocator>
75auto convert_csr_base_to_csr(Tuples &&csr_matrix, dr::index<> shape,
76 std::size_t nnz, Allocator &&allocator) {
77 auto &&[v, j] = *csr_matrix.begin()->begin();
78
79 using T = std::remove_reference_t<decltype(v)>;
80 using I = std::remove_reference_t<decltype(j)>;
81
82 typename std::allocator_traits<Allocator>::template rebind_alloc<I>
83 i_allocator(allocator);
84
85 T *values = allocator.allocate(nnz);
86 I *rowptr = i_allocator.allocate(shape[0] + 1);
87 I *colind = i_allocator.allocate(nnz);
88
89 rowptr[0] = 0;
90
91 std::size_t r = 0;
92 std::size_t c = 0;
93 for (auto iter = csr_matrix.begin(); iter != csr_matrix.end(); ++iter) {
94 for (auto iter2 = iter->begin(); iter2 != iter->end(); ++iter2) {
95 auto &&[value, j] = *iter2;
96
97 values[c] = value;
98 colind[c] = j;
99 c++;
100 }
101 assert(r + 1 <= shape[0]);
102 rowptr[r + 1] = c;
103 r++;
104
105 assert(c <= nnz);
106 // throw std::runtime_error("csr_matrix_impl_: given invalid matrix");
107 }
108
109 for (; r < shape[0]; r++) {
110 rowptr[r + 1] = nnz;
111 }
112
113 return dr::views::csr_matrix_view(values, rowptr, colind,
114 dr::index<I>(shape[0], shape[1]), nnz, 0);
115}
116
119template <typename T, typename I = std::size_t>
120inline csr_matrix_base<T, I> read_csr_matrix_base(std::string file_path,
121 bool one_indexed = true) {
122 using size_type = std::size_t;
123
124 std::ifstream f;
125
126 f.open(file_path.c_str());
127
128 if (!f.is_open()) {
129 // TODO better choice of exception.
130 throw std::runtime_error("mmread: cannot open " + file_path);
131 }
132
133 std::string buf;
134
135 // Make sure the file is matrix market matrix, coordinate, and check whether
136 // it is symmetric. If the matrix is symmetric, non-diagonal elements will
137 // be inserted in both (i, j) and (j, i). Error out if skew-symmetric or
138 // Hermitian.
139 std::getline(f, buf);
140 std::istringstream ss(buf);
141 std::string item;
142 ss >> item;
143 if (item != "%%MatrixMarket") {
144 throw std::runtime_error(file_path +
145 " could not be parsed as a Matrix Market file.");
146 }
147 ss >> item;
148 if (item != "matrix") {
149 throw std::runtime_error(file_path +
150 " could not be parsed as a Matrix Market file.");
151 }
152 ss >> item;
153 if (item != "coordinate") {
154 throw std::runtime_error(file_path +
155 " could not be parsed as a Matrix Market file.");
156 }
157 bool pattern;
158 ss >> item;
159 if (item == "pattern") {
160 pattern = true;
161 } else {
162 pattern = false;
163 }
164 // TODO: do something with real vs. integer vs. pattern?
165 ss >> item;
166 bool symmetric;
167 if (item == "general") {
168 symmetric = false;
169 } else if (item == "symmetric") {
170 symmetric = true;
171 } else {
172 throw std::runtime_error(file_path + " has an unsupported matrix type");
173 }
174
175 bool outOfComments = false;
176 while (!outOfComments) {
177 std::getline(f, buf);
178
179 if (buf[0] != '%') {
180 outOfComments = true;
181 }
182 }
183
184 I m, n, nnz;
185 // std::istringstream ss(buf);
186 ss.clear();
187 ss.str(buf);
188 ss >> m >> n >> nnz;
189
190 // NOTE for symmetric matrices: `nnz` holds the number of stored values in
191 // the matrix market file, while `matrix.nnz_` will hold the total number of
192 // stored values (including "mirrored" symmetric values).
193 csr_matrix_base<T, I> matrix({m, n}, nnz);
194
195 size_type c = 0;
196 while (std::getline(f, buf)) {
197 I i, j;
198 T v;
199 std::istringstream ss(buf);
200 if (!pattern) {
201 ss >> i >> j >> v;
202 } else {
203 ss >> i >> j;
204 v = T(1);
205 }
206 if (one_indexed) {
207 i--;
208 j--;
209 }
210
211 if (i >= m || j >= n) {
212 throw std::runtime_error(
213 "read_MatrixMarket: file has nonzero out of bounds.");
214 }
215
216 matrix.push_back(i, {v, j});
217
218 if (symmetric && i != j) {
219 matrix.push_back(j, {v, i});
220 }
221
222 c++;
223 if (c > nnz) {
224 throw std::runtime_error("read_MatrixMarket: error reading Matrix Market "
225 "file, file has more nonzeros than reported.");
226 }
227 }
228
229 matrix.sort();
230 f.close();
231
232 return matrix;
233}
234
235template <typename T, typename I, typename Allocator, typename... Args>
236void destroy_csr_matrix_view(dr::views::csr_matrix_view<T, I, Args...> view,
237 Allocator &&alloc) {
238 alloc.deallocate(view.values_data(), view.size());
239 typename std::allocator_traits<Allocator>::template rebind_alloc<I> i_alloc(
240 alloc);
241 i_alloc.deallocate(view.colind_data(), view.size());
242 i_alloc.deallocate(view.rowptr_data(), view.shape()[0] + 1);
243}
244
245} // namespace __detail
246
247template <typename T, typename I = std::size_t>
248auto read_csr(std::string file_path, bool one_indexed = true) {
249 auto m = __detail::read_csr_matrix_base<T, I>(file_path, one_indexed);
250 auto shape = m.shape();
251 auto nnz = m.size();
252 auto t =
253 __detail::convert_csr_base_to_csr(m, shape, nnz, std::allocator<T>{});
254
255 return t;
256}
257} // namespace dr
Definition: index.hpp:34
Definition: csr_matrix_view.hpp:126