-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmatrix.hpp
205 lines (156 loc) · 6.6 KB
/
matrix.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#ifndef MATRIX_HPP
#define MATRIX_HPP
#include <memory>
#include <algorithm>
#include "common.hpp"
namespace matrix {
using idx_t = int; // Signed indices allows better loop optimizations
struct slice {
idx_t offset;
idx_t size;
};
struct strided_slice {
idx_t offset;
idx_t size;
idx_t stride;
};
template<typename T> struct slicevec;
/// Reference to a subarray
template<typename T>
struct refvec {
using idx_t = int;
using scalar_t = T;
using ref_t = scalar_t&;
using const_ref_t = scalar_t&; // Constness is contained in T if needed
using iterator = scalar_t*;
using const_iterator = scalar_t*;
refvec(scalar_t* data ,idx_t size) : _data(data), _size(size) {}
refvec(refvec&&) = default;
refvec(const refvec&) = default;
scalar_t* data() const { return _data; }
iterator begin() const { return _data; }
iterator end() const { return _data + _size; }
ref_t operator[](idx_t i) const {
assume(i >= 0, "negative indice");
assume(i < _size, "out of bound indice");
return _data[i];
}
refvec<T> operator[](slice s) {
assume(s.offset >= 0, "negative offset");
assume(s.offset + s.size <= _size, "Out of bound slice");
return refvec<T>(_data + s.offset, s.size);
}
slicevec<T> operator[](strided_slice s) {
assume(s.offset >= 0, "negative offset");
idx_t min = s.offset;
idx_t max = s.offset + (s.size-1)*s.stride;
assume(min >= 0 && min < _size && max >= 0 && max < _size, "Slice out of bound");
return slicevec<T>(_data, s);
}
idx_t size() const { return _size; }
scalar_t* _data;
idx_t _size;
};
/// Reference to a subarray with strides
template<typename T>
struct slicevec : protected refvec<T> {
using scalar_t = T;
using ref_t = scalar_t&;
using refvec<T>::size;
// Refereced memory size: this->_size * this->_stride
slicevec(scalar_t* data , strided_slice s) : refvec<T>(data + s.offset, s.size), _stride(s.stride) {}
slicevec(slicevec&&) = default;
slicevec(const slicevec&) = default;
idx_t stride() const { return _stride; }
ref_t operator[](idx_t i) const {
assume(i >= 0, "negative indice");
assume(i < this->_size, "out of bound indice");
return this->_data[i*_stride];
}
slicevec<T> operator[](slice s) {
assume(s.offset >= 0, "negative offset");
assume(s.offset + s.size <= this->_size, "Out of bound slice");
return slicevec<T>(this->_data, {s.offset * _stride, s.size, _stride});
}
slicevec<T> operator[](strided_slice s) {
assume(s.offset >= 0, "negative offset");
idx_t min = s.offset;
idx_t max = s.offset + (s.size-1)*s.stride;
assume(min >= 0 && min < this->_size && max >= 0 && max < this->_size, "Slice out of bound");
return slicevec<T>(this->_data, {s.offset * _stride, s.size, s.stride * _stride});
}
struct iterator {
scalar_t* ptr;
idx_t stride;
iterator& operator++() { ptr += stride; return *this; }
bool operator<(const iterator& other) { return ptr < other.ptr; }
bool operator!=(const iterator& other) { return ptr != other.ptr; }
ref_t operator*() const { return *ptr; }
};
using const_iterator = iterator;
iterator begin() const { return {this->data(), _stride}; }
iterator end() const { return {this->data() + this->size() * _stride, _stride}; }
idx_t _stride;
};
/// Own a memory range of T values
template<typename T>
struct vector {
using idx_t = int;
using scalar_t = T;
using ref_t = scalar_t&;
using const_ref_t = const scalar_t&;
using iterator = scalar_t*;
using const_iterator = const scalar_t*;
using unique_arr_t = std::unique_ptr<scalar_t[]>;
typedef scalar_t (&array_ref)[];
typedef const scalar_t (&const_array_ref)[];
vector(idx_t size) : _data(new scalar_t[size_t(size)]), _size(size) {}
vector(idx_t size, scalar_t v) : _data(new scalar_t[size_t(size)]{v}), _size(size) {}
vector(unique_arr_t&& data, idx_t size) : _data(std::move(data)), _size(size) {}
vector(iterator* data, idx_t size) : vector(size) {
std::copy(data, data + _size);
}
vector(vector&&) = default;
vector& operator=(vector&&) = default;
explicit vector(const vector& from) : vector(from._data.get(), from._size) {}
array_ref data() { return _data.get(); }
const_array_ref data() const { return _data.get(); }
idx_t size() const {return _size; }
unique_arr_t as_unique_ptr() && {
return std::move(_data);
}
operator refvec<T>() { return {_data.get(), _size}; }
operator refvec<const T>() const { return {_data.get(), _size}; }
template<typename I> auto operator[](I i) -> decltype(this->operator refvec<T>()[i])
{ return this->operator refvec<T>()[i]; }
template<typename I> auto operator[](I i) const -> decltype(this->operator refvec<const T>()[i])
{ return *this->operator refvec<const T>()[i]; }
iterator begin() { return _data.get(); }
iterator end() { return _data.get() + _size; }
const_iterator begin() const { return _data.get(); }
const_iterator end() const { return _data.get() + _size; }
unique_arr_t _data;
idx_t _size;
};
template<typename base>
struct matrix_t : public base {
using typename base::idx_t;
using typename base::scalar_t;
matrix_t(idx_t r, idx_t c) : base(r*c), _rows(r), _cols(c) {}
matrix_t(idx_t r, idx_t c, scalar_t v) : base(r*c, v), _rows(r), _cols(c) {}
// template<typename T, typename=decltype(base(std::declval<T>()), idx_t{})>
// matrix(T&& x, idx_t r, idx_t c) : base(std::forward<T>(x), r * c), _rows(r), _cols(c) {}
idx_t cols() const { return _cols; }
idx_t rows() const { return this->size() / _cols; }
auto row(idx_t i) -> decltype((*this)[slice{}]) { return (*this)[slice{_cols * i, _cols}]; }
auto row(idx_t i) const -> decltype((*this)[slice{}]) { return (*this)[slice{_cols * i, _cols}]; }
auto col(idx_t i) -> decltype((*this)[strided_slice{}]) { return (*this)[strided_slice{i, _rows, _cols}]; }
auto col(idx_t i) const -> decltype((*this)[strided_slice{}]) { return (*this)[strided_slice{i, _rows, _cols}]; }
auto operator() (idx_t r, idx_t c) -> decltype((*this)[idx_t{}]) { return static_cast<refvec<scalar_t>>(*this)[r*_cols + c]; }
auto operator() (idx_t r, idx_t c) const -> decltype((*this)[idx_t{}]) { return this[r*_cols + c]; }
idx_t _rows, _cols;
};
template<typename T> using matrix = matrix_t<vector<T>>;
template<typename T> using matrix_ref = matrix_t<refvec<T>>;
} /* namespace matrix */
#endif // MATRIX_HPP