guanaqo 1.0.0-alpha.24
Utilities for scientific software
Loading...
Searching...
No Matches
matrix-view.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file
4/// @ingroup linalg_views
5/// Conversion between guanaqo::MatrixView and NumPy arrays for nanobind bindings.
6
8#include <nanobind/nanobind.h>
9#include <nanobind/ndarray.h>
10#include <type_traits>
11#include <variant>
12
14
15/// @addtogroup linalg_views
16/// @{
17
18/// Nanobind type caster for @ref guanaqo::MatrixView.
19/// Supports only NumPy arrays on CPU. No conversions or copies are performed.
20template <class T, class I, class S, guanaqo::StorageOrder O>
21struct type_caster<guanaqo::MatrixView<T, I, S, O>> {
23
25 static constexpr bool is_row_major = MatrixView::is_row_major;
26 static constexpr bool has_static_inner_stride = requires {
27 { S::value } -> std::convertible_to<I>;
28 };
29
30 using NDArray = ndarray<numpy, T, ndim<2>, device::cpu>;
32 using Contig = std::conditional_t<is_row_major, c_contig, f_contig>;
33 using NDArrayContig = ndarray<numpy, T, ndim<2>, Contig, device::cpu>;
35
36 NB_TYPE_CASTER(MatrixView, NDArrayCaster::Name);
37
38 type_caster() : value{{.data = nullptr, .rows = 0, .cols = 0}} {}
39 type_caster(const type_caster &) = default;
40 type_caster(type_caster &&) noexcept = default;
41
42 private:
44
45 bool from_python_(auto &caster, handle src, uint8_t flags,
46 cleanup_list *cleanup) noexcept {
47 if (!caster.from_python(src, flags, cleanup))
48 return false;
49 auto &arr = caster.value;
50 const I rows = static_cast<I>(arr.shape(0)),
51 cols = static_cast<I>(arr.shape(1));
52 const I row_stride = static_cast<I>(arr.stride(0)),
53 col_stride = static_cast<I>(arr.stride(1));
54 const I inner_stride = is_column_major ? row_stride : col_stride,
55 outer_stride = is_column_major ? col_stride : row_stride;
56 // Validate inner stride against compile-time expectation
57 if constexpr (has_static_inner_stride) {
58 // For empty arrays, accept any reported stride
59 if (rows > 0 && cols > 0 && inner_stride != S::value)
60 return false;
61 }
62 if constexpr (has_static_inner_stride) {
63 this->value.reassign({{
64 .data = arr.data(),
65 .rows = rows,
66 .cols = cols,
67 .outer_stride = outer_stride,
68 }});
69 } else {
70 this->value.reassign({{
71 .data = arr.data(),
72 .rows = rows,
73 .cols = cols,
74 .inner_stride = inner_stride,
75 .outer_stride = outer_stride,
76 }});
77 }
78 return true;
79 }
80
81 public:
82 bool from_python(handle src, uint8_t flags,
83 cleanup_list *cleanup) noexcept {
84 flags &= ~(uint8_t)cast_flags::accepts_none; // Don't accept None
85 const auto flags_no_convert = flags & ~(uint8_t)cast_flags::convert;
86 if (!std::is_const_v<T> || S{} > 1)
87 // no conversions if mutable or non-unit stride
88 flags = flags_no_convert;
89 // Try without conversions first
90 if (from_python_(caster.template emplace<NDArrayCaster>(), src,
91 flags_no_convert, cleanup))
92 return true;
93 if (flags == flags_no_convert)
94 return false;
95 // Try with conversions enabled
96 return from_python_(caster.template emplace<NDArrayContigCaster>(), src,
97 flags, cleanup);
98 }
99
100 static handle from_cpp(const Value &view, rv_policy policy,
101 cleanup_list *cleanup) noexcept {
102 const size_t shape[2]{static_cast<size_t>(view.rows),
103 static_cast<size_t>(view.cols)};
104 const int64_t strides[2]{static_cast<int64_t>(view.row_stride()),
105 static_cast<int64_t>(view.col_stride())};
106 if (policy == rv_policy::automatic ||
107 policy == rv_policy::automatic_reference)
108 policy = rv_policy::reference;
109 return NDArrayCaster::from_cpp(
110 NDArray(view.data(), 2, shape, handle(), strides), policy, cleanup);
111 }
112};
113
114/// @}
115
116} // namespace nanobind::detail
Non-owning matrix view.
A lightweight view of a 2D matrix.
Definition mat-view.hpp:68
static constexpr bool is_column_major
Definition mat-view.hpp:73
static constexpr bool is_row_major
Definition mat-view.hpp:74
std::conditional_t< is_row_major, c_contig, f_contig > Contig
ndarray< numpy, T, ndim< 2 >, Contig, device::cpu > NDArrayContig
bool from_python_(auto &caster, handle src, uint8_t flags, cleanup_list *cleanup) noexcept
ndarray< numpy, T, ndim< 2 >, device::cpu > NDArray
std::variant< NDArrayCaster, NDArrayContigCaster > caster
bool from_python(handle src, uint8_t flags, cleanup_list *cleanup) noexcept
static handle from_cpp(const Value &view, rv_policy policy, cleanup_list *cleanup) noexcept