1 // -*- C++ -*-
2 /** @file */
3 #pragma once
4
5
6 #include <memory>
7 #include <cstring>
8 #include <algorithm>
9 #include <iostream>
10 #include "common.hpp"
11 #include "arch.hpp"
12 #include <type_traits>
13 #include "number.hpp"
14 #include "forward.hpp"
15 #include "fusion.hpp"
16 #include "unroll.hpp"
17 #include "algorithms.hpp"
18 #include "vec.hpp"
19 #include "matrix_impl.hpp"
20 #include "matrix_view.hpp"
21
22 namespace arm_cmsis_dsp {
23
24 /** \addtogroup Matrix Matrixes
25 * \ingroup DSPPP
26 * @{
27 */
28
29 template<typename P,int R,int C,
30 template<int> typename A>
31 struct traits<Matrix<P,R,C,A>>
32 {
33 typedef P Scalar;
34 #if defined(HAS_VECTOR)
35 typedef typename vector_traits<P>::vector Vector;
36 #endif
37 };
38
39 template<typename P,int S>
40 struct traits<MatrixView<P,S>>
41 {
42 typedef P Scalar;
43 #if defined(HAS_VECTOR)
44 typedef typename vector_traits<P>::vector Vector;
45 #endif
46 };
47
48 template<typename P,int R,int C,
49 template<int> typename A>
50 struct traits<const Matrix<P,R,C,A>&>
51 {
52 typedef P Scalar;
53 #if defined(HAS_VECTOR)
54 typedef typename vector_traits<P>::vector Vector;
55 #endif
56 };
57
58 template<typename P,int S>
59 struct traits<const MatrixView<P,S>&>
60 {
61 typedef P Scalar;
62 #if defined(HAS_VECTOR)
63 typedef typename vector_traits<P>::vector Vector;
64 #endif
65 };
66
67
68 template<typename P,int R,int C,
69 template<int> typename Allocator>
70 struct IsVector<Matrix<P,R,C,Allocator>>
71 {
72 constexpr static bool value = true;
73 };
74
75
76
77 template<typename P,int R,int C,
78 template<int> typename Allocator>
79 struct HasStaticStride<Matrix<P,R,C,Allocator>>
80 {
81 constexpr static bool value = (C>0);
82 };
83
84 template<typename P,int R,int C,
85 template<int> typename Allocator>
86 struct StaticStride<Matrix<P,R,C,Allocator>>
87 {
88 constexpr static index_t value = C;
89 };
90
91 template<typename P,int R,int C,
92 template<int> typename Allocator>
93 struct IsMatrix<Matrix<P,R,C,Allocator>>
94 {
95 constexpr static bool value = true;
96 };
97
98 template<typename P,int R,int C,
99 template<int> typename Allocator>
100 struct HasMatrixIndexing<Matrix<P,R,C,Allocator>>
101 {
102 constexpr static bool value = true;
103 };
104
105 template<typename P,int S>
106 struct IsMatrix<MatrixView<P,S>>
107 {
108 constexpr static bool value = true;
109 };
110
111 template<typename P,int S>
112 struct HasStaticStride<MatrixView<P,S>>
113 {
114 constexpr static bool value = (S>0);
115 };
116
117 template<typename P,int S>
118 struct StaticStride<MatrixView<P,S>>
119 {
120 constexpr static index_t value = S;
121 };
122
123 template<typename P,int S>
124 struct HasMatrixIndexing<MatrixView<P,S>>
125 {
126 constexpr static bool value = true;
127 };
128
129 template<typename P,int R,int C,
130 template<int> typename Allocator>
131 struct IsVector<const Matrix<P,R,C,Allocator>&>
132 {
133 constexpr static bool value = true;
134 };
135
136
137 template<typename P>
138 struct IsVector<MatrixView<P,CONSTRAINED_DYNAMIC>>
139 {
140 constexpr static bool value = true;
141 };
142
143 template<typename P>
144 struct IsVector<const MatrixView<P,CONSTRAINED_DYNAMIC>&>
145 {
146 constexpr static bool value = true;
147 };
148
149 template<typename P,int R,int C,
150 template<int> typename Allocator>
151 struct HasStaticStride<const Matrix<P,R,C,Allocator>&>
152 {
153 constexpr static bool value = (C>0);
154 };
155
156 template<typename P,int R,int C,
157 template<int> typename Allocator>
158 struct StaticStride<const Matrix<P,R,C,Allocator>&>
159 {
160 constexpr static index_t value = C;
161 };
162
163 template<typename P,int R,int C,
164 template<int> typename Allocator>
165 struct HasMatrixIndexing<const Matrix<P,R,C,Allocator>&>
166 {
167 constexpr static bool value = true;
168 };
169
170
171 template<typename P,int S>
172 struct IsMatrix<const MatrixView<P,S>&>
173 {
174 constexpr static bool value = true;
175 };
176
177 template<typename P,int S>
178 struct HasMatrixIndexing<const MatrixView<P,S>&>
179 {
180 constexpr static bool value = true;
181 };
182
183 template<typename P,int S>
184 struct HasStaticStride<const MatrixView<P,S>&>
185 {
186 constexpr static bool value = (S>0);
187 };
188
189 template<typename P,int S>
190 struct StaticStride<const MatrixView<P,S>&>
191 {
192 constexpr static index_t value = S;
193 };
194
195 template<typename P,int R,int C,
196 template<int> typename Allocator>
197 struct ElementType<Matrix<P,R,C,Allocator>>
198 {
199 typedef P type;
200 };
201
202
203 template<typename P,int S>
204 struct ElementType<MatrixView<P,S>>
205 {
206 typedef P type;
207 };
208
209 template<typename P,int R,int C,
210 template<int> typename Allocator>
211 struct ElementType<const Matrix<P,R,C,Allocator>&>
212 {
213 typedef P type;
214 };
215
216 template<typename P,int S>
217 struct ElementType<const MatrixView<P,S>&>
218 {
219 typedef P type;
220 };
221
222 template<typename P,int R,int C,
223 template<int> typename Allocator>
224 struct StaticLength<Matrix<P,R,C,Allocator>>
225 {
226 constexpr static vector_length_t value = (R*C<0) ? 0 : R*C;
227 };
228
229 template<typename P,int S>
230 struct StaticLength<MatrixView<P,S>>
231 {
232 constexpr static vector_length_t value = 0;
233 };
234
235 template<typename P,int R,int C,
236 template<int> typename Allocator>
237 struct StaticLength<const Matrix<P,R,C,Allocator>&>
238 {
239 constexpr static vector_length_t value = (R*C<0) ? 0 : R*C;
240 };
241
242 template<typename P,int S>
243 struct StaticLength<const MatrixView<P,S>&>
244 {
245 constexpr static vector_length_t value = 0 ;
246 };
247
248 template<typename P,int R,int C,
249 template<int> typename Allocator>
250 struct IsDynamic<Matrix<P,R,C,Allocator>>
251 {
252 constexpr static bool value = (R<0) || (C<0);
253 };
254
255 template<typename P,int S>
256 struct IsDynamic<MatrixView<P,S>>
257 {
258 constexpr static bool value = true;
259 };
260
261 template<typename P,int R,int C,
262 template<int> typename Allocator>
263 struct IsDynamic<const Matrix<P,R,C,Allocator>&>
264 {
265 constexpr static bool value = (R<0) || (C<0);
266 };
267
268 template<typename P,int S>
269 struct IsDynamic<const MatrixView<P,S>&>
270 {
271 constexpr static bool value = true;
272 };
273
274 /*
275
276
277 Compatibility of vector and matrix dimensions at build time
278
279 */
280
281 template<typename T>
282 struct NbRows
283 {
284 constexpr static vector_length_t value = DYNAMIC;
285 };
286
287 template<typename P,int R,int C,
288 template<int> typename Allocator>
289 struct NbRows<Matrix<P,R,C,Allocator>>
290 {
291 constexpr static vector_length_t value = R;
292 };
293
294 template<typename P,int R,int C,
295 template<int> typename Allocator>
296 struct NbRows<const Matrix<P,R,C,Allocator>&>
297 {
298 constexpr static vector_length_t value = R;
299 };
300
301 template<typename T>
302 struct NbCols
303 {
304 constexpr static vector_length_t value = DYNAMIC;
305 };
306
307 template<typename P,int R,int C,
308 template<int> typename Allocator>
309 struct NbCols<Matrix<P,R,C,Allocator>>
310 {
311 constexpr static vector_length_t value = C;
312 };
313
314 template<typename P,int R,int C,
315 template<int> typename Allocator>
316 struct NbCols<const Matrix<P,R,C,Allocator>&>
317 {
318 constexpr static vector_length_t value = C;
319 };
320
321
322 template<typename M,typename V>
323 struct CompatibleStaticMatVecProduct
324 {
325 constexpr static bool value =
326 is_only_vector<V>() &&
327 HasMatrixIndexing<M>::value &&
328 (NbCols<M>::value == StaticLength<V>::value) &&
329 !IsDynamic<M>::value
330 && SameElementType<M,V>::value;
331
332 };
333
334 /* MB IsMatrix because we need transpose operator */
335 template<typename MA,typename MB>
336 struct CompatibleStaticMatMatProduct
337 {
338 constexpr static bool value =
339 HasMatrixIndexing<MA>::value &&
340 IsMatrix<MB>::value &&
341 (NbCols<MA>::value == NbRows<MB>::value) &&
342 !IsDynamic<MA>::value &&
343 SameElementType<MA,MB>::value;
344
345 };
346
347 template<typename M,typename V>
348 struct CompatibleDynamicMatVecProduct
349 {
350 constexpr static bool value =
351 HasMatrixIndexing<M>::value &&
352 IsDynamic<M>::value &&
353 is_only_vector<V>() &&
354 SameElementType<M,V>::value;
355
356 };
357
358 /* MB IsMatrix because we need transpose operator */
359 template<typename MA,typename MB>
360 struct CompatibleDynamicMatMatProductStaticStride
361 {
362 constexpr static bool value =
363 HasMatrixIndexing<MA>::value &&
364 IsMatrix<MB>::value &&
365 IsDynamic<MA>::value &&
366 HasStaticStride<MB>::value &&
367 SameElementType<MA,MB>::value;
368 };
369
370 template<typename MA,typename MB>
371 struct CompatibleDynamicMatMatProductDynamicStride
372 {
373 constexpr static bool value =
374 HasMatrixIndexing<MA>::value &&
375 IsMatrix<MB>::value &&
376 IsDynamic<MA>::value &&
377 !HasStaticStride<MB>::value &&
378 SameElementType<MA,MB>::value;
379 };
380
381 template<typename MA,typename MB>
382 struct CompatibleDynamicMatMatProduct
383 {
384 constexpr static bool value =
385 HasMatrixIndexing<MA>::value &&
386 IsMatrix<MB>::value &&
387 IsDynamic<MA>::value &&
388 SameElementType<MA,MB>::value;
389 };
390
391 template<typename M,typename V>
392 struct OutputVector {
393 typedef Vector<typename traits<V>::Scalar,
394 OutputVectorDim<M>::value,TMP_ALLOC> type;
395 };
396
397 template<typename MA,typename MB>
398 struct OutputMatrix {
399 constexpr static bool dynamic = (NbRows<MA>::value < 0) || (NbCols<MB>::value < 0);
400 constexpr static vector_length_t nbrows = dynamic ? DYNAMIC : NbRows<MA>::value;
401 constexpr static vector_length_t nbcols = dynamic ? DYNAMIC : NbCols<MB>::value;
402
403 typedef Matrix<typename traits<MA>::Scalar,nbrows,nbcols,TMP_ALLOC> type;
404 };
405
406
407
408 template<typename M>
409 struct OutputVectorDim
410 {
411 constexpr static vector_length_t value = DYNAMIC;
412 };
413
414 template<typename P,int R,int C,
415 template<int> typename Allocator>
416 struct OutputVectorDim<Matrix<P,R,C,Allocator>>
417 {
418 constexpr static vector_length_t value = R;
419 };
420
421 template<typename P,int R,int C,
422 template<int> typename Allocator>
423 struct OutputVectorDim<const Matrix<P,R,C,Allocator>&>
424 {
425 constexpr static vector_length_t value = R;
426 };
427
428
429 template<typename T,int S>
430 struct VecRef<MatrixView<T,S>>
431 {
432 typedef MatrixView<T,S> type;
refarm_cmsis_dsp::VecRef433 static type ref(const MatrixView<T,S>&a){
434 return(a);
435 };
436 };
437
438 template<typename P,int R,int C,
439 template<int> typename A>
440 struct VecRef<Matrix<P,R,C,A>,((R>0) && (C>0))>
441 {
442 typedef const Matrix<P,R,C,A>& type;
refarm_cmsis_dsp::VecRef443 static type ref(const Matrix<P,R,C,A>&a,typename std::enable_if<(R>0) && (C>0)>::type* = nullptr){
444 return(a);
445 };
446 };
447
448 template<typename P,int R,int C,
449 template<int> typename A>
450 struct VecRef<Matrix<P,R,C,A>,((R<0) || (C<0))>
451 {
452 typedef MatrixView<P,CONSTRAINED_DYNAMIC> type;
refarm_cmsis_dsp::VecRef453 static type ref(const Matrix<P,R,C,A>&a,typename std::enable_if<(R<0) || (C<0)>::type* = nullptr){
454 return(type(a,a.rows(),a.columns()));
455 };
456 };
457
458
459 /*****************
460 *
461 *
462 * Fused matrix operators
463 *
464 ****************/
465
466 /**
467 * @brief Outer product operator for expressions
468 *
469 * @tparam LHS Left hand side datatype
470 * @tparam RHS Right hand side datatype
471 * @tparam DerivedOp Operator for the Outer operation
472 *
473 * vector `op` vector (including matrix)
474 */
475 template<typename LHS,typename RHS,typename DerivedOp>
476 struct _Outer: _Expr<_Outer<LHS,RHS,DerivedOp>>
477 {
478 //! Type of vector elements
479 using Scalar = typename traits<LHS>::Scalar;
480 #if defined(HAS_VECTOR)
481 //! Type of vector in the architecture
482 using Vector = typename traits<LHS>::Vector;
483 #endif
484 /**
485 * @brief Create an Outer operator
486 *
487 * @param lhs Left hand side expression
488 * @param rhs Right hand side expression
489 * @param op operator
490 */
_Outerarm_cmsis_dsp::_Outer491 _Outer(const LHS &lhs,
492 const RHS &rhs,
493 const _BinaryOperator<Scalar,DerivedOp> &op):
494 lhs_(lhs),rhs_(rhs),op_(op){
495 }
496
497 /**
498 * @brief Create an Outer operator from another operator of same type
499 *
500 * @param other the other operator
501 */
_Outerarm_cmsis_dsp::_Outer502 _Outer(const _Outer &other):
503 lhs_(other.lhs_),rhs_(other.rhs_),op_(other.op_){
504 }
505
506 _Outer& operator=(const _Outer& other) = delete;
507 _Outer& operator=(_Outer&& other) = delete;
508
509 /**
510 * @brief Move semantic for _Outer operator
511 *
512 * @param other the other operator
513 */
_Outerarm_cmsis_dsp::_Outer514 _Outer(_Outer &&other):
515 lhs_(std::move(other.lhs_)),rhs_(std::move(other.rhs_)),op_(std::move(other.op_))
516 {
517 }
518
519
520
521 /**
522 * @brief Length of the matrix (seen as vector) resulting from the outer operator
523 * @tparam R Right hand side datatype
524 * @tparam L Left hand side datatype
525 *
526 * @return vector dimension
527 */
528 template<typename R=RHS, typename L=LHS,
529 typename std::enable_if<IsVector<L>::value && IsVector<R>::value,bool>::type = true>
lengtharm_cmsis_dsp::_Outer530 vector_length_t length() const {
531 return(lhs_.length() * rhs_.length());
532 }
533
534 /**
535 * @brief Rows of the matrix
536 * @tparam R Right hand side datatype
537 * @tparam L Left hand side datatype
538 *
539 * @return number of rows
540 */
541 template<typename R=RHS, typename L=LHS,
542 typename std::enable_if<IsVector<L>::value,bool>::type = true>
rowsarm_cmsis_dsp::_Outer543 vector_length_t rows() const {
544 return(lhs_.length());
545 }
546
547
548 /**
549 * @brief Columns of the matrix
550 * @tparam R Right hand side datatype
551 * @tparam L Left hand side datatype
552 *
553 * @return number of columns
554 */
555 template<typename R=RHS, typename L=LHS,
556 typename std::enable_if<IsVector<R>::value,bool>::type = true>
columnsarm_cmsis_dsp::_Outer557 vector_length_t columns() const {
558 return(rhs_.length());
559 }
560
561
562 /**
563 * @brief Expression value at given position
564 * @tparam R Right hand side datatype
565 * @tparam L Left hand side datatype
566 * @param r row index
567 * @param c column index
568 *
569 * @return expression value
570 */
571 template<typename R=RHS, typename L=LHS,
572 typename std::enable_if<IsVector<L>::value &&
573 IsVector<R>::value,bool>::type = true>
operator ()arm_cmsis_dsp::_Outer574 Scalar const operator()(const index_t r,const index_t c) const
575 {
576 return(op_(lhs_[r],rhs_[c]));
577 }
578
579
580 #if defined(HAS_VECTOR)
581 /*
582 *
583 * For matrix
584 *
585 */
586
587 /* V + V */
588
589 /**
590 * @brief Expression vector value at given position
591 * @tparam R Right hand side datatype
592 * @tparam L Left hand side datatype
593 * @param r row index
594 * @param c column index
595 *
596 * @return expression vector value
597 *
598 * Vector + Vector (matrix interpreted as a Vector)
599 */
600 template<typename R=RHS, typename L=LHS,
601 typename std::enable_if<IsVector<L>::value &&
602 IsVector<R>::value,bool>::type = true>
matrix_oparm_cmsis_dsp::_Outer603 Vector const matrix_op(const index_t r,const index_t c) const
604 {
605 return(op_(lhs_[r],rhs_.vector_op(c)));
606 }
607
608 /**
609 * @brief Expression vector value at given position with tail predication
610 * @tparam R Right hand side datatype
611 * @tparam L Left hand side datatype
612 * @param r row index
613 * @param c column index
614 * @param remaining remaining number of samples in loop
615 *
616 * @return expression vector value
617 *
618 * Vector + Vector (matrix interpreted as a Vector)
619 */
620 template<typename R=RHS, typename L=LHS,
621 typename std::enable_if<IsVector<L>::value &&
622 IsVector<R>::value,bool>::type = true>
matrix_op_tailarm_cmsis_dsp::_Outer623 Vector const matrix_op_tail(const index_t r,const index_t c,const vector_length_t remaining) const
624 {
625 return(op_(lhs_[r],rhs_.vector_op_tail(c,remaining),inner::vctpq<Scalar>::mk(remaining)));
626 }
627
628
629 #endif
630 const LHS lhs_;
631 const RHS rhs_;
632 const _BinaryOperator<Scalar,DerivedOp> op_;
633 };
634
635 template<typename LHS,typename RHS,typename DerivedOp>
636 struct IsVector<_Outer<LHS,RHS,DerivedOp>>
637 {
638 constexpr static bool value = false;
639 };
640
641 template<typename LHS,typename RHS,typename DerivedOp>
642 struct HasMatrixIndexing<_Outer<LHS,RHS,DerivedOp>>
643 {
644 constexpr static bool value = true;
645 };
646
647 template<typename LHS,typename RHS,typename DerivedOp>
648 struct StaticLength<_Outer<LHS,RHS,DerivedOp>>
649 {
650 constexpr static vector_length_t value = StaticLength<LHS>::value * StaticLength<RHS>::value;
651 };
652
653 template<typename LHS,typename RHS,typename DerivedOp>
654 struct IsDynamic<_Outer<LHS,RHS,DerivedOp>>
655 {
656 constexpr static vector_length_t value = IsDynamic<LHS>::value || IsDynamic<RHS>::value;
657 };
658
659 template<typename LHS,typename RHS,typename DerivedOp>
660 struct Complexity<_Outer<LHS,RHS,DerivedOp>>
661 {
662 constexpr static int lhsv = Complexity<LHS>::value;
663 constexpr static int rhsv = Complexity<RHS>::value;
664 constexpr static int value = lhsv + rhsv + 1;
665 };
666
667 template<typename LHS,typename RHS,typename DerivedOp>
668 struct ElementType<_Outer<LHS,RHS,DerivedOp>>
669 {
670 typedef typename ElementType<LHS>::type type;
671 };
672
673 template<typename LHS,typename RHS,typename DerivedOp>
674 struct traits<_Outer<LHS,RHS,DerivedOp>>
675 {
676 typedef typename traits<LHS>::Scalar Scalar;
677 #if defined(HAS_VECTOR)
678 typedef typename traits<LHS>::Vector Vector;
679 #endif
680 };
681
682 template<typename LHS,typename RHS,typename OP>
683 struct VecRef<_Outer<LHS,RHS,OP>>
684 {
685 typedef _Outer<LHS,RHS,OP> type;
refarm_cmsis_dsp::VecRef686 static type ref(const _Outer<LHS,RHS,OP>&a){
687 return(a);
688 };
689 };
690
691 template<typename LHS,typename RHS,typename OP>
692 struct NbRows<_Outer<LHS,RHS,OP>>
693 {
694 constexpr static vector_length_t value = NbRows<LHS>::value;
695 };
696
697
698 template<typename LHS,typename RHS,typename OP>
699 struct NbCols<_Outer<LHS,RHS,OP>>
700 {
701 constexpr static vector_length_t value = NbCols<RHS>::value;
702 };
703
704
705 /**
706 * @brief Outer product
707 * @tparam VA Right hand side datatype
708 * @tparam VB Left hand side datatype
709 * @param a Vector a
710 * @param b Vector b
711 *
712 * @return Outer product of a and b
713 *
714 */
715 template<typename VA,typename VB,
716 typename std::enable_if<vector_idx_pair<VA,VB>(),bool>::type = true>
outer(const VA & a,const VB & b)717 inline auto outer(const VA&a,const VB&b)
718 {
719 //constexpr int NBROWS = StaticLength<VA>::value;
720 //constexpr int NBCOLS = StaticLength<VB>::value;
721
722 //using T = typename traits<VA>::Scalar;
723
724 //Matrix<T,NBROWS,NBCOLS,TMP_ALLOC> res;
725 //_outer(res,a,b);
726 using Scalar = typename traits<VA>::Scalar;
727 using VecLHS = VecRef<VA>;
728 using VecRHS = VecRef<VB>;
729
730 return(_Outer<typename VecLHS::type,typename VecRHS::type,_MulOp<Scalar>>(VecLHS::ref(a),VecRHS::ref(b),_MulOp<Scalar>()));
731
732
733 }
734
735 /*! @} */
736 }
737