GNU Octave  4.0.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
mx-op-defs.h
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2015 John W. Eaton
4 Copyright (C) 2008-2009 Jaroslav Hajek
5 Copyright (C) 2009-2010 VZLU Prague, a.s.
6 
7 This file is part of Octave.
8 
9 Octave is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License as published by the
11 Free Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
13 
14 Octave is distributed in the hope that it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Octave; see the file COPYING. If not, see
21 <http://www.gnu.org/licenses/>.
22 
23 */
24 
25 #if !defined (octave_mx_op_defs_h)
26 #define octave_mx_op_defs_h 1
27 
28 #include "lo-array-gripes.h"
29 #include "mx-op-decl.h"
30 #include "mx-inlines.cc"
31 
32 #define SNANCHK(s) \
33  if (xisnan (s)) \
34  gripe_nan_to_logical_conversion ()
35 
36 #define MNANCHK(m, MT) \
37  if (do_mx_check (m, mx_inline_any_nan<MT>)) \
38  gripe_nan_to_logical_conversion ()
39 
40 // vector by scalar operations.
41 
42 #define VS_BIN_OP(R, F, OP, V, S) \
43  R \
44  F (const V& v, const S& s) \
45  { \
46  return do_ms_binary_op<R::element_type, V::element_type, S> (v, s, OP); \
47  }
48 
49 #define VS_BIN_OPS(R, V, S) \
50  VS_BIN_OP (R, operator +, mx_inline_add, V, S) \
51  VS_BIN_OP (R, operator -, mx_inline_sub, V, S) \
52  VS_BIN_OP (R, operator *, mx_inline_mul, V, S) \
53  VS_BIN_OP (R, operator /, mx_inline_div, V, S)
54 
55 // scalar by vector by operations.
56 
57 #define SV_BIN_OP(R, F, OP, S, V) \
58  R \
59  F (const S& s, const V& v) \
60  { \
61  return do_sm_binary_op<R::element_type, S, V::element_type> (s, v, OP); \
62  }
63 
64 #define SV_BIN_OPS(R, S, V) \
65  SV_BIN_OP (R, operator +, mx_inline_add, S, V) \
66  SV_BIN_OP (R, operator -, mx_inline_sub, S, V) \
67  SV_BIN_OP (R, operator *, mx_inline_mul, S, V) \
68  SV_BIN_OP (R, operator /, mx_inline_div, S, V)
69 
70 // vector by vector operations.
71 
72 #define VV_BIN_OP(R, F, OP, V1, V2) \
73  R \
74  F (const V1& v1, const V2& v2) \
75  { \
76  return do_mm_binary_op<R::element_type, V1::element_type, V2::element_type> (v1, v2, OP, OP, OP, #F); \
77  }
78 
79 #define VV_BIN_OPS(R, V1, V2) \
80  VV_BIN_OP (R, operator +, mx_inline_add, V1, V2) \
81  VV_BIN_OP (R, operator -, mx_inline_sub, V1, V2) \
82  VV_BIN_OP (R, product, mx_inline_mul, V1, V2) \
83  VV_BIN_OP (R, quotient, mx_inline_div, V1, V2)
84 
85 // matrix by scalar operations.
86 
87 #define MS_BIN_OP(R, OP, M, S, F) \
88  R \
89  OP (const M& m, const S& s) \
90  { \
91  return do_ms_binary_op<R::element_type, M::element_type, S> (m, s, F); \
92  }
93 
94 #define MS_BIN_OPS(R, M, S) \
95  MS_BIN_OP (R, operator +, M, S, mx_inline_add) \
96  MS_BIN_OP (R, operator -, M, S, mx_inline_sub) \
97  MS_BIN_OP (R, operator *, M, S, mx_inline_mul) \
98  MS_BIN_OP (R, operator /, M, S, mx_inline_div)
99 
100 #define MS_CMP_OP(F, OP, M, S) \
101  boolMatrix \
102  F (const M& m, const S& s) \
103  { \
104  return do_ms_binary_op<bool, M::element_type, S> (m, s, OP); \
105  }
106 
107 #define MS_CMP_OPS(M, S) \
108  MS_CMP_OP (mx_el_lt, mx_inline_lt, M, S) \
109  MS_CMP_OP (mx_el_le, mx_inline_le, M, S) \
110  MS_CMP_OP (mx_el_ge, mx_inline_ge, M, S) \
111  MS_CMP_OP (mx_el_gt, mx_inline_gt, M, S) \
112  MS_CMP_OP (mx_el_eq, mx_inline_eq, M, S) \
113  MS_CMP_OP (mx_el_ne, mx_inline_ne, M, S)
114 
115 #define MS_BOOL_OP(F, OP, M, S) \
116  boolMatrix \
117  F (const M& m, const S& s) \
118  { \
119  MNANCHK (m, M::element_type); \
120  SNANCHK (s); \
121  return do_ms_binary_op<bool, M::element_type, S> (m, s, OP); \
122  }
123 
124 #define MS_BOOL_OPS(M, S) \
125  MS_BOOL_OP (mx_el_and, mx_inline_and, M, S) \
126  MS_BOOL_OP (mx_el_or, mx_inline_or, M, S)
127 
128 // scalar by matrix operations.
129 
130 #define SM_BIN_OP(R, OP, S, M, F) \
131  R \
132  OP (const S& s, const M& m) \
133  { \
134  return do_sm_binary_op<R::element_type, S, M::element_type> (s, m, F); \
135  }
136 
137 #define SM_BIN_OPS(R, S, M) \
138  SM_BIN_OP (R, operator +, S, M, mx_inline_add) \
139  SM_BIN_OP (R, operator -, S, M, mx_inline_sub) \
140  SM_BIN_OP (R, operator *, S, M, mx_inline_mul) \
141  SM_BIN_OP (R, operator /, S, M, mx_inline_div)
142 
143 #define SM_CMP_OP(F, OP, S, M) \
144  boolMatrix \
145  F (const S& s, const M& m) \
146  { \
147  return do_sm_binary_op<bool, S, M::element_type> (s, m, OP); \
148  }
149 
150 #define SM_CMP_OPS(S, M) \
151  SM_CMP_OP (mx_el_lt, mx_inline_lt, S, M) \
152  SM_CMP_OP (mx_el_le, mx_inline_le, S, M) \
153  SM_CMP_OP (mx_el_ge, mx_inline_ge, S, M) \
154  SM_CMP_OP (mx_el_gt, mx_inline_gt, S, M) \
155  SM_CMP_OP (mx_el_eq, mx_inline_eq, S, M) \
156  SM_CMP_OP (mx_el_ne, mx_inline_ne, S, M)
157 
158 #define SM_BOOL_OP(F, OP, S, M) \
159  boolMatrix \
160  F (const S& s, const M& m) \
161  { \
162  SNANCHK (s); \
163  MNANCHK (m, M::element_type); \
164  return do_sm_binary_op<bool, S, M::element_type> (s, m, OP); \
165  }
166 
167 #define SM_BOOL_OPS(S, M) \
168  SM_BOOL_OP (mx_el_and, mx_inline_and, S, M) \
169  SM_BOOL_OP (mx_el_or, mx_inline_or, S, M)
170 
171 // matrix by matrix operations.
172 
173 #define MM_BIN_OP(R, OP, M1, M2, F) \
174  R \
175  OP (const M1& m1, const M2& m2) \
176  { \
177  return do_mm_binary_op<R::element_type, M1::element_type, M2::element_type> (m1, m2, F, F, F, #OP); \
178  }
179 
180 #define MM_BIN_OPS(R, M1, M2) \
181  MM_BIN_OP (R, operator +, M1, M2, mx_inline_add) \
182  MM_BIN_OP (R, operator -, M1, M2, mx_inline_sub) \
183  MM_BIN_OP (R, product, M1, M2, mx_inline_mul) \
184  MM_BIN_OP (R, quotient, M1, M2, mx_inline_div)
185 
186 #define MM_CMP_OP(F, OP, M1, M2) \
187  boolMatrix \
188  F (const M1& m1, const M2& m2) \
189  { \
190  return do_mm_binary_op<bool, M1::element_type, M2::element_type> (m1, m2, OP, OP, OP, #F); \
191  }
192 
193 #define MM_CMP_OPS(M1, M2) \
194  MM_CMP_OP (mx_el_lt, mx_inline_lt, M1, M2) \
195  MM_CMP_OP (mx_el_le, mx_inline_le, M1, M2) \
196  MM_CMP_OP (mx_el_ge, mx_inline_ge, M1, M2) \
197  MM_CMP_OP (mx_el_gt, mx_inline_gt, M1, M2) \
198  MM_CMP_OP (mx_el_eq, mx_inline_eq, M1, M2) \
199  MM_CMP_OP (mx_el_ne, mx_inline_ne, M1, M2)
200 
201 #define MM_BOOL_OP(F, OP, M1, M2) \
202  boolMatrix \
203  F (const M1& m1, const M2& m2) \
204  { \
205  MNANCHK (m1, M1::element_type); \
206  MNANCHK (m2, M2::element_type); \
207  return do_mm_binary_op<bool, M1::element_type, M2::element_type> (m1, m2, OP, OP, OP, #F); \
208  }
209 
210 #define MM_BOOL_OPS(M1, M2) \
211  MM_BOOL_OP (mx_el_and, mx_inline_and, M1, M2) \
212  MM_BOOL_OP (mx_el_or, mx_inline_or, M1, M2)
213 
214 // N-d matrix by scalar operations.
215 
216 #define NDS_BIN_OP(R, OP, ND, S, F) \
217  R \
218  OP (const ND& m, const S& s) \
219  { \
220  return do_ms_binary_op<R::element_type, ND::element_type, S> (m, s, F); \
221  }
222 
223 #define NDS_BIN_OPS(R, ND, S) \
224  NDS_BIN_OP (R, operator +, ND, S, mx_inline_add) \
225  NDS_BIN_OP (R, operator -, ND, S, mx_inline_sub) \
226  NDS_BIN_OP (R, operator *, ND, S, mx_inline_mul) \
227  NDS_BIN_OP (R, operator /, ND, S, mx_inline_div)
228 
229 #define NDS_CMP_OP(F, OP, ND, S) \
230  boolNDArray \
231  F (const ND& m, const S& s) \
232  { \
233  return do_ms_binary_op<bool, ND::element_type, S> (m, s, OP); \
234  }
235 
236 #define NDS_CMP_OPS(ND, S) \
237  NDS_CMP_OP (mx_el_lt, mx_inline_lt, ND, S) \
238  NDS_CMP_OP (mx_el_le, mx_inline_le, ND, S) \
239  NDS_CMP_OP (mx_el_ge, mx_inline_ge, ND, S) \
240  NDS_CMP_OP (mx_el_gt, mx_inline_gt, ND, S) \
241  NDS_CMP_OP (mx_el_eq, mx_inline_eq, ND, S) \
242  NDS_CMP_OP (mx_el_ne, mx_inline_ne, ND, S)
243 
244 #define NDS_BOOL_OP(F, OP, ND, S) \
245  boolNDArray \
246  F (const ND& m, const S& s) \
247  { \
248  MNANCHK (m, ND::element_type); \
249  SNANCHK (s); \
250  return do_ms_binary_op<bool, ND::element_type, S> (m, s, OP); \
251  }
252 
253 #define NDS_BOOL_OPS(ND, S) \
254  NDS_BOOL_OP (mx_el_and, mx_inline_and, ND, S) \
255  NDS_BOOL_OP (mx_el_or, mx_inline_or, ND, S) \
256  NDS_BOOL_OP (mx_el_not_and, mx_inline_not_and, ND, S) \
257  NDS_BOOL_OP (mx_el_not_or, mx_inline_not_or, ND, S) \
258  NDS_BOOL_OP (mx_el_and_not, mx_inline_and_not, ND, S) \
259  NDS_BOOL_OP (mx_el_or_not, mx_inline_or_not, ND, S)
260 
261 // scalar by N-d matrix operations.
262 
263 #define SND_BIN_OP(R, OP, S, ND, F) \
264  R \
265  OP (const S& s, const ND& m) \
266  { \
267  return do_sm_binary_op<R::element_type, S, ND::element_type> (s, m, F); \
268  }
269 
270 #define SND_BIN_OPS(R, S, ND) \
271  SND_BIN_OP (R, operator +, S, ND, mx_inline_add) \
272  SND_BIN_OP (R, operator -, S, ND, mx_inline_sub) \
273  SND_BIN_OP (R, operator *, S, ND, mx_inline_mul) \
274  SND_BIN_OP (R, operator /, S, ND, mx_inline_div)
275 
276 #define SND_CMP_OP(F, OP, S, ND) \
277  boolNDArray \
278  F (const S& s, const ND& m) \
279  { \
280  return do_sm_binary_op<bool, S, ND::element_type> (s, m, OP); \
281  }
282 
283 #define SND_CMP_OPS(S, ND) \
284  SND_CMP_OP (mx_el_lt, mx_inline_lt, S, ND) \
285  SND_CMP_OP (mx_el_le, mx_inline_le, S, ND) \
286  SND_CMP_OP (mx_el_ge, mx_inline_ge, S, ND) \
287  SND_CMP_OP (mx_el_gt, mx_inline_gt, S, ND) \
288  SND_CMP_OP (mx_el_eq, mx_inline_eq, S, ND) \
289  SND_CMP_OP (mx_el_ne, mx_inline_ne, S, ND)
290 
291 #define SND_BOOL_OP(F, OP, S, ND) \
292  boolNDArray \
293  F (const S& s, const ND& m) \
294  { \
295  SNANCHK (s); \
296  MNANCHK (m, ND::element_type); \
297  return do_sm_binary_op<bool, S, ND::element_type> (s, m, OP); \
298  }
299 
300 #define SND_BOOL_OPS(S, ND) \
301  SND_BOOL_OP (mx_el_and, mx_inline_and, S, ND) \
302  SND_BOOL_OP (mx_el_or, mx_inline_or, S, ND) \
303  SND_BOOL_OP (mx_el_not_and, mx_inline_not_and, S, ND) \
304  SND_BOOL_OP (mx_el_not_or, mx_inline_not_or, S, ND) \
305  SND_BOOL_OP (mx_el_and_not, mx_inline_and_not, S, ND) \
306  SND_BOOL_OP (mx_el_or_not, mx_inline_or_not, S, ND)
307 
308 // N-d matrix by N-d matrix operations.
309 
310 #define NDND_BIN_OP(R, OP, ND1, ND2, F) \
311  R \
312  OP (const ND1& m1, const ND2& m2) \
313  { \
314  return do_mm_binary_op<R::element_type, ND1::element_type, ND2::element_type> (m1, m2, F, F, F, #OP); \
315  }
316 
317 #define NDND_BIN_OPS(R, ND1, ND2) \
318  NDND_BIN_OP (R, operator +, ND1, ND2, mx_inline_add) \
319  NDND_BIN_OP (R, operator -, ND1, ND2, mx_inline_sub) \
320  NDND_BIN_OP (R, product, ND1, ND2, mx_inline_mul) \
321  NDND_BIN_OP (R, quotient, ND1, ND2, mx_inline_div)
322 
323 #define NDND_CMP_OP(F, OP, ND1, ND2) \
324  boolNDArray \
325  F (const ND1& m1, const ND2& m2) \
326  { \
327  return do_mm_binary_op<bool, ND1::element_type, ND2::element_type> (m1, m2, OP, OP, OP, #F); \
328  }
329 
330 #define NDND_CMP_OPS(ND1, ND2) \
331  NDND_CMP_OP (mx_el_lt, mx_inline_lt, ND1, ND2) \
332  NDND_CMP_OP (mx_el_le, mx_inline_le, ND1, ND2) \
333  NDND_CMP_OP (mx_el_ge, mx_inline_ge, ND1, ND2) \
334  NDND_CMP_OP (mx_el_gt, mx_inline_gt, ND1, ND2) \
335  NDND_CMP_OP (mx_el_eq, mx_inline_eq, ND1, ND2) \
336  NDND_CMP_OP (mx_el_ne, mx_inline_ne, ND1, ND2)
337 
338 #define NDND_BOOL_OP(F, OP, ND1, ND2) \
339  boolNDArray \
340  F (const ND1& m1, const ND2& m2) \
341  { \
342  MNANCHK (m1, ND1::element_type); \
343  MNANCHK (m2, ND2::element_type); \
344  return do_mm_binary_op<bool, ND1::element_type, ND2::element_type> (m1, m2, OP, OP, OP, #F); \
345  }
346 
347 #define NDND_BOOL_OPS(ND1, ND2) \
348  NDND_BOOL_OP (mx_el_and, mx_inline_and, ND1, ND2) \
349  NDND_BOOL_OP (mx_el_or, mx_inline_or, ND1, ND2) \
350  NDND_BOOL_OP (mx_el_not_and, mx_inline_not_and, ND1, ND2) \
351  NDND_BOOL_OP (mx_el_not_or, mx_inline_not_or, ND1, ND2) \
352  NDND_BOOL_OP (mx_el_and_not, mx_inline_and_not, ND1, ND2) \
353  NDND_BOOL_OP (mx_el_or_not, mx_inline_or_not, ND1, ND2)
354 
355 // scalar by diagonal matrix operations.
356 
357 #define SDM_BIN_OP(R, OP, S, DM) \
358  R \
359  operator OP (const S& s, const DM& dm) \
360  { \
361  R r (dm.rows (), dm.cols ()); \
362  \
363  for (octave_idx_type i = 0; i < dm.length (); i++) \
364  r.dgxelem (i) = s OP dm.dgelem (i); \
365  \
366  return r; \
367 }
368 
369 #define SDM_BIN_OPS(R, S, DM) \
370  SDM_BIN_OP (R, *, S, DM)
371 
372 // diagonal matrix by scalar operations.
373 
374 #define DMS_BIN_OP(R, OP, DM, S) \
375  R \
376  operator OP (const DM& dm, const S& s) \
377  { \
378  R r (dm.rows (), dm.cols ()); \
379  \
380  for (octave_idx_type i = 0; i < dm.length (); i++) \
381  r.dgxelem (i) = dm.dgelem (i) OP s; \
382  \
383  return r; \
384  }
385 
386 #define DMS_BIN_OPS(R, DM, S) \
387  DMS_BIN_OP (R, *, DM, S) \
388  DMS_BIN_OP (R, /, DM, S)
389 
390 // matrix by diagonal matrix operations.
391 
392 #define MDM_BIN_OP(R, OP, M, DM, OPEQ) \
393 R \
394 OP (const M& m, const DM& dm) \
395 { \
396  R r; \
397  \
398  octave_idx_type m_nr = m.rows (); \
399  octave_idx_type m_nc = m.cols (); \
400  \
401  octave_idx_type dm_nr = dm.rows (); \
402  octave_idx_type dm_nc = dm.cols (); \
403  \
404  if (m_nr != dm_nr || m_nc != dm_nc) \
405  gripe_nonconformant (#OP, m_nr, m_nc, dm_nr, dm_nc); \
406  else \
407  { \
408  r.resize (m_nr, m_nc); \
409  \
410  if (m_nr > 0 && m_nc > 0) \
411  { \
412  r = R (m); \
413  \
414  octave_idx_type len = dm.length (); \
415  \
416  for (octave_idx_type i = 0; i < len; i++) \
417  r.elem (i, i) OPEQ dm.elem (i, i); \
418  } \
419  } \
420  \
421  return r; \
422 }
423 
424 #define MDM_MULTIPLY_OP(R, M, DM, R_ZERO) \
425 R \
426 operator * (const M& m, const DM& dm) \
427 { \
428  R r; \
429  \
430  octave_idx_type m_nr = m.rows (); \
431  octave_idx_type m_nc = m.cols (); \
432  \
433  octave_idx_type dm_nr = dm.rows (); \
434  octave_idx_type dm_nc = dm.cols (); \
435  \
436  if (m_nc != dm_nr) \
437  gripe_nonconformant ("operator *", m_nr, m_nc, dm_nr, dm_nc); \
438  else \
439  { \
440  r = R (m_nr, dm_nc); \
441  R::element_type *rd = r.fortran_vec (); \
442  const M::element_type *md = m.data (); \
443  const DM::element_type *dd = dm.data (); \
444  \
445  octave_idx_type len = dm.length (); \
446  for (octave_idx_type i = 0; i < len; i++) \
447  { \
448  mx_inline_mul (m_nr, rd, md, dd[i]); \
449  rd += m_nr; md += m_nr; \
450  } \
451  mx_inline_fill (m_nr * (dm_nc - len), rd, R_ZERO); \
452  } \
453  \
454  return r; \
455 }
456 
457 #define MDM_BIN_OPS(R, M, DM, R_ZERO) \
458  MDM_BIN_OP (R, operator +, M, DM, +=) \
459  MDM_BIN_OP (R, operator -, M, DM, -=) \
460  MDM_MULTIPLY_OP (R, M, DM, R_ZERO)
461 
462 // diagonal matrix by matrix operations.
463 
464 #define DMM_BIN_OP(R, OP, DM, M, OPEQ, PREOP) \
465 R \
466 OP (const DM& dm, const M& m) \
467 { \
468  R r; \
469  \
470  octave_idx_type dm_nr = dm.rows (); \
471  octave_idx_type dm_nc = dm.cols (); \
472  \
473  octave_idx_type m_nr = m.rows (); \
474  octave_idx_type m_nc = m.cols (); \
475  \
476  if (dm_nr != m_nr || dm_nc != m_nc) \
477  gripe_nonconformant (#OP, dm_nr, dm_nc, m_nr, m_nc); \
478  else \
479  { \
480  if (m_nr > 0 && m_nc > 0) \
481  { \
482  r = R (PREOP m); \
483  \
484  octave_idx_type len = dm.length (); \
485  \
486  for (octave_idx_type i = 0; i < len; i++) \
487  r.elem (i, i) OPEQ dm.elem (i, i); \
488  } \
489  else \
490  r.resize (m_nr, m_nc); \
491  } \
492  \
493  return r; \
494 }
495 
496 #define DMM_MULTIPLY_OP(R, DM, M, R_ZERO) \
497 R \
498 operator * (const DM& dm, const M& m) \
499 { \
500  R r; \
501  \
502  octave_idx_type dm_nr = dm.rows (); \
503  octave_idx_type dm_nc = dm.cols (); \
504  \
505  octave_idx_type m_nr = m.rows (); \
506  octave_idx_type m_nc = m.cols (); \
507  \
508  if (dm_nc != m_nr) \
509  gripe_nonconformant ("operator *", dm_nr, dm_nc, m_nr, m_nc); \
510  else \
511  { \
512  r = R (dm_nr, m_nc); \
513  R::element_type *rd = r.fortran_vec (); \
514  const M::element_type *md = m.data (); \
515  const DM::element_type *dd = dm.data (); \
516  \
517  octave_idx_type len = dm.length (); \
518  for (octave_idx_type i = 0; i < m_nc; i++) \
519  { \
520  mx_inline_mul (len, rd, md, dd); \
521  rd += len; md += m_nr; \
522  mx_inline_fill (dm_nr - len, rd, R_ZERO); \
523  rd += dm_nr - len; \
524  } \
525  } \
526  \
527  return r; \
528 }
529 
530 #define DMM_BIN_OPS(R, DM, M, R_ZERO) \
531  DMM_BIN_OP (R, operator +, DM, M, +=, ) \
532  DMM_BIN_OP (R, operator -, DM, M, +=, -) \
533  DMM_MULTIPLY_OP (R, DM, M, R_ZERO)
534 
535 // diagonal matrix by diagonal matrix operations.
536 
537 #define DMDM_BIN_OP(R, OP, DM1, DM2, F) \
538  R \
539  OP (const DM1& dm1, const DM2& dm2) \
540  { \
541  R r; \
542  \
543  octave_idx_type dm1_nr = dm1.rows (); \
544  octave_idx_type dm1_nc = dm1.cols (); \
545  \
546  octave_idx_type dm2_nr = dm2.rows (); \
547  octave_idx_type dm2_nc = dm2.cols (); \
548  \
549  if (dm1_nr != dm2_nr || dm1_nc != dm2_nc) \
550  gripe_nonconformant (#OP, dm1_nr, dm1_nc, dm2_nr, dm2_nc); \
551  else \
552  { \
553  r.resize (dm1_nr, dm1_nc); \
554  \
555  if (dm1_nr > 0 && dm1_nc > 0) \
556  F (dm1.length (), r.fortran_vec (), dm1.data (), dm2.data ()); \
557  } \
558  \
559  return r; \
560  }
561 
562 #define DMDM_BIN_OPS(R, DM1, DM2) \
563  DMDM_BIN_OP (R, operator +, DM1, DM2, mx_inline_add) \
564  DMDM_BIN_OP (R, operator -, DM1, DM2, mx_inline_sub) \
565  DMDM_BIN_OP (R, product, DM1, DM2, mx_inline_mul)
566 
567 // scalar by N-d array min/max ops
568 
569 #define SND_MINMAX_FCN(FCN, OP, T, S) \
570 T \
571 FCN (S d, const T& m) \
572 { \
573  return do_sm_binary_op<T::element_type, S, T::element_type> (d, m, mx_inline_x##FCN); \
574 }
575 
576 #define NDS_MINMAX_FCN(FCN, OP, T, S) \
577 T \
578 FCN (const T& m, S d) \
579 { \
580  return do_ms_binary_op<T::element_type, T::element_type, S> (m, d, mx_inline_x##FCN); \
581 }
582 
583 #define NDND_MINMAX_FCN(FCN, OP, T, S) \
584 T \
585 FCN (const T& a, const T& b) \
586 { \
587  return do_mm_binary_op<T::element_type, T::element_type, T::element_type> (a, b, mx_inline_x##FCN, mx_inline_x##FCN, mx_inline_x##FCN, #FCN); \
588 }
589 
590 #define MINMAX_FCNS(T, S) \
591  SND_MINMAX_FCN (min, <, T, S) \
592  NDS_MINMAX_FCN (min, <, T, S) \
593  NDND_MINMAX_FCN (min, <, T, S) \
594  SND_MINMAX_FCN (max, >, T, S) \
595  NDS_MINMAX_FCN (max, >, T, S) \
596  NDND_MINMAX_FCN (max, >, T, S)
597 
598 // permutation matrix by matrix ops and vice versa
599 
600 #define PMM_MULTIPLY_OP(PM, M) \
601 M operator * (const PM& p, const M& x) \
602 { \
603  octave_idx_type nr = x.rows (); \
604  octave_idx_type nc = x.columns (); \
605  M result; \
606  if (p.columns () != nr) \
607  gripe_nonconformant ("operator *", p.rows (), p.columns (), nr, nc); \
608  else \
609  { \
610  result = M (nr, nc); \
611  result.assign (p.col_perm_vec (), idx_vector::colon, x); \
612  } \
613  \
614  return result; \
615 }
616 
617 #define MPM_MULTIPLY_OP(M, PM) \
618 M operator * (const M& x, const PM& p) \
619 { \
620  octave_idx_type nr = x.rows (); \
621  octave_idx_type nc = x.columns (); \
622  M result; \
623  if (p.rows () != nc) \
624  gripe_nonconformant ("operator *", nr, nc, p.rows (), p.columns ()); \
625  else \
626  result = x.index (idx_vector::colon, p.col_perm_vec ()); \
627  \
628  return result; \
629 }
630 
631 #define PMM_BIN_OPS(R, PM, M) \
632  PMM_MULTIPLY_OP(PM, M);
633 
634 #define MPM_BIN_OPS(R, M, PM) \
635  MPM_MULTIPLY_OP(M, PM);
636 
637 #define NDND_MAPPER_BODY(R, NAME) \
638  R retval (dims ()); \
639  octave_idx_type n = numel (); \
640  for (octave_idx_type i = 0; i < n; i++) \
641  retval.xelem (i) = NAME (elem (i)); \
642  return retval;
643 
644 #endif