1 // SPDX-License-Identifier: Apache-2.0
2 //
3 // Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au)
4 // Copyright 2008-2016 National ICT Australia (NICTA)
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License");
7 // you may not use this file except in compliance with the License.
8 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 // ------------------------------------------------------------------------
17 
18 
19 //! \addtogroup operator_times
20 //! @{
21 
22 
23 
24 //! Base * scalar
25 template<typename T1>
26 arma_inline
27 typename enable_if2< is_arma_type<T1>::value, const eOp<T1, eop_scalar_times> >::result
operator *(const T1 & X,const typename T1::elem_type k)28 operator*
29 (const T1& X, const typename T1::elem_type k)
30   {
31   arma_extra_debug_sigprint();
32 
33   return eOp<T1, eop_scalar_times>(X,k);
34   }
35 
36 
37 
38 //! scalar * Base
39 template<typename T1>
40 arma_inline
41 typename enable_if2< is_arma_type<T1>::value, const eOp<T1, eop_scalar_times> >::result
operator *(const typename T1::elem_type k,const T1 & X)42 operator*
43 (const typename T1::elem_type k, const T1& X)
44   {
45   arma_extra_debug_sigprint();
46 
47   return eOp<T1, eop_scalar_times>(X,k);  // NOTE: order is swapped
48   }
49 
50 
51 
52 //! non-complex Base * complex scalar
53 template<typename T1>
54 arma_inline
55 typename
56 enable_if2
57   <
58   (is_arma_type<T1>::value && is_cx<typename T1::elem_type>::no),
59   const mtOp<typename std::complex<typename T1::pod_type>, T1, op_cx_scalar_times>
60   >::result
operator *(const T1 & X,const std::complex<typename T1::pod_type> & k)61 operator*
62   (
63   const T1&                                  X,
64   const std::complex<typename T1::pod_type>& k
65   )
66   {
67   arma_extra_debug_sigprint();
68 
69   return mtOp<typename std::complex<typename T1::pod_type>, T1, op_cx_scalar_times>('j', X, k);
70   }
71 
72 
73 
74 //! complex scalar * non-complex Base
75 template<typename T1>
76 arma_inline
77 typename
78 enable_if2
79   <
80   (is_arma_type<T1>::value && is_cx<typename T1::elem_type>::no),
81   const mtOp<typename std::complex<typename T1::pod_type>, T1, op_cx_scalar_times>
82   >::result
operator *(const std::complex<typename T1::pod_type> & k,const T1 & X)83 operator*
84   (
85   const std::complex<typename T1::pod_type>& k,
86   const T1&                                  X
87   )
88   {
89   arma_extra_debug_sigprint();
90 
91   return mtOp<typename std::complex<typename T1::pod_type>, T1, op_cx_scalar_times>('j', X, k);
92   }
93 
94 
95 
96 //! scalar * trans(T1)
97 template<typename T1>
98 arma_inline
99 const Op<T1, op_htrans2>
operator *(const typename T1::elem_type k,const Op<T1,op_htrans> & X)100 operator*
101 (const typename T1::elem_type k, const Op<T1, op_htrans>& X)
102   {
103   arma_extra_debug_sigprint();
104 
105   return Op<T1, op_htrans2>(X.m, k);
106   }
107 
108 
109 
110 //! trans(T1) * scalar
111 template<typename T1>
112 arma_inline
113 const Op<T1, op_htrans2>
operator *(const Op<T1,op_htrans> & X,const typename T1::elem_type k)114 operator*
115 (const Op<T1, op_htrans>& X, const typename T1::elem_type k)
116   {
117   arma_extra_debug_sigprint();
118 
119   return Op<T1, op_htrans2>(X.m, k);
120   }
121 
122 
123 
124 //! Base * diagmat
125 template<typename T1, typename T2>
126 arma_inline
127 typename
128 enable_if2
129   <
130   (is_arma_type<T1>::value && is_same_type<typename T1::elem_type, typename T2::elem_type>::value),
131   const Glue<T1, Op<T2, op_diagmat>, glue_times_diag>
132   >::result
operator *(const T1 & X,const Op<T2,op_diagmat> & Y)133 operator*
134 (const T1& X, const Op<T2, op_diagmat>& Y)
135   {
136   arma_extra_debug_sigprint();
137 
138   return Glue<T1, Op<T2, op_diagmat>, glue_times_diag>(X, Y);
139   }
140 
141 
142 
143 //! diagmat * Base
144 template<typename T1, typename T2>
145 arma_inline
146 typename
147 enable_if2
148   <
149   (is_arma_type<T2>::value && is_same_type<typename T1::elem_type, typename T2::elem_type>::value),
150   const Glue<Op<T1, op_diagmat>, T2, glue_times_diag>
151   >::result
operator *(const Op<T1,op_diagmat> & X,const T2 & Y)152 operator*
153 (const Op<T1, op_diagmat>& X, const T2& Y)
154   {
155   arma_extra_debug_sigprint();
156 
157   return Glue<Op<T1, op_diagmat>, T2, glue_times_diag>(X, Y);
158   }
159 
160 
161 
162 //! diagmat * diagmat
163 template<typename T1, typename T2>
164 inline
165 Mat< typename promote_type<typename T1::elem_type, typename T2::elem_type>::result >
operator *(const Op<T1,op_diagmat> & X,const Op<T2,op_diagmat> & Y)166 operator*
167 (const Op<T1, op_diagmat>& X, const Op<T2, op_diagmat>& Y)
168   {
169   arma_extra_debug_sigprint();
170 
171   typedef typename T1::elem_type eT1;
172   typedef typename T2::elem_type eT2;
173 
174   typedef typename promote_type<eT1,eT2>::result out_eT;
175 
176   promote_type<eT1,eT2>::check();
177 
178   const diagmat_proxy<T1> A(X.m);
179   const diagmat_proxy<T2> B(Y.m);
180 
181   arma_debug_assert_mul_size(A.n_rows, A.n_cols, B.n_rows, B.n_cols, "matrix multiplication");
182 
183   Mat<out_eT> out(A.n_rows, B.n_cols, arma_zeros_indicator());
184 
185   const uword A_length = (std::min)(A.n_rows, A.n_cols);
186   const uword B_length = (std::min)(B.n_rows, B.n_cols);
187 
188   const uword N = (std::min)(A_length, B_length);
189 
190   for(uword i=0; i<N; ++i)
191     {
192     out.at(i,i) = upgrade_val<eT1,eT2>::apply( A[i] ) * upgrade_val<eT1,eT2>::apply( B[i] );
193     }
194 
195   return out;
196   }
197 
198 
199 
200 //! multiplication of Base objects with same element type
201 template<typename T1, typename T2>
202 arma_inline
203 typename
204 enable_if2
205   <
206   is_arma_type<T1>::value && is_arma_type<T2>::value && is_same_type<typename T1::elem_type, typename T2::elem_type>::value,
207   const Glue<T1, T2, glue_times>
208   >::result
operator *(const T1 & X,const T2 & Y)209 operator*
210 (const T1& X, const T2& Y)
211   {
212   arma_extra_debug_sigprint();
213 
214   return Glue<T1, T2, glue_times>(X, Y);
215   }
216 
217 
218 
219 //! multiplication of Base objects with different element types
220 template<typename T1, typename T2>
221 inline
222 typename
223 enable_if2
224   <
225   (is_arma_type<T1>::value && is_arma_type<T2>::value && (is_same_type<typename T1::elem_type, typename T2::elem_type>::no)),
226   const mtGlue< typename promote_type<typename T1::elem_type, typename T2::elem_type>::result, T1, T2, glue_mixed_times >
227   >::result
operator *(const T1 & X,const T2 & Y)228 operator*
229   (
230   const T1& X,
231   const T2& Y
232   )
233   {
234   arma_extra_debug_sigprint();
235 
236   typedef typename T1::elem_type eT1;
237   typedef typename T2::elem_type eT2;
238 
239   typedef typename promote_type<eT1,eT2>::result out_eT;
240 
241   promote_type<eT1,eT2>::check();
242 
243   return mtGlue<out_eT, T1, T2, glue_mixed_times>( X, Y );
244   }
245 
246 
247 
248 //! sparse multiplied by scalar
249 template<typename T1>
250 inline
251 typename
252 enable_if2
253   <
254   is_arma_sparse_type<T1>::value,
255   SpOp<T1,spop_scalar_times>
256   >::result
operator *(const T1 & X,const typename T1::elem_type k)257 operator*
258   (
259   const T1& X,
260   const typename T1::elem_type k
261   )
262   {
263   arma_extra_debug_sigprint();
264 
265   return SpOp<T1,spop_scalar_times>(X, k);
266   }
267 
268 
269 
270 template<typename T1>
271 inline
272 typename
273 enable_if2
274   <
275   is_arma_sparse_type<T1>::value,
276   SpOp<T1,spop_scalar_times>
277   >::result
operator *(const typename T1::elem_type k,const T1 & X)278 operator*
279   (
280   const typename T1::elem_type k,
281   const T1& X
282   )
283   {
284   arma_extra_debug_sigprint();
285 
286   return SpOp<T1,spop_scalar_times>(X, k);
287   }
288 
289 
290 
291 //! non-complex sparse * complex scalar
292 template<typename T1>
293 arma_inline
294 typename
295 enable_if2
296   <
297   (is_arma_sparse_type<T1>::value && is_cx<typename T1::elem_type>::no),
298   const mtSpOp<typename std::complex<typename T1::pod_type>, T1, spop_cx_scalar_times>
299   >::result
operator *(const T1 & X,const std::complex<typename T1::pod_type> & k)300 operator*
301   (
302   const T1&                                  X,
303   const std::complex<typename T1::pod_type>& k
304   )
305   {
306   arma_extra_debug_sigprint();
307 
308   return mtSpOp<typename std::complex<typename T1::pod_type>, T1, spop_cx_scalar_times>('j', X, k);
309   }
310 
311 
312 
313 //! complex scalar * non-complex sparse
314 template<typename T1>
315 arma_inline
316 typename
317 enable_if2
318   <
319   (is_arma_sparse_type<T1>::value && is_cx<typename T1::elem_type>::no),
320   const mtSpOp<typename std::complex<typename T1::pod_type>, T1, spop_cx_scalar_times>
321   >::result
operator *(const std::complex<typename T1::pod_type> & k,const T1 & X)322 operator*
323   (
324   const std::complex<typename T1::pod_type>& k,
325   const T1&                                  X
326   )
327   {
328   arma_extra_debug_sigprint();
329 
330   return mtSpOp<typename std::complex<typename T1::pod_type>, T1, spop_cx_scalar_times>('j', X, k);
331   }
332 
333 
334 
335 //! multiplication of two sparse objects
336 template<typename T1, typename T2>
337 inline
338 typename
339 enable_if2
340   <
341   (is_arma_sparse_type<T1>::value && is_arma_sparse_type<T2>::value && is_same_type<typename T1::elem_type, typename T2::elem_type>::value),
342   const SpGlue<T1,T2,spglue_times>
343   >::result
operator *(const T1 & x,const T2 & y)344 operator*
345   (
346   const T1& x,
347   const T2& y
348   )
349   {
350   arma_extra_debug_sigprint();
351 
352   return SpGlue<T1,T2,spglue_times>(x, y);
353   }
354 
355 
356 
357 //! multiplication of one sparse and one dense object
358 template<typename T1, typename T2>
359 inline
360 typename
361 enable_if2
362   <
363   (is_arma_sparse_type<T1>::value && is_arma_type<T2>::value && is_same_type<typename T1::elem_type, typename T2::elem_type>::value),
364   Mat<typename T1::elem_type>
365   >::result
operator *(const T1 & x,const T2 & y)366 operator*
367   (
368   const T1& x,
369   const T2& y
370   )
371   {
372   arma_extra_debug_sigprint();
373 
374   typedef typename T1::elem_type eT;
375 
376   Mat<eT> result;
377 
378   spglue_times_misc::sparse_times_dense(result, x, y);
379 
380   return result;
381   }
382 
383 
384 
385 //! multiplication of one dense and one sparse object
386 template<typename T1, typename T2>
387 inline
388 typename
389 enable_if2
390   <
391   (is_arma_type<T1>::value && is_arma_sparse_type<T2>::value && is_same_type<typename T1::elem_type, typename T2::elem_type>::value),
392   Mat<typename T1::elem_type>
393   >::result
operator *(const T1 & x,const T2 & y)394 operator*
395   (
396   const T1& x,
397   const T2& y
398   )
399   {
400   arma_extra_debug_sigprint();
401 
402   typedef typename T1::elem_type eT;
403 
404   Mat<eT> result;
405 
406   spglue_times_misc::dense_times_sparse(result, x, y);
407 
408   return result;
409   }
410 
411 
412 
413 //! multiplication of two sparse objects with different element types
414 template<typename T1, typename T2>
415 inline
416 typename
417 enable_if2
418   <
419   (is_arma_sparse_type<T1>::value && is_arma_sparse_type<T2>::value && (is_same_type<typename T1::elem_type, typename T2::elem_type>::no)),
420   const mtSpGlue< typename promote_type<typename T1::elem_type, typename T2::elem_type>::result, T1, T2, spglue_times_mixed >
421   >::result
operator *(const T1 & X,const T2 & Y)422 operator*
423   (
424   const T1& X,
425   const T2& Y
426   )
427   {
428   arma_extra_debug_sigprint();
429 
430   typedef typename T1::elem_type eT1;
431   typedef typename T2::elem_type eT2;
432 
433   typedef typename promote_type<eT1,eT2>::result out_eT;
434 
435   promote_type<eT1,eT2>::check();
436 
437   return mtSpGlue<out_eT, T1, T2, spglue_times_mixed>( X, Y );
438   }
439 
440 
441 
442 //! multiplication of one sparse and one dense object with different element types
443 template<typename T1, typename T2>
444 inline
445 typename
446 enable_if2
447   <
448   (is_arma_sparse_type<T1>::value && is_arma_type<T2>::value && is_same_type<typename T1::elem_type, typename T2::elem_type>::no),
449   Mat< typename promote_type<typename T1::elem_type, typename T2::elem_type>::result >
450   >::result
operator *(const T1 & X,const T2 & Y)451 operator*
452   (
453   const T1& X,
454   const T2& Y
455   )
456   {
457   arma_extra_debug_sigprint();
458 
459   Mat< typename promote_type<typename T1::elem_type, typename T2::elem_type>::result > out;
460 
461   spglue_times_mixed::sparse_times_dense(out, X, Y);
462 
463   return out;
464   }
465 
466 
467 
468 //! multiplication of one dense and one sparse object with different element types
469 template<typename T1, typename T2>
470 inline
471 typename
472 enable_if2
473   <
474   (is_arma_type<T1>::value && is_arma_sparse_type<T2>::value && is_same_type<typename T1::elem_type, typename T2::elem_type>::no),
475   Mat< typename promote_type<typename T1::elem_type, typename T2::elem_type>::result >
476   >::result
operator *(const T1 & X,const T2 & Y)477 operator*
478   (
479   const T1& X,
480   const T2& Y
481   )
482   {
483   arma_extra_debug_sigprint();
484 
485   Mat< typename promote_type<typename T1::elem_type, typename T2::elem_type>::result > out;
486 
487   spglue_times_mixed::dense_times_sparse(out, X, Y);
488 
489   return out;
490   }
491 
492 
493 
494 //! @}
495