18
19
20
24#include "./concepts.hpp"
25#include "./declarations.hpp"
26#include "./linalg/matmul.hpp"
27#include "./linalg/det_and_inverse.hpp"
28#include "./macros.hpp"
29#include "./stdutil/complex.hpp"
30#include "./traits.hpp"
36#ifdef NDA_ENFORCE_BOUNDCHECK
37#include "./exceptions.hpp"
43
44
45
48
49
50
51
52
53
54
55
56
57
58 template <
char OP, Array A>
60 static_assert(OP ==
'-',
"Error in nda::expr_unary: Only negation is supported");
66
67
68
69
70
71
72
73
74
75 template <
typename... Args>
77 return -
a(std::forward<Args>(args)...
);
81
82
83
87
88
89
94
95
96
97
98
99
100
101
102
103
104
105 template <
char OP, ArrayOrScalar L, ArrayOrScalar R>
114 using L_t = std::decay_t<L>;
117 using R_t = std::decay_t<R>;
130
131
132
136 return get_layout_info<R> & get_layout_info<L>;
140
141
142
149 EXPECTS(l.shape() == r.shape());
155
156
157
170
171
172
173
174
175
176
177
178
179 template <
typename... Args>
182 if constexpr (OP ==
'+') {
187 return (std::equal_to{}(args...) ?
l +
r(args...
) :
r(args...
));
190 return l +
r(args...
);
195 return (std::equal_to{}(args...) ?
l(args...
) +
r :
l(args...
));
198 return l(args...
) +
r;
201 return l(args...
) +
r(args...
);
205 if constexpr (OP ==
'-') {
210 return (std::equal_to{}(args...) ?
l -
r(args...
) : -
r(args...
));
213 return l -
r(args...
);
218 return (std::equal_to{}(args...) ?
l(args...
) -
r :
l(args...
));
221 return l(args...
) -
r;
224 return l(args...
) -
r(args...
);
228 if constexpr (OP ==
'*') {
231 return l *
r(args...
);
234 return l(args...
) *
r;
237 static_assert(
algebra !=
'M',
"Error in nda::expr: Matrix algebra not supported");
238 return l(args...
) *
r(args...
);
243 if constexpr (OP ==
'/') {
246 static_assert(
algebra !=
'M',
"Error in nda::expr: Matrix algebra not supported");
247 return l /
r(args...
);
250 return l(args...
) /
r;
253 static_assert(
algebra !=
'M',
"Error in nda::expr: Matrix algebra not supported");
254 return l(args...
) /
r(args...
);
260
261
262
263
264
265
266
267
268 template <
typename Arg>
270 static_assert(get_rank<
expr> == 1,
"Error in nda::expr: Subscript operator only available for expressions of rank 1");
271 return operator()(std::forward<Arg>(arg));
276
277
278
279
280
281
282
283
286 return {std::forward<A>(a)};
290
291
292
293
294
295
296
297
298
299
300 template <Array L, Array R>
302 static_assert(get_rank<L> == get_rank<R>,
"Error in lazy nda::operator+: Rank mismatch");
303 return expr<
'+', L, R>{std::forward<L>(l), std::forward<R>(r)};
307
308
309
310
311
312
313
314
315
316
317
318
319 template <Array A, Scalar S>
321 return expr<
'+', A, std::decay_t<S>>{std::forward<A>(a), s};
325
326
327
328
329
330
331
332
333
334
335
336
337 template <Scalar S, Array A>
339 return expr<
'+', std::decay_t<S>, A>{s, std::forward<A>(a)};
343
344
345
346
347
348
349
350
351
352
353 template <Array L, Array R>
355 static_assert(get_rank<L> == get_rank<R>,
"Error in lazy nda::operator-: Rank mismatch");
356 return expr<
'-', L, R>{std::forward<L>(l), std::forward<R>(r)};
360
361
362
363
364
365
366
367
368
369
370
371
372 template <Array A, Scalar S>
374 return expr<
'-', A, std::decay_t<S>>{std::forward<A>(a), s};
378
379
380
381
382
383
384
385
386
387
388
389
390 template <Scalar S, Array A>
392 return expr<
'-', std::decay_t<S>, A>{s, std::forward<A>(a)};
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412 template <Array L, Array R>
415 static constexpr char l_algebra = get_algebra<L>;
416 static constexpr char r_algebra = get_algebra<R>;
417 static_assert(l_algebra !=
'V',
"Error in nda::operator*: Can not multiply vector by an array or a matrix");
420 if constexpr (l_algebra ==
'A') {
421 static_assert(r_algebra ==
'A',
"Error in nda::operator*: Both types need to be arrays");
422 static_assert(get_rank<L> == get_rank<R>,
"Error in nda::operator*: Rank mismatch");
423#ifdef NDA_ENFORCE_BOUNDCHECK
424 if (l.shape() != r.shape()) NDA_RUNTIME_ERROR <<
"Error in nda::operator*: Dimension mismatch: " << l.shape() <<
" != " << r.shape();
426 return expr<
'*', L, R>{std::forward<L>(l), std::forward<R>(r)};
430 if constexpr (l_algebra ==
'M') {
431 static_assert(r_algebra !=
'A',
"Error in nda::operator*: Can not multiply a matrix by an array");
432 if constexpr (r_algebra ==
'M')
434 return matmul(std::forward<L>(l), std::forward<R>(r));
437 return matvecmul(std::forward<L>(l), std::forward<R>(r));
442
443
444
445
446
447
448
449
450
451
452 template <Array A, Scalar S>
454 return expr<
'*', A, std::decay_t<S>>{std::forward<A>(a), s};
458
459
460
461
462
463
464
465
466
467
468 template <Scalar S, Array A>
470 return expr<
'*', std::decay_t<S>, A>{s, std::forward<A>(a)};
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489 template <Array L, Array R>
492 static constexpr char l_algebra = get_algebra<L>;
493 static constexpr char r_algebra = get_algebra<R>;
494 static_assert(l_algebra !=
'V',
"Error in nda::operator/: Can not divide a vector by an array or a matrix");
497 if constexpr (l_algebra ==
'A') {
498 static_assert(r_algebra ==
'A',
"Error in nda::operator/: Both types need to be arrays");
499 static_assert(get_rank<L> == get_rank<R>,
"Error in nda::operator/: Rank mismatch");
500#ifdef NDA_ENFORCE_BOUNDCHECK
501 if (l.shape() != r.shape()) NDA_RUNTIME_ERROR <<
"Error in nda::operator/: Dimension mismatch: " << l.shape() <<
" != " << r.shape();
503 return expr<
'/', L, R>{std::forward<L>(l), std::forward<R>(r)};
507 if constexpr (l_algebra ==
'M') {
508 static_assert(r_algebra ==
'M',
"Error in nda::operator*: Can not divide a matrix by an array/vector");
509 return std::forward<L>(l) * inverse(matrix<get_value_t<R>>{std::forward<R>(r)});
514
515
516
517
518
519
520
521
522
523
524 template <Array A, Scalar S>
526 return expr<
'/', A, std::decay_t<S>>{std::forward<A>(a), s};
530
531
532
533
534
535
536
537
538
539
540
541
542 template <Scalar S, Array A>
544 static constexpr char algebra = get_algebra<A>;
545 if constexpr (algebra ==
'M')
546 return s * inverse(matrix<get_value_t<A>>{std::forward<A>(a)});
548 return expr<
'/', std::decay_t<S>, A>{s, std::forward<A>(a)};
Array auto operator-(L &&l, R &&r)
Subtraction operator for two nda::Array types.
Array auto operator+(L &&l, R &&r)
Addition operator for two nda::Array types.
Array auto operator/(L &&l, R &&r)
Division operator for two nda::Array types.
auto operator*(L &&l, R &&r)
Multiplication operator for two nda::Array types.
expr_unary<'-', A > operator-(A &&a)
Unary minus operator for nda::Array types.
Lazy unary expression for nda::Array types.
auto operator()(Args &&...args) const
Function call operator.
constexpr long size() const
Get the total size of the nda::Array operand.
constexpr auto shape() const
Get the shape of the nda::Array operand.
Lazy binary expression for nda::ArrayOrScalar types.
L l
nda::ArrayOrScalar left hand side operand.
constexpr long size() const
Get the total size of the expression (result of the operation).
static constexpr bool r_is_scalar
Constexpr variable that is true if the right hand side operand is a scalar.
constexpr decltype(auto) shape() const
Get the shape of the expression (result of the operation).
auto operator[](Arg &&arg) const
Subscript operator.
static constexpr layout_info_t compute_layout_info()
Compute the layout information of the expression.
static constexpr char algebra
Constexpr variable specifying the algebra of one of the non-scalar operands.
R r
nda::ArrayOrScalar right hand side operand.
auto operator()(Args const &...args) const
Function call operator.
static constexpr bool l_is_scalar
Constexpr variable that is true if the left hand side operand is a scalar.
Stores information about the memory layout and the stride order of an array/view.