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