cyqlone develop
Fast, parallel and vectorized solver for linear systems with optimal control structure.
Loading...
Searching...
No Matches
matio.cpp
Go to the documentation of this file.
1#include <cyqlone/matio.hpp>
2#include <cyqlone/ocp.hpp>
3#include <batmat/linalg/copy.hpp>
4#include <guanaqo/string-util.hpp>
5#include <matio.h>
6
7#include <algorithm>
8#include <climits>
9#include <concepts>
10#include <cstring>
11#include <filesystem>
12#include <format>
13#include <memory>
14#include <span>
15#include <stdexcept>
16#include <vector>
17
18namespace cyqlone {
19
20template <class T>
22template <>
23struct matio_traits<float> {
24 static constexpr auto type = MAT_T_SINGLE;
25 static constexpr auto class_ = MAT_C_SINGLE;
26};
27template <>
28struct matio_traits<double> {
29 static constexpr auto type = MAT_T_DOUBLE;
30 static constexpr auto class_ = MAT_C_DOUBLE;
31};
32template <std::unsigned_integral I>
33struct matio_traits<I> {
34 static constexpr auto type = sizeof(I) == 1 ? MAT_T_UINT8
35 : sizeof(I) == 2 ? MAT_T_UINT16
36 : sizeof(I) == 4 ? MAT_T_UINT32
37 : sizeof(I) == 8 ? MAT_T_UINT64
38 : MAT_T_UNKNOWN;
39 static constexpr auto class_ = sizeof(I) == 1 ? MAT_C_UINT8
40 : sizeof(I) == 2 ? MAT_C_UINT16
41 : sizeof(I) == 4 ? MAT_C_UINT32
42 : sizeof(I) == 8 ? MAT_C_UINT64
43 : MAT_C_EMPTY;
44 static_assert(CHAR_BIT == 8, "Unsupported char size");
45 static_assert(type != MAT_T_UNKNOWN, "Unsupported unsigned integer type");
46 static_assert(class_ != MAT_C_EMPTY, "Unsupported unsigned integer type");
47};
48template <std::signed_integral I>
49struct matio_traits<I> {
50 static constexpr auto type = sizeof(I) == 1 ? MAT_T_INT8
51 : sizeof(I) == 2 ? MAT_T_INT16
52 : sizeof(I) == 4 ? MAT_T_INT32
53 : sizeof(I) == 8 ? MAT_T_INT64
54 : MAT_T_UNKNOWN;
55 static constexpr auto class_ = sizeof(I) == 1 ? MAT_C_INT8
56 : sizeof(I) == 2 ? MAT_C_INT16
57 : sizeof(I) == 4 ? MAT_C_INT32
58 : sizeof(I) == 8 ? MAT_C_INT64
59 : MAT_C_EMPTY;
60 static_assert(CHAR_BIT == 8, "Unsupported char size");
61 static_assert(type != MAT_T_UNKNOWN, "Unsupported signed integer type");
62 static_assert(class_ != MAT_C_EMPTY, "Unsupported signed integer type");
63};
64
65// RAII wrappers
66using MatFilePtr = std::unique_ptr<mat_t, decltype(&Mat_Close)>;
67using MatVarPtr = std::unique_ptr<matvar_t, decltype(&Mat_VarFree)>;
68
69template <class T, size_t N>
70MatVarPtr create_tensor_var(const char *name, std::span<const T> buffer,
71 std::array<index_t, N> dims) {
72 std::array<size_t, N> dimsu;
73 std::ranges::copy(dims, dimsu.begin());
75 dimsu.size(), dimsu.data(), const_cast<T *>(buffer.data()), 0),
76 Mat_VarFree);
77}
78
79template <class T, size_t N>
80void write_tensor(mat_t *matfp, const char *name, std::span<const T> buffer,
81 std::array<index_t, N> dims) {
82 MatVarPtr var = create_tensor_var(name, buffer, dims);
83 if (!var)
84 throw std::runtime_error(std::format("Failed to create var {}", name));
85 if (auto e = Mat_VarWrite(matfp, var.get(), MAT_COMPRESSION_ZLIB); e)
86 throw std::runtime_error(std::format("Failed to write var {} ({})", name, e));
87}
88
89MatFilePtr open_mat(const std::filesystem::path &filename, MatioOpenMode mode) {
90 int imode = mode == MatioOpenMode::Write ? MAT_ACC_RDWR : MAT_ACC_RDONLY;
91 MatFilePtr matfp(Mat_Open(filename.c_str(), imode), Mat_Close);
92 if (!matfp)
93 throw std::runtime_error(std::format("Failed to open .mat file {}", filename.string()));
94 return matfp;
95}
96
97MatFilePtr create_mat(const std::filesystem::path &filename) {
98 MatFilePtr matfp(Mat_CreateVer(filename.c_str(), nullptr, MAT_FT_MAT5), Mat_Close);
99 if (!matfp)
100 throw std::runtime_error(std::format("Failed to create .mat file {}", filename.string()));
101 return matfp;
102}
103
104template <class T>
105void add_to_mat_impl(mat_t *mat, const std::string &varname,
107 const auto r = static_cast<size_t>(data.rows), c = static_cast<size_t>(data.cols);
108 if (data.rows == data.outer_stride) {
109 write_tensor<T, 2>(mat, varname.c_str(), std::span{data.data, r * c},
110 {data.rows, data.cols});
111 } else {
112 std::vector<T> buffer(r * c);
114 .data = buffer.data(),
115 .rows = data.rows,
116 .cols = data.cols,
117 }} = data;
118 write_tensor<T, 2>(mat, varname.c_str(), std::span{buffer}, {data.rows, data.cols});
119 }
120}
121
122void add_to_mat(mat_t *mat, const std::string &varname, float value) {
123 write_tensor<float, 1>(mat, varname.c_str(), std::span{&value, 1}, {1});
124}
125
126void add_to_mat(mat_t *mat, const std::string &varname, double value) {
127 write_tensor<double, 1>(mat, varname.c_str(), std::span{&value, 1}, {1});
128}
129
130void add_to_mat(mat_t *mat, const std::string &varname, unsigned short value) {
131 write_tensor<unsigned short, 1>(mat, varname.c_str(), std::span{&value, 1}, {1});
132}
133
134void add_to_mat(mat_t *mat, const std::string &varname, unsigned int value) {
135 write_tensor<unsigned int, 1>(mat, varname.c_str(), std::span{&value, 1}, {1});
136}
137
138void add_to_mat(mat_t *mat, const std::string &varname, unsigned long value) {
139 write_tensor<unsigned long, 1>(mat, varname.c_str(), std::span{&value, 1}, {1});
140}
141
142void add_to_mat(mat_t *mat, const std::string &varname, unsigned long long value) {
143 write_tensor<unsigned long long, 1>(mat, varname.c_str(), std::span{&value, 1}, {1});
144}
145
146void add_to_mat(mat_t *mat, const std::string &varname, short value) {
147 write_tensor<short, 1>(mat, varname.c_str(), std::span{&value, 1}, {1});
148}
149
150void add_to_mat(mat_t *mat, const std::string &varname, int value) {
151 write_tensor<int, 1>(mat, varname.c_str(), std::span{&value, 1}, {1});
152}
153
154void add_to_mat(mat_t *mat, const std::string &varname, long value) {
155 write_tensor<long, 1>(mat, varname.c_str(), std::span{&value, 1}, {1});
156}
157
158void add_to_mat(mat_t *mat, const std::string &varname, long long value) {
159 write_tensor<long long, 1>(mat, varname.c_str(), std::span{&value, 1}, {1});
160}
161
162void add_to_mat(mat_t *mat, const std::string &varname,
164 add_to_mat_impl(mat, varname, data);
165}
166
167void add_to_mat(mat_t *mat, const std::string &varname,
169 add_to_mat_impl(mat, varname, data);
170}
171
172template <class T>
173void add_to_mat_impl(mat_t *mat, const std::string &varname,
175 const auto r = static_cast<size_t>(data.rows()), c = static_cast<size_t>(data.cols()),
176 d = static_cast<size_t>(data.depth());
177 if (data.rows() == data.outer_stride() && data.layer_stride() == data.rows() * data.cols()) {
178 write_tensor<T, 3>(mat, varname.c_str(), std::span{data.data(), r * c * d},
179 {data.rows(), data.cols(), data.depth()});
180 } else {
182 .depth = data.depth(),
183 .rows = data.rows(),
184 .cols = data.cols(),
185 }};
186 for (index_t l = 0; l < data.depth(); ++l)
187 batmat::linalg::copy(data(l), buffer(l));
188 add_to_mat(mat, varname, buffer.view());
189 }
190}
191
192void add_to_mat(mat_t *mat, const std::string &varname,
194 add_to_mat_impl(mat, varname, data);
195}
196
197void add_to_mat(mat_t *mat, const std::string &varname,
199 add_to_mat_impl(mat, varname, data);
200}
201
202void add_to_mat(mat_t *mat, const std::string &varname, std::span<const float> data) {
203 write_tensor<float, 1>(mat, varname.c_str(), data, {static_cast<index_t>(data.size())});
204}
205
206void add_to_mat(mat_t *mat, const std::string &varname, std::span<const double> data) {
207 write_tensor<double, 1>(mat, varname.c_str(), data, {static_cast<index_t>(data.size())});
208}
209
210void add_to_mat(mat_t *mat, const std::string &varname, std::span<const unsigned short> data) {
211 write_tensor<unsigned short, 1>(mat, varname.c_str(), data,
212 {static_cast<index_t>(data.size())});
213}
214
215void add_to_mat(mat_t *mat, const std::string &varname, std::span<const unsigned int> data) {
216 write_tensor<unsigned int, 1>(mat, varname.c_str(), data, {static_cast<index_t>(data.size())});
217}
218
219void add_to_mat(mat_t *mat, const std::string &varname, std::span<const unsigned long> data) {
220 write_tensor<unsigned long, 1>(mat, varname.c_str(), data, {static_cast<index_t>(data.size())});
221}
222
223void add_to_mat(mat_t *mat, const std::string &varname, std::span<const unsigned long long> data) {
224 write_tensor<unsigned long long, 1>(mat, varname.c_str(), data,
225 {static_cast<index_t>(data.size())});
226}
227
228void add_to_mat(mat_t *mat, const std::string &varname, std::span<const short> data) {
229 write_tensor<short, 1>(mat, varname.c_str(), data, {static_cast<index_t>(data.size())});
230}
231
232void add_to_mat(mat_t *mat, const std::string &varname, std::span<const int> data) {
233 write_tensor<int, 1>(mat, varname.c_str(), data, {static_cast<index_t>(data.size())});
234}
235
236void add_to_mat(mat_t *mat, const std::string &varname, std::span<const long> data) {
237 write_tensor<long, 1>(mat, varname.c_str(), data, {static_cast<index_t>(data.size())});
238}
239
240void add_to_mat(mat_t *mat, const std::string &varname, std::span<const long long> data) {
241 write_tensor<long long, 1>(mat, varname.c_str(), data, {static_cast<index_t>(data.size())});
242}
243
244void add_to_mat(mat_t *mat, const std::string &varname, const SparseMatrix &matrix) {
245 std::array<const char *, 5> fieldnames{"num_rows", "num_cols", "row_indices", "col_indices",
246 "values"};
247 std::array<size_t, 2> struct_dims{1, 1};
248 MatVarPtr struct_{Mat_VarCreateStruct(varname.c_str(), struct_dims.size(), struct_dims.data(),
249 fieldnames.data(), fieldnames.size()),
250 Mat_VarFree};
251 if (!struct_)
252 throw std::runtime_error(std::format("Failed to create struct {}", varname));
253 using index_traits = matio_traits<decltype(SparseMatrix::row_indices)::value_type>;
254 std::array<size_t, 2> scalar_dims{1, 1}; // MATLAB scalars are 1x1 matrices
255 Mat_VarSetStructFieldByIndex(struct_.get(), 0, 0,
256 Mat_VarCreate("num_rows", index_traits::class_, index_traits::type,
257 scalar_dims.size(), scalar_dims.data(),
258 &matrix.sparsity.rows, 0));
259 Mat_VarSetStructFieldByIndex(struct_.get(), 1, 0,
260 Mat_VarCreate("num_cols", index_traits::class_, index_traits::type,
261 scalar_dims.size(), scalar_dims.data(),
262 &matrix.sparsity.cols, 0));
263 const size_t n_row_indices = matrix.sparsity.row_indices.size();
264 Mat_VarSetStructFieldByIndex(struct_.get(), 2, 0,
265 Mat_VarCreate("row_indices", index_traits::class_,
266 index_traits::type, 1, &n_row_indices,
267 matrix.sparsity.row_indices.data(), 0));
268 const size_t n_col_indices = matrix.sparsity.col_indices.size();
269 Mat_VarSetStructFieldByIndex(struct_.get(), 3, 0,
270 Mat_VarCreate("col_indices", index_traits::class_,
271 index_traits::type, 1, &n_col_indices,
272 matrix.sparsity.col_indices.data(), 0));
273 using value_traits = matio_traits<decltype(SparseMatrix::values)::value_type>;
274 const size_t n_values = matrix.values.size();
275 Mat_VarSetStructFieldByIndex(struct_.get(), 4, 0,
276 Mat_VarCreate("values", value_traits::class_, value_traits::type,
277 1, &n_values, matrix.values.data(), 0));
278 if (auto e = Mat_VarWrite(mat, struct_.get(), MAT_COMPRESSION_ZLIB); e)
279 throw std::runtime_error(std::format("Failed to write struct {} ({})", varname, e));
280}
281
282void add_to_mat(mat_t *mat, const std::string &varname, const LinearOCPStorage &ocp) {
283 const auto [N, nx, nu, ny, ny_N] = ocp.dim;
284 const auto nxu = nx + nu;
286 std::array<const char *, 8> fieldnames{"H", "CD", "CN", "AB", "qr", "b", "b_min", "b_max"};
287 std::array<size_t, 2> struct_dims{1, 1};
288 MatVarPtr struct_{Mat_VarCreateStruct(varname.c_str(), struct_dims.size(), struct_dims.data(),
289 fieldnames.data(), fieldnames.size()),
290 Mat_VarFree};
291 if (!struct_)
292 throw std::runtime_error(std::format("Failed to create struct {}", varname));
293 const auto set_struct_field = [&](size_t field_index, MatVarPtr field) {
294 if (std::strcmp(field->name, fieldnames[field_index]) != 0)
295 throw std::runtime_error(std::format("Field name mismatch: expected {}, got {}",
296 fieldnames[field_index], field->name));
297 if (!field)
298 throw std::runtime_error(std::format("Failed to create field {} in struct {}",
299 fieldnames[field_index], varname));
300 Mat_VarSetStructFieldByIndex(struct_.get(), field_index, 0, field.release());
301 };
302
303 // H: (nx+nu, nx+nu, N+1)
304 std::vector<real_t> buf((N + 1) * nxu * nxu, 0.0);
305 for (index_t i = 0; i < N; ++i)
307 ocp.H(i),
308 Mat{{.data = &buf[i * nxu * nxu], .rows = nxu, .cols = nxu, .outer_stride = nxu}});
309 // Q(N): (nx, nx), padded by zeros
311 ocp.Q(N), Mat{{.data = &buf[N * nxu * nxu], .rows = nx, .cols = nx, .outer_stride = nxu}});
312 set_struct_field(0, create_tensor_var<real_t, 3>("H", buf, {nxu, nxu, N + 1}));
313
314 // CD: (ny, nx+nu, N)
315 buf.resize(N * ny * nxu);
316 for (index_t i = 0; i < N; ++i)
318 ocp.CD(i),
319 Mat{{.data = &buf[i * ny * nxu], .rows = ny, .cols = nxu, .outer_stride = ny}});
320 set_struct_field(1, create_tensor_var<real_t, 3>("CD", buf, {ny, nxu, N}));
321 // C(N): (ny_N, nx+nu)
322 buf.resize(ny_N * nx);
323 batmat::linalg::copy(ocp.C(N),
324 Mat{{.data = buf.data(), .rows = ny_N, .cols = nx, .outer_stride = ny_N}});
325 set_struct_field(2, create_tensor_var<real_t, 2>("CN", buf, {ny_N, nx}));
326
327 // AB: (nx, nx+nu, N)
328 buf.resize(N * nx * nxu);
329 for (index_t i = 0; i < N; ++i)
331 ocp.AB(i),
332 Mat{{.data = &buf[i * nx * nxu], .rows = nx, .cols = nxu, .outer_stride = nx}});
333 set_struct_field(3, create_tensor_var<real_t, 3>("AB", buf, {nx, nxu, N}));
334
335 // Vectors
336 set_struct_field(4, create_tensor_var<real_t, 2>("qr", std::span(ocp.qr().data, ocp.qr().rows),
337 {ocp.qr().rows, 1}));
338 set_struct_field(5, create_tensor_var<real_t, 2>("b", std::span(ocp.b().data, ocp.b().rows),
339 {ocp.b().rows, 1}));
340 set_struct_field(6, create_tensor_var<real_t, 2>("b_min",
341 std::span(ocp.b_min().data, ocp.b_min().rows),
342 {ocp.b_min().rows, 1}));
343 set_struct_field(7, create_tensor_var<real_t, 2>("b_max",
344 std::span(ocp.b_max().data, ocp.b_max().rows),
345 {ocp.b_max().rows, 1}));
346
347 if (auto e = Mat_VarWrite(mat, struct_.get(), MAT_COMPRESSION_ZLIB); e)
348 throw std::runtime_error(std::format("Failed to write struct {} ({})", varname, e));
349}
350
351void validate_mat_var(const matvar_t *var, const std::string &name, int expected_rank) {
352 if (!var)
353 throw std::runtime_error(std::format("Variable {} is missing", name));
354 if (var->rank != expected_rank)
355 throw std::runtime_error(std::format("Variable {}: invalid rank {} (expected {})", name,
356 var->rank, expected_rank));
357 if (var->isComplex)
358 throw std::runtime_error(std::format("Variable {}: should be real", name));
359 if (var->class_type != matio_traits<real_t>::class_)
360 throw std::runtime_error(std::format("Variable {}: invalid class type", name));
361 if (var->data_type != matio_traits<real_t>::type)
362 throw std::runtime_error(std::format("Variable {}: invalid data type", name));
363}
364
365void read_from_mat(mat_t *mat, const std::string &varname, LinearOCPStorage &ocp) {
366 MatVarPtr ocpvar(Mat_VarRead(mat, varname.c_str()), Mat_VarFree);
367 if (!ocpvar)
368 throw std::runtime_error(std::format("Missing variable: {}", varname));
369 if (ocpvar->class_type != MAT_C_STRUCT)
370 throw std::runtime_error(std::format("Variable {} should be a struct", varname));
371
372 const matvar_t *ABmat = Mat_VarGetStructFieldByName(ocpvar.get(), "AB", 0);
373 const matvar_t *CDmat = Mat_VarGetStructFieldByName(ocpvar.get(), "CD", 0);
374 const matvar_t *CNmat = Mat_VarGetStructFieldByName(ocpvar.get(), "CN", 0);
375 const matvar_t *Hmat = Mat_VarGetStructFieldByName(ocpvar.get(), "H", 0);
376 const matvar_t *qrmat = Mat_VarGetStructFieldByName(ocpvar.get(), "qr", 0);
377 const matvar_t *bmat = Mat_VarGetStructFieldByName(ocpvar.get(), "b", 0);
378 const matvar_t *b_minmat = Mat_VarGetStructFieldByName(ocpvar.get(), "b_min", 0);
379 const matvar_t *b_maxmat = Mat_VarGetStructFieldByName(ocpvar.get(), "b_max", 0);
380
381 std::vector<std::string_view> missing;
382 if (!ABmat)
383 missing.emplace_back("AB");
384 if (!CDmat)
385 missing.emplace_back("CD");
386 if (!CNmat)
387 missing.emplace_back("CN");
388 if (!Hmat)
389 missing.emplace_back("H");
390 if (!qrmat)
391 missing.emplace_back("qr");
392 if (!bmat)
393 missing.emplace_back("b");
394 if (!b_minmat)
395 missing.emplace_back("b_min");
396 if (!b_maxmat)
397 missing.emplace_back("b_max");
398 if (!missing.empty())
399 throw std::runtime_error(
400 std::format("Variable {} is missing fields: {}", varname, guanaqo::join(missing)));
401 validate_mat_var(ABmat, "AB", 3);
402 validate_mat_var(CDmat, "CD", 3);
403 validate_mat_var(CNmat, "CN", 2);
404 validate_mat_var(Hmat, "H", 3);
405 validate_mat_var(qrmat, "qr", 2);
406 validate_mat_var(bmat, "b", 2);
407 validate_mat_var(b_minmat, "b_min", 2);
408 validate_mat_var(b_maxmat, "b_max", 2);
409 auto nx = static_cast<index_t>(ABmat->dims[0]), nxu = static_cast<index_t>(ABmat->dims[1]),
410 N = static_cast<index_t>(ABmat->dims[2]), nu = nxu - nx;
411 auto ny = static_cast<index_t>(CDmat->dims[0]), ny_N = static_cast<index_t>(CNmat->dims[0]);
412 BATMAT_ASSERT(nxu >= nx);
413 BATMAT_ASSERT(static_cast<index_t>(Hmat->dims[0]) == nxu);
414 BATMAT_ASSERT(static_cast<index_t>(Hmat->dims[1]) == nxu);
415 BATMAT_ASSERT(static_cast<index_t>(Hmat->dims[2]) == N + 1);
416 BATMAT_ASSERT(static_cast<index_t>(CDmat->dims[1]) == nxu);
417 BATMAT_ASSERT(static_cast<index_t>(CDmat->dims[2]) == N);
418 BATMAT_ASSERT(static_cast<index_t>(CNmat->dims[1]) == nx);
419 BATMAT_ASSERT(static_cast<index_t>(qrmat->dims[0]) == N * nxu + nx);
420 BATMAT_ASSERT(static_cast<index_t>(qrmat->dims[1]) == 1);
421 BATMAT_ASSERT(static_cast<index_t>(bmat->dims[0]) == (N + 1) * nx);
422 BATMAT_ASSERT(static_cast<index_t>(bmat->dims[1]) == 1);
423 BATMAT_ASSERT(static_cast<index_t>(b_minmat->dims[0]) == N * ny + ny_N);
424 BATMAT_ASSERT(static_cast<index_t>(b_minmat->dims[1]) == 1);
425 BATMAT_ASSERT(static_cast<index_t>(b_maxmat->dims[0]) == N * ny + ny_N);
426 BATMAT_ASSERT(static_cast<index_t>(b_maxmat->dims[1]) == 1);
427
429 View<const real_t, index_t> ABview{
430 {.data = static_cast<const real_t *>(ABmat->data), .depth = N, .rows = nx, .cols = nxu}};
431 View<const real_t, index_t> CDview{
432 {.data = static_cast<const real_t *>(CDmat->data), .depth = N, .rows = ny, .cols = nxu}};
433 View<const real_t, index_t> CNview{
434 {.data = static_cast<const real_t *>(CNmat->data), .depth = 1, .rows = ny_N, .cols = nx}};
435 View<const real_t, index_t> Hview{{.data = static_cast<const real_t *>(Hmat->data),
436 .depth = N + 1,
437 .rows = nxu,
438 .cols = nxu}};
439 View<const real_t, index_t> qrview{{.data = static_cast<const real_t *>(qrmat->data),
440 .depth = 1,
441 .rows = N * nxu + nx,
442 .cols = 1}};
443 View<const real_t, index_t> bview{{.data = static_cast<const real_t *>(bmat->data),
444 .depth = 1,
445 .rows = (N + 1) * nx,
446 .cols = 1}};
447 View<const real_t, index_t> b_minview{{.data = static_cast<const real_t *>(b_minmat->data),
448 .depth = 1,
449 .rows = N * ny + ny_N,
450 .cols = 1}};
451 View<const real_t, index_t> b_maxview{{.data = static_cast<const real_t *>(b_maxmat->data),
452 .depth = 1,
453 .rows = N * ny + ny_N,
454 .cols = 1}};
455
456 ocp = {.dim = {.N_horiz = N, .nx = nx, .nu = nu, .ny = ny, .ny_N = ny_N}};
457
458 // H: (nx+nu, nx+nu, N+1)
459 for (index_t i = 0; i < N; ++i)
460 batmat::linalg::copy(Hview(i), ocp.H(i));
461 // Q(N): (nx, nx), padded by zeros
462 batmat::linalg::copy(Hview(N).top_left(nx, nx), ocp.Q(N));
463
464 // CD: (ny, nx+nu, N)
465 for (index_t i = 0; i < N; ++i)
466 batmat::linalg::copy(CDview(i), ocp.CD(i));
467 // C(N): (ny_N, nx+nu)
468 batmat::linalg::copy(CNview(0), ocp.C(N));
469
470 // AB: (nx, nx+nu, N)
471 for (index_t i = 0; i < N; ++i)
472 batmat::linalg::copy(ABview(i), ocp.AB(i));
473
474 // Vectors
475 ocp.qr() = qrview(0);
476 ocp.b() = bview(0);
477 ocp.b_min() = b_minview(0);
478 ocp.b_max() = b_maxview(0);
479}
480
481auto open_vector_var(mat_t *mat, const std::string &varname) {
482 MatVarPtr var(Mat_VarRead(mat, varname.c_str()), Mat_VarFree);
483 if (!var)
484 throw std::runtime_error(std::format("Missing variable: {}", varname));
485 validate_mat_var(var.get(), varname, 2);
486 if (var->dims[1] != 1)
487 throw std::runtime_error(std::format("Variable {}: should have one column", varname));
488 return var;
489}
490
491void read_from_mat(mat_t *mat, const std::string &varname, std::span<float> data) {
492 auto var = open_vector_var(mat, varname);
493 auto n = var->dims[0];
494 BATMAT_ASSERT(n == data.size());
495 const auto *var_data = static_cast<const float *>(var->data);
496 std::copy_n(var_data, n, data.begin());
497}
498
499void read_from_mat(mat_t *mat, const std::string &varname, std::span<double> data) {
500 auto var = open_vector_var(mat, varname);
501 auto n = var->dims[0];
502 BATMAT_ASSERT(n == data.size());
503 const auto *var_data = static_cast<const double *>(var->data);
504 std::copy_n(var_data, n, data.begin());
505}
506
507void read_from_mat(mat_t *mat, const std::string &varname, std::vector<float> &data) {
508 auto var = open_vector_var(mat, varname);
509 auto n = var->dims[0];
510 data.resize(n);
511 const auto *var_data = static_cast<const float *>(var->data);
512 std::copy_n(var_data, n, data.begin());
513}
514
515void read_from_mat(mat_t *mat, const std::string &varname, std::vector<double> &data) {
516 auto var = open_vector_var(mat, varname);
517 auto n = var->dims[0];
518 data.resize(n);
519 const auto *var_data = static_cast<const double *>(var->data);
520 std::copy_n(var_data, n, data.begin());
521}
522
523void ocp_dump_mat(const std::filesystem::path &filename, const LinearOCPStorage &ocp) {
524 auto matfp = create_mat(filename);
525 add_to_mat(matfp.get(), "ocp", ocp);
526}
527
528} // namespace cyqlone
#define BATMAT_ASSERT(x)
std::string join(std::ranges::input_range auto strings, join_opt opt={})
void copy(VA &&A, VB &&B, Opts... opts)
MatFilePtr create_mat(const std::filesystem::path &filename)
Create and open a new .mat file for writing.
Definition matio.cpp:97
MatioOpenMode
Definition matio.hpp:28
void add_to_mat(mat_t *mat, const std::string &varname, float value)
Add a value to an open .mat file.
Definition matio.cpp:122
void read_from_mat(mat_t *mat, const std::string &varname, LinearOCPStorage &ocp)
Load a LinearOCPStorage from a .mat file.
Definition matio.cpp:365
MatFilePtr open_mat(const std::filesystem::path &filename, MatioOpenMode mode=MatioOpenMode::Read)
Opens a .mat file for reading or writing.
Definition matio.cpp:89
::_mat_t mat_t
Incomplete matio struct type.
Definition matio.hpp:24
std::unique_ptr< mat_t, int(*)(mat_t *)> MatFilePtr
Owning handle to a matio file. The file will be closed when the handle goes out of scope.
Definition matio.hpp:26
void ocp_dump_mat(const std::filesystem::path &filename, const LinearOCPStorage &ocp)
Dump the data from a LinearOCPStorage to a new .mat file.
Definition matio.cpp:523
Functions for exporting and loading matrices and OCP data to and from .mat files.
simd_view_types< std::remove_const_t< T >, Abi >::template matrix< T, Order > matrix
void validate_mat_var(const matvar_t *var, const std::string &name, int expected_rank)
Definition matio.cpp:351
auto open_vector_var(mat_t *mat, const std::string &varname)
Definition matio.cpp:481
MatVarPtr create_tensor_var(const char *name, std::span< const T > buffer, std::array< index_t, N > dims)
Definition matio.cpp:70
void add_to_mat_impl(mat_t *mat, const std::string &varname, guanaqo::MatrixView< const T, index_t > data)
Definition matio.cpp:105
std::unique_ptr< matvar_t, decltype(&Mat_VarFree)> MatVarPtr
Definition matio.cpp:67
void write_tensor(mat_t *matfp, const char *name, std::span< const T > buffer, std::array< index_t, N > dims)
Definition matio.cpp:80
Data structure for optimal control problems.
Storage for a linear-quadratic OCP of the form.
Definition ocp.hpp:37
guanaqo::MatrixView< real_t, index_t > CD(index_t i)
Definition ocp.hpp:95
guanaqo::MatrixView< real_t, index_t > b_min()
Definition ocp.hpp:267
guanaqo::MatrixView< real_t, index_t > b()
Definition ocp.hpp:251
guanaqo::MatrixView< real_t, index_t > H(index_t i)
Definition ocp.hpp:64
guanaqo::MatrixView< real_t, index_t > C(index_t i)
Definition ocp.hpp:106
guanaqo::MatrixView< real_t, index_t > Q(index_t i)
Definition ocp.hpp:75
guanaqo::MatrixView< real_t, index_t > b_max()
Definition ocp.hpp:283
guanaqo::MatrixView< real_t, index_t > AB(index_t i)
Definition ocp.hpp:116
guanaqo::MatrixView< real_t, index_t > qr()
Definition ocp.hpp:225
A sparse matrix in COO format.
Definition sparse.hpp:26
const std::vector< index_t > row_indices
Definition sparse.hpp:27
const std::vector< real_t > values
Definition sparse.hpp:28
static constexpr auto type
Definition matio.cpp:34
static constexpr auto class_
Definition matio.cpp:39
static constexpr auto class_
Definition matio.cpp:30
static constexpr auto type
Definition matio.cpp:29
static constexpr auto class_
Definition matio.cpp:25
static constexpr auto type
Definition matio.cpp:24