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