comparison liboctave/operators/Sparse-op-defs.h @ 22197:e43d83253e28

refill multi-line macro definitions Use the Emacs C++ mode style for line continuation markers in multi-line macro definitions. * make_int.cc, __dsearchn__.cc, __magick_read__.cc, besselj.cc, bitfcns.cc, bsxfun.cc, cellfun.cc, data.cc, defun-dld.h, defun-int.h, defun.h, det.cc, error.h, find.cc, gcd.cc, graphics.cc, interpreter.h, jit-ir.h, jit-typeinfo.h, lookup.cc, ls-mat5.cc, max.cc, mexproto.h, mxarray.in.h, oct-stream.cc, ordschur.cc, pr-output.cc, profiler.h, psi.cc, regexp.cc, sparse-xdiv.cc, sparse-xpow.cc, tril.cc, txt-eng.h, utils.cc, variables.cc, variables.h, xdiv.cc, xpow.cc, __glpk__.cc, ov-base.cc, ov-base.h, ov-cell.cc, ov-ch-mat.cc, ov-classdef.cc, ov-complex.cc, ov-cx-mat.cc, ov-cx-sparse.cc, ov-float.cc, ov-float.h, ov-flt-complex.cc, ov-flt-cx-mat.cc, ov-flt-re-mat.cc, ov-int-traits.h, ov-lazy-idx.h, ov-perm.cc, ov-re-mat.cc, ov-re-sparse.cc, ov-scalar.cc, ov-scalar.h, ov-str-mat.cc, ov-type-conv.h, ov.cc, ov.h, op-class.cc, op-int-conv.cc, op-int.h, op-str-str.cc, ops.h, lex.ll, Array.cc, CMatrix.cc, CSparse.cc, MArray.cc, MArray.h, MDiagArray2.cc, MDiagArray2.h, MSparse.h, Sparse.cc, dMatrix.cc, dSparse.cc, fCMatrix.cc, fMatrix.cc, idx-vector.cc, f77-fcn.h, quit.h, bsxfun-decl.h, bsxfun-defs.cc, lo-specfun.cc, oct-convn.cc, oct-convn.h, oct-norm.cc, oct-norm.h, oct-rand.cc, Sparse-op-decls.h, Sparse-op-defs.h, mx-inlines.cc, mx-op-decl.h, mx-op-defs.h, mach-info.cc, oct-group.cc, oct-passwd.cc, oct-syscalls.cc, oct-time.cc, data-conv.cc, kpse.cc, lo-ieee.h, lo-macros.h, oct-cmplx.h, oct-glob.cc, oct-inttypes.cc, oct-inttypes.h, oct-locbuf.h, oct-sparse.h, url-transfer.cc, oct-conf-post.in.h, shared-fcns.h: Refill macro definitions.
author John W. Eaton <jwe@octave.org>
date Mon, 01 Aug 2016 12:40:18 -0400
parents 278fc29b69ca
children bac0d6f07a3e
comparison
equal deleted inserted replaced
22196:dd992fd74fce 22197:e43d83253e28
31 #include "oct-locbuf.h" 31 #include "oct-locbuf.h"
32 #include "mx-inlines.cc" 32 #include "mx-inlines.cc"
33 33
34 // sparse matrix by scalar operations. 34 // sparse matrix by scalar operations.
35 35
36 #define SPARSE_SMS_BIN_OP_1(R, F, OP, M, S) \ 36 #define SPARSE_SMS_BIN_OP_1(R, F, OP, M, S) \
37 R \ 37 R \
38 F (const M& m, const S& s) \ 38 F (const M& m, const S& s) \
39 { \ 39 { \
40 octave_idx_type nr = m.rows (); \ 40 octave_idx_type nr = m.rows (); \
41 octave_idx_type nc = m.cols (); \ 41 octave_idx_type nc = m.cols (); \
42 \ 42 \
43 R r (nr, nc, (0.0 OP s)); \ 43 R r (nr, nc, (0.0 OP s)); \
44 \ 44 \
45 for (octave_idx_type j = 0; j < nc; j++) \ 45 for (octave_idx_type j = 0; j < nc; j++) \
46 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \ 46 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
47 r.xelem (m.ridx (i), j) = m.data (i) OP s; \ 47 r.xelem (m.ridx (i), j) = m.data (i) OP s; \
48 return r; \ 48 return r; \
49 } 49 }
50 50
51 #define SPARSE_SMS_BIN_OP_2(R, F, OP, M, S) \ 51 #define SPARSE_SMS_BIN_OP_2(R, F, OP, M, S) \
52 R \ 52 R \
53 F (const M& m, const S& s) \ 53 F (const M& m, const S& s) \
54 { \ 54 { \
55 octave_idx_type nr = m.rows (); \ 55 octave_idx_type nr = m.rows (); \
56 octave_idx_type nc = m.cols (); \ 56 octave_idx_type nc = m.cols (); \
57 octave_idx_type nz = m.nnz (); \ 57 octave_idx_type nz = m.nnz (); \
58 \ 58 \
59 R r (nr, nc, nz); \ 59 R r (nr, nc, nz); \
60 \ 60 \
61 for (octave_idx_type i = 0; i < nz; i++) \ 61 for (octave_idx_type i = 0; i < nz; i++) \
62 { \ 62 { \
63 r.xdata (i) = m.data (i) OP s; \ 63 r.xdata (i) = m.data (i) OP s; \
64 r.xridx (i) = m.ridx (i); \ 64 r.xridx (i) = m.ridx (i); \
65 } \ 65 } \
66 for (octave_idx_type i = 0; i < nc + 1; i++) \ 66 for (octave_idx_type i = 0; i < nc + 1; i++) \
67 r.xcidx (i) = m.cidx (i); \ 67 r.xcidx (i) = m.cidx (i); \
68 \ 68 \
69 r.maybe_compress (true); \ 69 r.maybe_compress (true); \
70 return r; \ 70 return r; \
71 } 71 }
72 72
73 #define SPARSE_SMS_BIN_OPS(R1, R2, M, S) \ 73 #define SPARSE_SMS_BIN_OPS(R1, R2, M, S) \
74 SPARSE_SMS_BIN_OP_1 (R1, operator +, +, M, S) \ 74 SPARSE_SMS_BIN_OP_1 (R1, operator +, +, M, S) \
75 SPARSE_SMS_BIN_OP_1 (R1, operator -, -, M, S) \ 75 SPARSE_SMS_BIN_OP_1 (R1, operator -, -, M, S) \
76 SPARSE_SMS_BIN_OP_2 (R2, operator *, *, M, S) \ 76 SPARSE_SMS_BIN_OP_2 (R2, operator *, *, M, S) \
77 SPARSE_SMS_BIN_OP_2 (R2, operator /, /, M, S) 77 SPARSE_SMS_BIN_OP_2 (R2, operator /, /, M, S)
78 78
79 #define SPARSE_SMS_CMP_OP(F, OP, M, MZ, MC, S, SZ, SC) \ 79 #define SPARSE_SMS_CMP_OP(F, OP, M, MZ, MC, S, SZ, SC) \
80 SparseBoolMatrix \ 80 SparseBoolMatrix \
81 F (const M& m, const S& s) \ 81 F (const M& m, const S& s) \
82 { \ 82 { \
83 octave_idx_type nr = m.rows (); \ 83 octave_idx_type nr = m.rows (); \
84 octave_idx_type nc = m.cols (); \ 84 octave_idx_type nc = m.cols (); \
85 SparseBoolMatrix r; \ 85 SparseBoolMatrix r; \
86 \ 86 \
87 if (MC (MZ) OP SC (s)) \ 87 if (MC (MZ) OP SC (s)) \
88 { \ 88 { \
89 r = SparseBoolMatrix (nr, nc, true); \ 89 r = SparseBoolMatrix (nr, nc, true); \
90 for (octave_idx_type j = 0; j < nc; j++) \ 90 for (octave_idx_type j = 0; j < nc; j++) \
91 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \ 91 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
92 if (! (MC (m.data (i)) OP SC (s))) \ 92 if (! (MC (m.data (i)) OP SC (s))) \
93 r.data (m.ridx (i) + j * nr) = false; \ 93 r.data (m.ridx (i) + j * nr) = false; \
94 r.maybe_compress (true); \ 94 r.maybe_compress (true); \
95 } \ 95 } \
96 else \ 96 else \
97 { \ 97 { \
98 r = SparseBoolMatrix (nr, nc, m.nnz ()); \ 98 r = SparseBoolMatrix (nr, nc, m.nnz ()); \
99 r.cidx (0) = static_cast<octave_idx_type> (0); \ 99 r.cidx (0) = static_cast<octave_idx_type> (0); \
100 octave_idx_type nel = 0; \ 100 octave_idx_type nel = 0; \
101 for (octave_idx_type j = 0; j < nc; j++) \ 101 for (octave_idx_type j = 0; j < nc; j++) \
102 { \ 102 { \
103 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \ 103 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
104 if (MC (m.data (i)) OP SC (s)) \ 104 if (MC (m.data (i)) OP SC (s)) \
105 { \ 105 { \
106 r.ridx (nel) = m.ridx (i); \ 106 r.ridx (nel) = m.ridx (i); \
107 r.data (nel++) = true; \ 107 r.data (nel++) = true; \
108 } \ 108 } \
109 r.cidx (j + 1) = nel; \ 109 r.cidx (j + 1) = nel; \
110 } \ 110 } \
111 r.maybe_compress (false); \ 111 r.maybe_compress (false); \
112 } \ 112 } \
113 return r; \ 113 return r; \
114 } 114 }
115 115
116 #define SPARSE_SMS_CMP_OPS(M, MZ, CM, S, SZ, CS) \ 116 #define SPARSE_SMS_CMP_OPS(M, MZ, CM, S, SZ, CS) \
117 SPARSE_SMS_CMP_OP (mx_el_lt, <, M, MZ, , S, SZ, ) \ 117 SPARSE_SMS_CMP_OP (mx_el_lt, <, M, MZ, , S, SZ, ) \
118 SPARSE_SMS_CMP_OP (mx_el_le, <=, M, MZ, , S, SZ, ) \ 118 SPARSE_SMS_CMP_OP (mx_el_le, <=, M, MZ, , S, SZ, ) \
119 SPARSE_SMS_CMP_OP (mx_el_ge, >=, M, MZ, , S, SZ, ) \ 119 SPARSE_SMS_CMP_OP (mx_el_ge, >=, M, MZ, , S, SZ, ) \
120 SPARSE_SMS_CMP_OP (mx_el_gt, >, M, MZ, , S, SZ, ) \ 120 SPARSE_SMS_CMP_OP (mx_el_gt, >, M, MZ, , S, SZ, ) \
121 SPARSE_SMS_CMP_OP (mx_el_eq, ==, M, MZ, , S, SZ, ) \ 121 SPARSE_SMS_CMP_OP (mx_el_eq, ==, M, MZ, , S, SZ, ) \
122 SPARSE_SMS_CMP_OP (mx_el_ne, !=, M, MZ, , S, SZ, ) 122 SPARSE_SMS_CMP_OP (mx_el_ne, !=, M, MZ, , S, SZ, )
123 123
124 #define SPARSE_SMS_EQNE_OPS(M, MZ, CM, S, SZ, CS) \ 124 #define SPARSE_SMS_EQNE_OPS(M, MZ, CM, S, SZ, CS) \
125 SPARSE_SMS_CMP_OP (mx_el_eq, ==, M, MZ, , S, SZ, ) \ 125 SPARSE_SMS_CMP_OP (mx_el_eq, ==, M, MZ, , S, SZ, ) \
126 SPARSE_SMS_CMP_OP (mx_el_ne, !=, M, MZ, , S, SZ, ) 126 SPARSE_SMS_CMP_OP (mx_el_ne, !=, M, MZ, , S, SZ, )
127 127
128 #define SPARSE_SMS_BOOL_OP(F, OP, M, S, LHS_ZERO, RHS_ZERO) \ 128 #define SPARSE_SMS_BOOL_OP(F, OP, M, S, LHS_ZERO, RHS_ZERO) \
129 SparseBoolMatrix \ 129 SparseBoolMatrix \
130 F (const M& m, const S& s) \ 130 F (const M& m, const S& s) \
131 { \ 131 { \
132 octave_idx_type nr = m.rows (); \ 132 octave_idx_type nr = m.rows (); \
133 octave_idx_type nc = m.cols (); \ 133 octave_idx_type nc = m.cols (); \
134 SparseBoolMatrix r; \ 134 SparseBoolMatrix r; \
135 \ 135 \
136 if (nr > 0 && nc > 0) \ 136 if (nr > 0 && nc > 0) \
137 { \ 137 { \
138 if (LHS_ZERO OP (s != RHS_ZERO)) \ 138 if (LHS_ZERO OP (s != RHS_ZERO)) \
139 { \ 139 { \
140 r = SparseBoolMatrix (nr, nc, true); \ 140 r = SparseBoolMatrix (nr, nc, true); \
141 for (octave_idx_type j = 0; j < nc; j++) \ 141 for (octave_idx_type j = 0; j < nc; j++) \
142 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \ 142 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
143 if (! ((m.data (i) != LHS_ZERO) OP (s != RHS_ZERO))) \ 143 if (! ((m.data (i) != LHS_ZERO) OP (s != RHS_ZERO))) \
144 r.data (m.ridx (i) + j * nr) = false; \ 144 r.data (m.ridx (i) + j * nr) = false; \
145 r.maybe_compress (true); \ 145 r.maybe_compress (true); \
146 } \ 146 } \
147 else \ 147 else \
148 { \ 148 { \
149 r = SparseBoolMatrix (nr, nc, m.nnz ()); \ 149 r = SparseBoolMatrix (nr, nc, m.nnz ()); \
150 r.cidx (0) = static_cast<octave_idx_type> (0); \ 150 r.cidx (0) = static_cast<octave_idx_type> (0); \
151 octave_idx_type nel = 0; \ 151 octave_idx_type nel = 0; \
152 for (octave_idx_type j = 0; j < nc; j++) \ 152 for (octave_idx_type j = 0; j < nc; j++) \
153 { \ 153 { \
154 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \ 154 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
155 if ((m.data (i) != LHS_ZERO) OP (s != RHS_ZERO)) \ 155 if ((m.data (i) != LHS_ZERO) OP (s != RHS_ZERO)) \
156 { \ 156 { \
157 r.ridx (nel) = m.ridx (i); \ 157 r.ridx (nel) = m.ridx (i); \
158 r.data (nel++) = true; \ 158 r.data (nel++) = true; \
159 } \ 159 } \
160 r.cidx (j + 1) = nel; \ 160 r.cidx (j + 1) = nel; \
161 } \ 161 } \
162 r.maybe_compress (false); \ 162 r.maybe_compress (false); \
163 } \ 163 } \
164 } \ 164 } \
165 return r; \ 165 return r; \
166 } 166 }
167 167
168 #define SPARSE_SMS_BOOL_OPS2(M, S, LHS_ZERO, RHS_ZERO) \ 168 #define SPARSE_SMS_BOOL_OPS2(M, S, LHS_ZERO, RHS_ZERO) \
169 SPARSE_SMS_BOOL_OP (mx_el_and, &&, M, S, LHS_ZERO, RHS_ZERO) \ 169 SPARSE_SMS_BOOL_OP (mx_el_and, &&, M, S, LHS_ZERO, RHS_ZERO) \
170 SPARSE_SMS_BOOL_OP (mx_el_or, ||, M, S, LHS_ZERO, RHS_ZERO) 170 SPARSE_SMS_BOOL_OP (mx_el_or, ||, M, S, LHS_ZERO, RHS_ZERO)
171 171
172 #define SPARSE_SMS_BOOL_OPS(M, S, ZERO) \ 172 #define SPARSE_SMS_BOOL_OPS(M, S, ZERO) \
173 SPARSE_SMS_BOOL_OPS2(M, S, ZERO, ZERO) 173 SPARSE_SMS_BOOL_OPS2(M, S, ZERO, ZERO)
174 174
175 // scalar by sparse matrix operations. 175 // scalar by sparse matrix operations.
176 176
177 #define SPARSE_SSM_BIN_OP_1(R, F, OP, S, M) \ 177 #define SPARSE_SSM_BIN_OP_1(R, F, OP, S, M) \
178 R \ 178 R \
179 F (const S& s, const M& m) \ 179 F (const S& s, const M& m) \
180 { \ 180 { \
181 octave_idx_type nr = m.rows (); \ 181 octave_idx_type nr = m.rows (); \
182 octave_idx_type nc = m.cols (); \ 182 octave_idx_type nc = m.cols (); \
183 \ 183 \
184 R r (nr, nc, (s OP 0.0)); \ 184 R r (nr, nc, (s OP 0.0)); \
185 \ 185 \
186 for (octave_idx_type j = 0; j < nc; j++) \ 186 for (octave_idx_type j = 0; j < nc; j++) \
187 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \ 187 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
188 r.xelem (m.ridx (i), j) = s OP m.data (i); \ 188 r.xelem (m.ridx (i), j) = s OP m.data (i); \
189 \ 189 \
190 return r; \ 190 return r; \
191 } 191 }
192 192
193 #define SPARSE_SSM_BIN_OP_2(R, F, OP, S, M) \ 193 #define SPARSE_SSM_BIN_OP_2(R, F, OP, S, M) \
194 R \ 194 R \
195 F (const S& s, const M& m) \ 195 F (const S& s, const M& m) \
196 { \ 196 { \
197 octave_idx_type nr = m.rows (); \ 197 octave_idx_type nr = m.rows (); \
198 octave_idx_type nc = m.cols (); \ 198 octave_idx_type nc = m.cols (); \
199 octave_idx_type nz = m.nnz (); \ 199 octave_idx_type nz = m.nnz (); \
200 \ 200 \
201 R r (nr, nc, nz); \ 201 R r (nr, nc, nz); \
202 \ 202 \
203 for (octave_idx_type i = 0; i < nz; i++) \ 203 for (octave_idx_type i = 0; i < nz; i++) \
204 { \ 204 { \
205 r.xdata (i) = s OP m.data (i); \ 205 r.xdata (i) = s OP m.data (i); \
206 r.xridx (i) = m.ridx (i); \ 206 r.xridx (i) = m.ridx (i); \
207 } \ 207 } \
208 for (octave_idx_type i = 0; i < nc + 1; i++) \ 208 for (octave_idx_type i = 0; i < nc + 1; i++) \
209 r.xcidx (i) = m.cidx (i); \ 209 r.xcidx (i) = m.cidx (i); \
210 \ 210 \
211 r.maybe_compress(true); \ 211 r.maybe_compress(true); \
212 return r; \ 212 return r; \
213 } 213 }
214 214
215 #define SPARSE_SSM_BIN_OPS(R1, R2, S, M) \ 215 #define SPARSE_SSM_BIN_OPS(R1, R2, S, M) \
216 SPARSE_SSM_BIN_OP_1 (R1, operator +, +, S, M) \ 216 SPARSE_SSM_BIN_OP_1 (R1, operator +, +, S, M) \
217 SPARSE_SSM_BIN_OP_1 (R1, operator -, -, S, M) \ 217 SPARSE_SSM_BIN_OP_1 (R1, operator -, -, S, M) \
218 SPARSE_SSM_BIN_OP_2 (R2, operator *, *, S, M) \ 218 SPARSE_SSM_BIN_OP_2 (R2, operator *, *, S, M) \
219 SPARSE_SSM_BIN_OP_2 (R2, operator /, /, S, M) 219 SPARSE_SSM_BIN_OP_2 (R2, operator /, /, S, M)
220 220
221 #define SPARSE_SSM_CMP_OP(F, OP, S, SZ, SC, M, MZ, MC) \ 221 #define SPARSE_SSM_CMP_OP(F, OP, S, SZ, SC, M, MZ, MC) \
222 SparseBoolMatrix \ 222 SparseBoolMatrix \
223 F (const S& s, const M& m) \ 223 F (const S& s, const M& m) \
224 { \ 224 { \
225 octave_idx_type nr = m.rows (); \ 225 octave_idx_type nr = m.rows (); \
226 octave_idx_type nc = m.cols (); \ 226 octave_idx_type nc = m.cols (); \
227 SparseBoolMatrix r; \ 227 SparseBoolMatrix r; \
228 \ 228 \
229 if (SC (s) OP SC (MZ)) \ 229 if (SC (s) OP SC (MZ)) \
230 { \ 230 { \
231 r = SparseBoolMatrix (nr, nc, true); \ 231 r = SparseBoolMatrix (nr, nc, true); \
232 for (octave_idx_type j = 0; j < nc; j++) \ 232 for (octave_idx_type j = 0; j < nc; j++) \
233 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \ 233 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
234 if (! (SC (s) OP MC (m.data (i)))) \ 234 if (! (SC (s) OP MC (m.data (i)))) \
235 r.data (m.ridx (i) + j * nr) = false; \ 235 r.data (m.ridx (i) + j * nr) = false; \
236 r.maybe_compress (true); \ 236 r.maybe_compress (true); \
237 } \ 237 } \
238 else \ 238 else \
239 { \ 239 { \
240 r = SparseBoolMatrix (nr, nc, m.nnz ()); \ 240 r = SparseBoolMatrix (nr, nc, m.nnz ()); \
241 r.cidx (0) = static_cast<octave_idx_type> (0); \ 241 r.cidx (0) = static_cast<octave_idx_type> (0); \
242 octave_idx_type nel = 0; \ 242 octave_idx_type nel = 0; \
243 for (octave_idx_type j = 0; j < nc; j++) \ 243 for (octave_idx_type j = 0; j < nc; j++) \
244 { \ 244 { \
245 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \ 245 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
246 if (SC (s) OP MC (m.data (i))) \ 246 if (SC (s) OP MC (m.data (i))) \
247 { \ 247 { \
248 r.ridx (nel) = m.ridx (i); \ 248 r.ridx (nel) = m.ridx (i); \
249 r.data (nel++) = true; \ 249 r.data (nel++) = true; \
250 } \ 250 } \
251 r.cidx (j + 1) = nel; \ 251 r.cidx (j + 1) = nel; \
252 } \ 252 } \
253 r.maybe_compress (false); \ 253 r.maybe_compress (false); \
254 } \ 254 } \
255 return r; \ 255 return r; \
256 } 256 }
257 257
258 #define SPARSE_SSM_CMP_OPS(S, SZ, SC, M, MZ, MC) \ 258 #define SPARSE_SSM_CMP_OPS(S, SZ, SC, M, MZ, MC) \
259 SPARSE_SSM_CMP_OP (mx_el_lt, <, S, SZ, , M, MZ, ) \ 259 SPARSE_SSM_CMP_OP (mx_el_lt, <, S, SZ, , M, MZ, ) \
260 SPARSE_SSM_CMP_OP (mx_el_le, <=, S, SZ, , M, MZ, ) \ 260 SPARSE_SSM_CMP_OP (mx_el_le, <=, S, SZ, , M, MZ, ) \
261 SPARSE_SSM_CMP_OP (mx_el_ge, >=, S, SZ, , M, MZ, ) \ 261 SPARSE_SSM_CMP_OP (mx_el_ge, >=, S, SZ, , M, MZ, ) \
262 SPARSE_SSM_CMP_OP (mx_el_gt, >, S, SZ, , M, MZ, ) \ 262 SPARSE_SSM_CMP_OP (mx_el_gt, >, S, SZ, , M, MZ, ) \
263 SPARSE_SSM_CMP_OP (mx_el_eq, ==, S, SZ, , M, MZ, ) \ 263 SPARSE_SSM_CMP_OP (mx_el_eq, ==, S, SZ, , M, MZ, ) \
264 SPARSE_SSM_CMP_OP (mx_el_ne, !=, S, SZ, , M, MZ, ) 264 SPARSE_SSM_CMP_OP (mx_el_ne, !=, S, SZ, , M, MZ, )
265 265
266 #define SPARSE_SSM_EQNE_OPS(S, SZ, SC, M, MZ, MC) \ 266 #define SPARSE_SSM_EQNE_OPS(S, SZ, SC, M, MZ, MC) \
267 SPARSE_SSM_CMP_OP (mx_el_eq, ==, S, SZ, , M, MZ, ) \ 267 SPARSE_SSM_CMP_OP (mx_el_eq, ==, S, SZ, , M, MZ, ) \
268 SPARSE_SSM_CMP_OP (mx_el_ne, !=, S, SZ, , M, MZ, ) 268 SPARSE_SSM_CMP_OP (mx_el_ne, !=, S, SZ, , M, MZ, )
269 269
270 #define SPARSE_SSM_BOOL_OP(F, OP, S, M, LHS_ZERO, RHS_ZERO) \ 270 #define SPARSE_SSM_BOOL_OP(F, OP, S, M, LHS_ZERO, RHS_ZERO) \
271 SparseBoolMatrix \ 271 SparseBoolMatrix \
272 F (const S& s, const M& m) \ 272 F (const S& s, const M& m) \
273 { \ 273 { \
274 octave_idx_type nr = m.rows (); \ 274 octave_idx_type nr = m.rows (); \
275 octave_idx_type nc = m.cols (); \ 275 octave_idx_type nc = m.cols (); \
276 SparseBoolMatrix r; \ 276 SparseBoolMatrix r; \
277 \ 277 \
278 if (nr > 0 && nc > 0) \ 278 if (nr > 0 && nc > 0) \
279 { \ 279 { \
280 if ((s != LHS_ZERO) OP RHS_ZERO) \ 280 if ((s != LHS_ZERO) OP RHS_ZERO) \
281 { \ 281 { \
282 r = SparseBoolMatrix (nr, nc, true); \ 282 r = SparseBoolMatrix (nr, nc, true); \
283 for (octave_idx_type j = 0; j < nc; j++) \ 283 for (octave_idx_type j = 0; j < nc; j++) \
284 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \ 284 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
285 if (! ((s != LHS_ZERO) OP (m.data (i) != RHS_ZERO))) \ 285 if (! ((s != LHS_ZERO) OP (m.data (i) != RHS_ZERO))) \
286 r.data (m.ridx (i) + j * nr) = false; \ 286 r.data (m.ridx (i) + j * nr) = false; \
287 r.maybe_compress (true); \ 287 r.maybe_compress (true); \
288 } \ 288 } \
289 else \ 289 else \
290 { \ 290 { \
291 r = SparseBoolMatrix (nr, nc, m.nnz ()); \ 291 r = SparseBoolMatrix (nr, nc, m.nnz ()); \
292 r.cidx (0) = static_cast<octave_idx_type> (0); \ 292 r.cidx (0) = static_cast<octave_idx_type> (0); \
293 octave_idx_type nel = 0; \ 293 octave_idx_type nel = 0; \
294 for (octave_idx_type j = 0; j < nc; j++) \ 294 for (octave_idx_type j = 0; j < nc; j++) \
295 { \ 295 { \
296 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \ 296 for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) \
297 if ((s != LHS_ZERO) OP (m.data (i) != RHS_ZERO)) \ 297 if ((s != LHS_ZERO) OP (m.data (i) != RHS_ZERO)) \
298 { \ 298 { \
299 r.ridx (nel) = m.ridx (i); \ 299 r.ridx (nel) = m.ridx (i); \
300 r.data (nel++) = true; \ 300 r.data (nel++) = true; \
301 } \ 301 } \
302 r.cidx (j + 1) = nel; \ 302 r.cidx (j + 1) = nel; \
303 } \ 303 } \
304 r.maybe_compress (false); \ 304 r.maybe_compress (false); \
305 } \ 305 } \
306 } \ 306 } \
307 return r; \ 307 return r; \
308 } 308 }
309 309
310 #define SPARSE_SSM_BOOL_OPS2(S, M, LHS_ZERO, RHS_ZERO) \ 310 #define SPARSE_SSM_BOOL_OPS2(S, M, LHS_ZERO, RHS_ZERO) \
311 SPARSE_SSM_BOOL_OP (mx_el_and, &&, S, M, LHS_ZERO, RHS_ZERO) \ 311 SPARSE_SSM_BOOL_OP (mx_el_and, &&, S, M, LHS_ZERO, RHS_ZERO) \
312 SPARSE_SSM_BOOL_OP (mx_el_or, ||, S, M, LHS_ZERO, RHS_ZERO) 312 SPARSE_SSM_BOOL_OP (mx_el_or, ||, S, M, LHS_ZERO, RHS_ZERO)
313 313
314 #define SPARSE_SSM_BOOL_OPS(S, M, ZERO) \ 314 #define SPARSE_SSM_BOOL_OPS(S, M, ZERO) \
315 SPARSE_SSM_BOOL_OPS2(S, M, ZERO, ZERO) 315 SPARSE_SSM_BOOL_OPS2(S, M, ZERO, ZERO)
316 316
317 // sparse matrix by sparse matrix operations. 317 // sparse matrix by sparse matrix operations.
318 318
319 #define SPARSE_SMSM_BIN_OP_1(R, F, OP, M1, M2) \ 319 #define SPARSE_SMSM_BIN_OP_1(R, F, OP, M1, M2) \
320 R \ 320 R \
321 F (const M1& m1, const M2& m2) \ 321 F (const M1& m1, const M2& m2) \
322 { \ 322 { \
323 R r; \ 323 R r; \
324 \ 324 \
325 octave_idx_type m1_nr = m1.rows (); \ 325 octave_idx_type m1_nr = m1.rows (); \
326 octave_idx_type m1_nc = m1.cols (); \ 326 octave_idx_type m1_nc = m1.cols (); \
327 \ 327 \
328 octave_idx_type m2_nr = m2.rows (); \ 328 octave_idx_type m2_nr = m2.rows (); \
329 octave_idx_type m2_nc = m2.cols (); \ 329 octave_idx_type m2_nc = m2.cols (); \
330 \ 330 \
331 if (m1_nr == 1 && m1_nc == 1) \ 331 if (m1_nr == 1 && m1_nc == 1) \
332 { \ 332 { \
333 if (m1.elem (0,0) == 0.) \ 333 if (m1.elem (0,0) == 0.) \
334 r = OP R (m2); \ 334 r = OP R (m2); \
335 else \ 335 else \
336 { \ 336 { \
337 r = R (m2_nr, m2_nc, m1.data (0) OP 0.); \ 337 r = R (m2_nr, m2_nc, m1.data (0) OP 0.); \
338 \ 338 \
339 for (octave_idx_type j = 0 ; j < m2_nc ; j++) \ 339 for (octave_idx_type j = 0 ; j < m2_nc ; j++) \
340 { \ 340 { \
341 octave_quit (); \ 341 octave_quit (); \
342 octave_idx_type idxj = j * m2_nr; \ 342 octave_idx_type idxj = j * m2_nr; \
343 for (octave_idx_type i = m2.cidx (j) ; i < m2.cidx (j+1) ; i++) \ 343 for (octave_idx_type i = m2.cidx (j) ; i < m2.cidx (j+1) ; i++) \
344 { \ 344 { \
345 octave_quit (); \ 345 octave_quit (); \
346 r.data (idxj + m2.ridx (i)) = m1.data (0) OP m2.data (i); \ 346 r.data (idxj + m2.ridx (i)) = m1.data (0) OP m2.data (i); \
347 } \ 347 } \
348 } \ 348 } \
349 r.maybe_compress (); \ 349 r.maybe_compress (); \
350 } \ 350 } \
351 } \ 351 } \
352 else if (m2_nr == 1 && m2_nc == 1) \ 352 else if (m2_nr == 1 && m2_nc == 1) \
353 { \ 353 { \
354 if (m2.elem (0,0) == 0.) \ 354 if (m2.elem (0,0) == 0.) \
355 r = R (m1); \ 355 r = R (m1); \
356 else \ 356 else \
357 { \ 357 { \
358 r = R (m1_nr, m1_nc, 0. OP m2.data (0)); \ 358 r = R (m1_nr, m1_nc, 0. OP m2.data (0)); \
359 \ 359 \
360 for (octave_idx_type j = 0 ; j < m1_nc ; j++) \ 360 for (octave_idx_type j = 0 ; j < m1_nc ; j++) \
361 { \ 361 { \
362 octave_quit (); \ 362 octave_quit (); \
363 octave_idx_type idxj = j * m1_nr; \ 363 octave_idx_type idxj = j * m1_nr; \
364 for (octave_idx_type i = m1.cidx (j) ; i < m1.cidx (j+1) ; i++) \ 364 for (octave_idx_type i = m1.cidx (j) ; i < m1.cidx (j+1) ; i++) \
365 { \ 365 { \
366 octave_quit (); \ 366 octave_quit (); \
367 r.data (idxj + m1.ridx (i)) = m1.data (i) OP m2.data (0); \ 367 r.data (idxj + m1.ridx (i)) = m1.data (i) OP m2.data (0); \
368 } \ 368 } \
369 } \ 369 } \
370 r.maybe_compress (); \ 370 r.maybe_compress (); \
371 } \ 371 } \
372 } \ 372 } \
373 else if (m1_nr != m2_nr || m1_nc != m2_nc) \ 373 else if (m1_nr != m2_nr || m1_nc != m2_nc) \
374 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \ 374 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \
375 else \ 375 else \
376 { \ 376 { \
377 r = R (m1_nr, m1_nc, (m1.nnz () + m2.nnz ())); \ 377 r = R (m1_nr, m1_nc, (m1.nnz () + m2.nnz ())); \
378 \ 378 \
379 octave_idx_type jx = 0; \ 379 octave_idx_type jx = 0; \
380 r.cidx (0) = 0; \ 380 r.cidx (0) = 0; \
381 for (octave_idx_type i = 0 ; i < m1_nc ; i++) \ 381 for (octave_idx_type i = 0 ; i < m1_nc ; i++) \
382 { \ 382 { \
383 octave_idx_type ja = m1.cidx (i); \ 383 octave_idx_type ja = m1.cidx (i); \
384 octave_idx_type ja_max = m1.cidx (i+1); \ 384 octave_idx_type ja_max = m1.cidx (i+1); \
385 bool ja_lt_max = ja < ja_max; \ 385 bool ja_lt_max = ja < ja_max; \
386 \ 386 \
387 octave_idx_type jb = m2.cidx (i); \ 387 octave_idx_type jb = m2.cidx (i); \
388 octave_idx_type jb_max = m2.cidx (i+1); \ 388 octave_idx_type jb_max = m2.cidx (i+1); \
389 bool jb_lt_max = jb < jb_max; \ 389 bool jb_lt_max = jb < jb_max; \
390 \ 390 \
391 while (ja_lt_max || jb_lt_max) \ 391 while (ja_lt_max || jb_lt_max) \
392 { \ 392 { \
393 octave_quit (); \ 393 octave_quit (); \
394 if ((! jb_lt_max) || \ 394 if ((! jb_lt_max) || \
395 (ja_lt_max && (m1.ridx (ja) < m2.ridx (jb)))) \ 395 (ja_lt_max && (m1.ridx (ja) < m2.ridx (jb)))) \
396 { \ 396 { \
397 r.ridx (jx) = m1.ridx (ja); \ 397 r.ridx (jx) = m1.ridx (ja); \
398 r.data (jx) = m1.data (ja) OP 0.; \ 398 r.data (jx) = m1.data (ja) OP 0.; \
399 jx++; \ 399 jx++; \
400 ja++; \ 400 ja++; \
401 ja_lt_max= ja < ja_max; \ 401 ja_lt_max= ja < ja_max; \
402 } \ 402 } \
403 else if ((! ja_lt_max) || \ 403 else if ((! ja_lt_max) || \
404 (jb_lt_max && (m2.ridx (jb) < m1.ridx (ja)))) \ 404 (jb_lt_max && (m2.ridx (jb) < m1.ridx (ja)))) \
405 { \ 405 { \
406 r.ridx (jx) = m2.ridx (jb); \ 406 r.ridx (jx) = m2.ridx (jb); \
407 r.data (jx) = 0. OP m2.data (jb); \ 407 r.data (jx) = 0. OP m2.data (jb); \
408 jx++; \ 408 jx++; \
409 jb++; \ 409 jb++; \
410 jb_lt_max= jb < jb_max; \ 410 jb_lt_max= jb < jb_max; \
411 } \ 411 } \
412 else \ 412 else \
413 { \ 413 { \
414 if ((m1.data (ja) OP m2.data (jb)) != 0.) \ 414 if ((m1.data (ja) OP m2.data (jb)) != 0.) \
415 { \ 415 { \
416 r.data (jx) = m1.data (ja) OP m2.data (jb); \ 416 r.data (jx) = m1.data (ja) OP m2.data (jb); \
417 r.ridx (jx) = m1.ridx (ja); \ 417 r.ridx (jx) = m1.ridx (ja); \
418 jx++; \ 418 jx++; \
419 } \ 419 } \
420 ja++; \ 420 ja++; \
421 ja_lt_max= ja < ja_max; \ 421 ja_lt_max= ja < ja_max; \
422 jb++; \ 422 jb++; \
423 jb_lt_max= jb < jb_max; \ 423 jb_lt_max= jb < jb_max; \
424 } \ 424 } \
425 } \ 425 } \
426 r.cidx (i+1) = jx; \ 426 r.cidx (i+1) = jx; \
427 } \ 427 } \
428 \ 428 \
429 r.maybe_compress (); \ 429 r.maybe_compress (); \
430 } \ 430 } \
431 \ 431 \
432 return r; \ 432 return r; \
433 } 433 }
434 434
435 #define SPARSE_SMSM_BIN_OP_2(R, F, OP, M1, M2) \ 435 #define SPARSE_SMSM_BIN_OP_2(R, F, OP, M1, M2) \
436 R \ 436 R \
437 F (const M1& m1, const M2& m2) \ 437 F (const M1& m1, const M2& m2) \
438 { \ 438 { \
439 R r; \ 439 R r; \
440 \ 440 \
441 octave_idx_type m1_nr = m1.rows (); \ 441 octave_idx_type m1_nr = m1.rows (); \
442 octave_idx_type m1_nc = m1.cols (); \ 442 octave_idx_type m1_nc = m1.cols (); \
443 \ 443 \
444 octave_idx_type m2_nr = m2.rows (); \ 444 octave_idx_type m2_nr = m2.rows (); \
445 octave_idx_type m2_nc = m2.cols (); \ 445 octave_idx_type m2_nc = m2.cols (); \
446 \ 446 \
447 if (m1_nr == 1 && m1_nc == 1) \ 447 if (m1_nr == 1 && m1_nc == 1) \
448 { \ 448 { \
449 if (m1.elem (0,0) == 0.) \ 449 if (m1.elem (0,0) == 0.) \
450 r = R (m2_nr, m2_nc); \ 450 r = R (m2_nr, m2_nc); \
451 else \ 451 else \
452 { \ 452 { \
453 r = R (m2); \ 453 r = R (m2); \
454 octave_idx_type m2_nnz = m2.nnz (); \ 454 octave_idx_type m2_nnz = m2.nnz (); \
455 \ 455 \
456 for (octave_idx_type i = 0 ; i < m2_nnz ; i++) \ 456 for (octave_idx_type i = 0 ; i < m2_nnz ; i++) \
457 { \ 457 { \
458 octave_quit (); \ 458 octave_quit (); \
459 r.data (i) = m1.data (0) OP r.data (i); \ 459 r.data (i) = m1.data (0) OP r.data (i); \
460 } \ 460 } \
461 r.maybe_compress (); \ 461 r.maybe_compress (); \
462 } \ 462 } \
463 } \ 463 } \
464 else if (m2_nr == 1 && m2_nc == 1) \ 464 else if (m2_nr == 1 && m2_nc == 1) \
465 { \ 465 { \
466 if (m2.elem (0,0) == 0.) \ 466 if (m2.elem (0,0) == 0.) \
467 r = R (m1_nr, m1_nc); \ 467 r = R (m1_nr, m1_nc); \
468 else \ 468 else \
469 { \ 469 { \
470 r = R (m1); \ 470 r = R (m1); \
471 octave_idx_type m1_nnz = m1.nnz (); \ 471 octave_idx_type m1_nnz = m1.nnz (); \
472 \ 472 \
473 for (octave_idx_type i = 0 ; i < m1_nnz ; i++) \ 473 for (octave_idx_type i = 0 ; i < m1_nnz ; i++) \
474 { \ 474 { \
475 octave_quit (); \ 475 octave_quit (); \
476 r.data (i) = r.data (i) OP m2.data (0); \ 476 r.data (i) = r.data (i) OP m2.data (0); \
477 } \ 477 } \
478 r.maybe_compress (); \ 478 r.maybe_compress (); \
479 } \ 479 } \
480 } \ 480 } \
481 else if (m1_nr != m2_nr || m1_nc != m2_nc) \ 481 else if (m1_nr != m2_nr || m1_nc != m2_nc) \
482 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \ 482 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \
483 else \ 483 else \
484 { \ 484 { \
485 r = R (m1_nr, m1_nc, (m1.nnz () > m2.nnz () ? m1.nnz () : m2.nnz ())); \ 485 r = R (m1_nr, m1_nc, (m1.nnz () > m2.nnz () ? m1.nnz () : m2.nnz ())); \
486 \ 486 \
487 octave_idx_type jx = 0; \ 487 octave_idx_type jx = 0; \
488 r.cidx (0) = 0; \ 488 r.cidx (0) = 0; \
489 for (octave_idx_type i = 0 ; i < m1_nc ; i++) \ 489 for (octave_idx_type i = 0 ; i < m1_nc ; i++) \
490 { \ 490 { \
491 octave_idx_type ja = m1.cidx (i); \ 491 octave_idx_type ja = m1.cidx (i); \
492 octave_idx_type ja_max = m1.cidx (i+1); \ 492 octave_idx_type ja_max = m1.cidx (i+1); \
493 bool ja_lt_max = ja < ja_max; \ 493 bool ja_lt_max = ja < ja_max; \
494 \ 494 \
495 octave_idx_type jb = m2.cidx (i); \ 495 octave_idx_type jb = m2.cidx (i); \
496 octave_idx_type jb_max = m2.cidx (i+1); \ 496 octave_idx_type jb_max = m2.cidx (i+1); \
497 bool jb_lt_max = jb < jb_max; \ 497 bool jb_lt_max = jb < jb_max; \
498 \ 498 \
499 while (ja_lt_max || jb_lt_max) \ 499 while (ja_lt_max || jb_lt_max) \
500 { \ 500 { \
501 octave_quit (); \ 501 octave_quit (); \
502 if ((! jb_lt_max) || \ 502 if ((! jb_lt_max) || \
503 (ja_lt_max && (m1.ridx (ja) < m2.ridx (jb)))) \ 503 (ja_lt_max && (m1.ridx (ja) < m2.ridx (jb)))) \
504 { \ 504 { \
505 ja++; ja_lt_max= ja < ja_max; \ 505 ja++; ja_lt_max= ja < ja_max; \
506 } \ 506 } \
507 else if ((! ja_lt_max) || \ 507 else if ((! ja_lt_max) || \
508 (jb_lt_max && (m2.ridx (jb) < m1.ridx (ja)))) \ 508 (jb_lt_max && (m2.ridx (jb) < m1.ridx (ja)))) \
509 { \ 509 { \
510 jb++; jb_lt_max= jb < jb_max; \ 510 jb++; jb_lt_max= jb < jb_max; \
511 } \ 511 } \
512 else \ 512 else \
513 { \ 513 { \
514 if ((m1.data (ja) OP m2.data (jb)) != 0.) \ 514 if ((m1.data (ja) OP m2.data (jb)) != 0.) \
515 { \ 515 { \
516 r.data (jx) = m1.data (ja) OP m2.data (jb); \ 516 r.data (jx) = m1.data (ja) OP m2.data (jb); \
517 r.ridx (jx) = m1.ridx (ja); \ 517 r.ridx (jx) = m1.ridx (ja); \
518 jx++; \ 518 jx++; \
519 } \ 519 } \
520 ja++; ja_lt_max= ja < ja_max; \ 520 ja++; ja_lt_max= ja < ja_max; \
521 jb++; jb_lt_max= jb < jb_max; \ 521 jb++; jb_lt_max= jb < jb_max; \
522 } \ 522 } \
523 } \ 523 } \
524 r.cidx (i+1) = jx; \ 524 r.cidx (i+1) = jx; \
525 } \ 525 } \
526 \ 526 \
527 r.maybe_compress (); \ 527 r.maybe_compress (); \
528 } \ 528 } \
529 \ 529 \
530 return r; \ 530 return r; \
531 } 531 }
532 532
533 #define SPARSE_SMSM_BIN_OP_3(R, F, OP, M1, M2) \ 533 #define SPARSE_SMSM_BIN_OP_3(R, F, OP, M1, M2) \
534 R \ 534 R \
535 F (const M1& m1, const M2& m2) \ 535 F (const M1& m1, const M2& m2) \
536 { \ 536 { \
537 R r; \ 537 R r; \
538 \ 538 \
539 octave_idx_type m1_nr = m1.rows (); \ 539 octave_idx_type m1_nr = m1.rows (); \
540 octave_idx_type m1_nc = m1.cols (); \ 540 octave_idx_type m1_nc = m1.cols (); \
541 \ 541 \
542 octave_idx_type m2_nr = m2.rows (); \ 542 octave_idx_type m2_nr = m2.rows (); \
543 octave_idx_type m2_nc = m2.cols (); \ 543 octave_idx_type m2_nc = m2.cols (); \
544 \ 544 \
545 if (m1_nr == 1 && m1_nc == 1) \ 545 if (m1_nr == 1 && m1_nc == 1) \
546 { \ 546 { \
547 if ((m1.elem (0,0) OP Complex ()) == Complex ()) \ 547 if ((m1.elem (0,0) OP Complex ()) == Complex ()) \
548 { \ 548 { \
549 octave_idx_type m2_nnz = m2.nnz (); \ 549 octave_idx_type m2_nnz = m2.nnz (); \
550 r = R (m2); \ 550 r = R (m2); \
551 for (octave_idx_type i = 0 ; i < m2_nnz ; i++) \ 551 for (octave_idx_type i = 0 ; i < m2_nnz ; i++) \
552 r.data (i) = m1.elem (0,0) OP r.data (i); \ 552 r.data (i) = m1.elem (0,0) OP r.data (i); \
553 r.maybe_compress (); \ 553 r.maybe_compress (); \
554 } \ 554 } \
555 else \ 555 else \
556 { \ 556 { \
557 r = R (m2_nr, m2_nc, m1.elem (0,0) OP Complex ()); \ 557 r = R (m2_nr, m2_nc, m1.elem (0,0) OP Complex ()); \
558 for (octave_idx_type j = 0 ; j < m2_nc ; j++) \ 558 for (octave_idx_type j = 0 ; j < m2_nc ; j++) \
559 { \ 559 { \
560 octave_quit (); \ 560 octave_quit (); \
561 octave_idx_type idxj = j * m2_nr; \ 561 octave_idx_type idxj = j * m2_nr; \
562 for (octave_idx_type i = m2.cidx (j) ; i < m2.cidx (j+1) ; i++) \ 562 for (octave_idx_type i = m2.cidx (j) ; i < m2.cidx (j+1) ; i++) \
563 { \ 563 { \
564 octave_quit (); \ 564 octave_quit (); \
565 r.data (idxj + m2.ridx (i)) = m1.elem (0,0) OP m2.data (i); \ 565 r.data (idxj + m2.ridx (i)) = m1.elem (0,0) OP m2.data (i); \
566 } \ 566 } \
567 } \ 567 } \
568 r.maybe_compress (); \ 568 r.maybe_compress (); \
569 } \ 569 } \
570 } \ 570 } \
571 else if (m2_nr == 1 && m2_nc == 1) \ 571 else if (m2_nr == 1 && m2_nc == 1) \
572 { \ 572 { \
573 if ((Complex () OP m1.elem (0,0)) == Complex ()) \ 573 if ((Complex () OP m1.elem (0,0)) == Complex ()) \
574 { \ 574 { \
575 octave_idx_type m1_nnz = m1.nnz (); \ 575 octave_idx_type m1_nnz = m1.nnz (); \
576 r = R (m1); \ 576 r = R (m1); \
577 for (octave_idx_type i = 0 ; i < m1_nnz ; i++) \ 577 for (octave_idx_type i = 0 ; i < m1_nnz ; i++) \
578 r.data (i) = r.data (i) OP m2.elem (0,0); \ 578 r.data (i) = r.data (i) OP m2.elem (0,0); \
579 r.maybe_compress (); \ 579 r.maybe_compress (); \
580 } \ 580 } \
581 else \ 581 else \
582 { \ 582 { \
583 r = R (m1_nr, m1_nc, Complex () OP m2.elem (0,0)); \ 583 r = R (m1_nr, m1_nc, Complex () OP m2.elem (0,0)); \
584 for (octave_idx_type j = 0 ; j < m1_nc ; j++) \ 584 for (octave_idx_type j = 0 ; j < m1_nc ; j++) \
585 { \ 585 { \
586 octave_quit (); \ 586 octave_quit (); \
587 octave_idx_type idxj = j * m1_nr; \ 587 octave_idx_type idxj = j * m1_nr; \
588 for (octave_idx_type i = m1.cidx (j) ; i < m1.cidx (j+1) ; i++) \ 588 for (octave_idx_type i = m1.cidx (j) ; i < m1.cidx (j+1) ; i++) \
589 { \ 589 { \
590 octave_quit (); \ 590 octave_quit (); \
591 r.data (idxj + m1.ridx (i)) = m1.data (i) OP m2.elem (0,0); \ 591 r.data (idxj + m1.ridx (i)) = m1.data (i) OP m2.elem (0,0); \
592 } \ 592 } \
593 } \ 593 } \
594 r.maybe_compress (); \ 594 r.maybe_compress (); \
595 } \ 595 } \
596 } \ 596 } \
597 else if (m1_nr != m2_nr || m1_nc != m2_nc) \ 597 else if (m1_nr != m2_nr || m1_nc != m2_nc) \
598 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \ 598 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \
599 else \ 599 else \
600 { \ 600 { \
601 \ 601 \
602 /* FIXME: Kludge... Always double/Complex, so Complex () */ \ 602 /* FIXME: Kludge... Always double/Complex, so Complex () */ \
603 r = R (m1_nr, m1_nc, (Complex () OP Complex ())); \ 603 r = R (m1_nr, m1_nc, (Complex () OP Complex ())); \
604 \ 604 \
605 for (octave_idx_type i = 0 ; i < m1_nc ; i++) \ 605 for (octave_idx_type i = 0 ; i < m1_nc ; i++) \
606 { \ 606 { \
607 octave_idx_type ja = m1.cidx (i); \ 607 octave_idx_type ja = m1.cidx (i); \
608 octave_idx_type ja_max = m1.cidx (i+1); \ 608 octave_idx_type ja_max = m1.cidx (i+1); \
609 bool ja_lt_max = ja < ja_max; \ 609 bool ja_lt_max = ja < ja_max; \
610 \ 610 \
611 octave_idx_type jb = m2.cidx (i); \ 611 octave_idx_type jb = m2.cidx (i); \
612 octave_idx_type jb_max = m2.cidx (i+1); \ 612 octave_idx_type jb_max = m2.cidx (i+1); \
613 bool jb_lt_max = jb < jb_max; \ 613 bool jb_lt_max = jb < jb_max; \
614 \ 614 \
615 while (ja_lt_max || jb_lt_max) \ 615 while (ja_lt_max || jb_lt_max) \
616 { \ 616 { \
617 octave_quit (); \ 617 octave_quit (); \
618 if ((! jb_lt_max) || \ 618 if ((! jb_lt_max) || \
619 (ja_lt_max && (m1.ridx (ja) < m2.ridx (jb)))) \ 619 (ja_lt_max && (m1.ridx (ja) < m2.ridx (jb)))) \
620 { \ 620 { \
621 /* keep those kludges coming */ \ 621 /* keep those kludges coming */ \
622 r.elem (m1.ridx (ja),i) = m1.data (ja) OP Complex (); \ 622 r.elem (m1.ridx (ja),i) = m1.data (ja) OP Complex (); \
623 ja++; \ 623 ja++; \
624 ja_lt_max= ja < ja_max; \ 624 ja_lt_max= ja < ja_max; \
625 } \ 625 } \
626 else if ((! ja_lt_max) || \ 626 else if ((! ja_lt_max) || \
627 (jb_lt_max && (m2.ridx (jb) < m1.ridx (ja)))) \ 627 (jb_lt_max && (m2.ridx (jb) < m1.ridx (ja)))) \
628 { \ 628 { \
629 /* keep those kludges coming */ \ 629 /* keep those kludges coming */ \
630 r.elem (m2.ridx (jb),i) = Complex () OP m2.data (jb); \ 630 r.elem (m2.ridx (jb),i) = Complex () OP m2.data (jb); \
631 jb++; \ 631 jb++; \
632 jb_lt_max= jb < jb_max; \ 632 jb_lt_max= jb < jb_max; \
633 } \ 633 } \
634 else \ 634 else \
635 { \ 635 { \
636 r.elem (m1.ridx (ja),i) = m1.data (ja) OP m2.data (jb); \ 636 r.elem (m1.ridx (ja),i) = m1.data (ja) OP m2.data (jb); \
637 ja++; \ 637 ja++; \
638 ja_lt_max= ja < ja_max; \ 638 ja_lt_max= ja < ja_max; \
639 jb++; \ 639 jb++; \
640 jb_lt_max= jb < jb_max; \ 640 jb_lt_max= jb < jb_max; \
641 } \ 641 } \
642 } \ 642 } \
643 } \ 643 } \
644 r.maybe_compress (true); \ 644 r.maybe_compress (true); \
645 } \ 645 } \
646 \ 646 \
647 return r; \ 647 return r; \
648 } 648 }
649 649
650 // Note that SM ./ SM needs to take into account the NaN and Inf values 650 // Note that SM ./ SM needs to take into account the NaN and Inf values
651 // implied by the division by zero. 651 // implied by the division by zero.
652 // FIXME: Are the NaNs double(NaN) or Complex(NaN,Nan) in the complex case? 652 // FIXME: Are the NaNs double(NaN) or Complex(NaN,Nan) in the complex case?
653 #define SPARSE_SMSM_BIN_OPS(R1, R2, M1, M2) \ 653 #define SPARSE_SMSM_BIN_OPS(R1, R2, M1, M2) \
654 SPARSE_SMSM_BIN_OP_1 (R1, operator +, +, M1, M2) \ 654 SPARSE_SMSM_BIN_OP_1 (R1, operator +, +, M1, M2) \
655 SPARSE_SMSM_BIN_OP_1 (R1, operator -, -, M1, M2) \ 655 SPARSE_SMSM_BIN_OP_1 (R1, operator -, -, M1, M2) \
656 SPARSE_SMSM_BIN_OP_2 (R2, product, *, M1, M2) \ 656 SPARSE_SMSM_BIN_OP_2 (R2, product, *, M1, M2) \
657 SPARSE_SMSM_BIN_OP_3 (R2, quotient, /, M1, M2) 657 SPARSE_SMSM_BIN_OP_3 (R2, quotient, /, M1, M2)
658 658
659 // FIXME: this macro duplicates the bodies of the template functions 659 // FIXME: this macro duplicates the bodies of the template functions
660 // defined in the SPARSE_SSM_CMP_OP and SPARSE_SMS_CMP_OP macros. 660 // defined in the SPARSE_SSM_CMP_OP and SPARSE_SMS_CMP_OP macros.
661 661
662 #define SPARSE_SMSM_CMP_OP(F, OP, M1, Z1, C1, M2, Z2, C2) \ 662 #define SPARSE_SMSM_CMP_OP(F, OP, M1, Z1, C1, M2, Z2, C2) \
663 SparseBoolMatrix \ 663 SparseBoolMatrix \
664 F (const M1& m1, const M2& m2) \ 664 F (const M1& m1, const M2& m2) \
665 { \ 665 { \
666 SparseBoolMatrix r; \ 666 SparseBoolMatrix r; \
667 \ 667 \
668 octave_idx_type m1_nr = m1.rows (); \ 668 octave_idx_type m1_nr = m1.rows (); \
669 octave_idx_type m1_nc = m1.cols (); \ 669 octave_idx_type m1_nc = m1.cols (); \
670 \ 670 \
671 octave_idx_type m2_nr = m2.rows (); \ 671 octave_idx_type m2_nr = m2.rows (); \
672 octave_idx_type m2_nc = m2.cols (); \ 672 octave_idx_type m2_nc = m2.cols (); \
673 \ 673 \
674 if (m1_nr == 1 && m1_nc == 1) \ 674 if (m1_nr == 1 && m1_nc == 1) \
675 { \ 675 { \
676 if (C1 (m1.elem (0,0)) OP C2 (Z2)) \ 676 if (C1 (m1.elem (0,0)) OP C2 (Z2)) \
677 { \ 677 { \
678 r = SparseBoolMatrix (m2_nr, m2_nc, true); \ 678 r = SparseBoolMatrix (m2_nr, m2_nc, true); \
679 for (octave_idx_type j = 0; j < m2_nc; j++) \ 679 for (octave_idx_type j = 0; j < m2_nc; j++) \
680 for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \ 680 for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \
681 if (! (C1 (m1.elem (0,0)) OP C2 (m2.data (i)))) \ 681 if (! (C1 (m1.elem (0,0)) OP C2 (m2.data (i)))) \
682 r.data (m2.ridx (i) + j * m2_nr) = false; \ 682 r.data (m2.ridx (i) + j * m2_nr) = false; \
683 r.maybe_compress (true); \ 683 r.maybe_compress (true); \
684 } \ 684 } \
685 else \ 685 else \
686 { \ 686 { \
687 r = SparseBoolMatrix (m2_nr, m2_nc, m2.nnz ()); \ 687 r = SparseBoolMatrix (m2_nr, m2_nc, m2.nnz ()); \
688 r.cidx (0) = static_cast<octave_idx_type> (0); \ 688 r.cidx (0) = static_cast<octave_idx_type> (0); \
689 octave_idx_type nel = 0; \ 689 octave_idx_type nel = 0; \
690 for (octave_idx_type j = 0; j < m2_nc; j++) \ 690 for (octave_idx_type j = 0; j < m2_nc; j++) \
691 { \ 691 { \
692 for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \ 692 for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \
693 if (C1 (m1.elem (0,0)) OP C2 (m2.data (i))) \ 693 if (C1 (m1.elem (0,0)) OP C2 (m2.data (i))) \
694 { \ 694 { \
695 r.ridx (nel) = m2.ridx (i); \ 695 r.ridx (nel) = m2.ridx (i); \
696 r.data (nel++) = true; \ 696 r.data (nel++) = true; \
697 } \ 697 } \
698 r.cidx (j + 1) = nel; \ 698 r.cidx (j + 1) = nel; \
699 } \ 699 } \
700 r.maybe_compress (false); \ 700 r.maybe_compress (false); \
701 } \ 701 } \
702 } \ 702 } \
703 else if (m2_nr == 1 && m2_nc == 1) \ 703 else if (m2_nr == 1 && m2_nc == 1) \
704 { \ 704 { \
705 if (C1 (Z1) OP C2 (m2.elem (0,0))) \ 705 if (C1 (Z1) OP C2 (m2.elem (0,0))) \
706 { \ 706 { \
707 r = SparseBoolMatrix (m1_nr, m1_nc, true); \ 707 r = SparseBoolMatrix (m1_nr, m1_nc, true); \
708 for (octave_idx_type j = 0; j < m1_nc; j++) \ 708 for (octave_idx_type j = 0; j < m1_nc; j++) \
709 for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \ 709 for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \
710 if (! (C1 (m1.data (i)) OP C2 (m2.elem (0,0)))) \ 710 if (! (C1 (m1.data (i)) OP C2 (m2.elem (0,0)))) \
711 r.data (m1.ridx (i) + j * m1_nr) = false; \ 711 r.data (m1.ridx (i) + j * m1_nr) = false; \
712 r.maybe_compress (true); \ 712 r.maybe_compress (true); \
713 } \ 713 } \
714 else \ 714 else \
715 { \ 715 { \
716 r = SparseBoolMatrix (m1_nr, m1_nc, m1.nnz ()); \ 716 r = SparseBoolMatrix (m1_nr, m1_nc, m1.nnz ()); \
717 r.cidx (0) = static_cast<octave_idx_type> (0); \ 717 r.cidx (0) = static_cast<octave_idx_type> (0); \
718 octave_idx_type nel = 0; \ 718 octave_idx_type nel = 0; \
719 for (octave_idx_type j = 0; j < m1_nc; j++) \ 719 for (octave_idx_type j = 0; j < m1_nc; j++) \
720 { \ 720 { \
721 for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \ 721 for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \
722 if (C1 (m1.data (i)) OP C2 (m2.elem (0,0))) \ 722 if (C1 (m1.data (i)) OP C2 (m2.elem (0,0))) \
723 { \ 723 { \
724 r.ridx (nel) = m1.ridx (i); \ 724 r.ridx (nel) = m1.ridx (i); \
725 r.data (nel++) = true; \ 725 r.data (nel++) = true; \
726 } \ 726 } \
727 r.cidx (j + 1) = nel; \ 727 r.cidx (j + 1) = nel; \
728 } \ 728 } \
729 r.maybe_compress (false); \ 729 r.maybe_compress (false); \
730 } \ 730 } \
731 } \ 731 } \
732 else if (m1_nr == m2_nr && m1_nc == m2_nc) \ 732 else if (m1_nr == m2_nr && m1_nc == m2_nc) \
733 { \ 733 { \
734 if (m1_nr != 0 || m1_nc != 0) \ 734 if (m1_nr != 0 || m1_nc != 0) \
735 { \ 735 { \
736 if (C1 (Z1) OP C2 (Z2)) \ 736 if (C1 (Z1) OP C2 (Z2)) \
737 { \ 737 { \
738 r = SparseBoolMatrix (m1_nr, m1_nc, true); \ 738 r = SparseBoolMatrix (m1_nr, m1_nc, true); \
739 for (octave_idx_type j = 0; j < m1_nc; j++) \ 739 for (octave_idx_type j = 0; j < m1_nc; j++) \
740 { \ 740 { \
741 octave_idx_type i1 = m1.cidx (j); \ 741 octave_idx_type i1 = m1.cidx (j); \
742 octave_idx_type e1 = m1.cidx (j+1); \ 742 octave_idx_type e1 = m1.cidx (j+1); \
743 octave_idx_type i2 = m2.cidx (j); \ 743 octave_idx_type i2 = m2.cidx (j); \
744 octave_idx_type e2 = m2.cidx (j+1); \ 744 octave_idx_type e2 = m2.cidx (j+1); \
745 while (i1 < e1 || i2 < e2) \ 745 while (i1 < e1 || i2 < e2) \
746 { \ 746 { \
747 if (i1 == e1 || (i2 < e2 && m1.ridx (i1) > m2.ridx (i2))) \ 747 if (i1 == e1 || (i2 < e2 && m1.ridx (i1) > m2.ridx (i2))) \
748 { \ 748 { \
749 if (! (C1 (Z1) OP C2 (m2.data (i2)))) \ 749 if (! (C1 (Z1) OP C2 (m2.data (i2)))) \
750 r.data (m2.ridx (i2) + j * m1_nr) = false; \ 750 r.data (m2.ridx (i2) + j * m1_nr) = false; \
751 i2++; \ 751 i2++; \
752 } \ 752 } \
753 else if (i2 == e2 || m1.ridx (i1) < m2.ridx (i2)) \ 753 else if (i2 == e2 || m1.ridx (i1) < m2.ridx (i2)) \
754 { \ 754 { \
755 if (! (C1 (m1.data (i1)) OP C2 (Z2))) \ 755 if (! (C1 (m1.data (i1)) OP C2 (Z2))) \
756 r.data (m1.ridx (i1) + j * m1_nr) = false; \ 756 r.data (m1.ridx (i1) + j * m1_nr) = false; \
757 i1++; \ 757 i1++; \
758 } \ 758 } \
759 else \ 759 else \
760 { \ 760 { \
761 if (! (C1 (m1.data (i1)) OP C2 (m2.data (i2)))) \ 761 if (! (C1 (m1.data (i1)) OP C2 (m2.data (i2)))) \
762 r.data (m1.ridx (i1) + j * m1_nr) = false; \ 762 r.data (m1.ridx (i1) + j * m1_nr) = false; \
763 i1++; \ 763 i1++; \
764 i2++; \ 764 i2++; \
765 } \ 765 } \
766 } \ 766 } \
767 } \ 767 } \
768 r.maybe_compress (true); \ 768 r.maybe_compress (true); \
769 } \ 769 } \
770 else \ 770 else \
771 { \ 771 { \
772 r = SparseBoolMatrix (m1_nr, m1_nc, m1.nnz () + m2.nnz ()); \ 772 r = SparseBoolMatrix (m1_nr, m1_nc, m1.nnz () + m2.nnz ()); \
773 r.cidx (0) = static_cast<octave_idx_type> (0); \ 773 r.cidx (0) = static_cast<octave_idx_type> (0); \
774 octave_idx_type nel = 0; \ 774 octave_idx_type nel = 0; \
775 for (octave_idx_type j = 0; j < m1_nc; j++) \ 775 for (octave_idx_type j = 0; j < m1_nc; j++) \
776 { \ 776 { \
777 octave_idx_type i1 = m1.cidx (j); \ 777 octave_idx_type i1 = m1.cidx (j); \
778 octave_idx_type e1 = m1.cidx (j+1); \ 778 octave_idx_type e1 = m1.cidx (j+1); \
779 octave_idx_type i2 = m2.cidx (j); \ 779 octave_idx_type i2 = m2.cidx (j); \
780 octave_idx_type e2 = m2.cidx (j+1); \ 780 octave_idx_type e2 = m2.cidx (j+1); \
781 while (i1 < e1 || i2 < e2) \ 781 while (i1 < e1 || i2 < e2) \
782 { \ 782 { \
783 if (i1 == e1 || (i2 < e2 && m1.ridx (i1) > m2.ridx (i2))) \ 783 if (i1 == e1 || (i2 < e2 && m1.ridx (i1) > m2.ridx (i2))) \
784 { \ 784 { \
785 if (C1 (Z1) OP C2 (m2.data (i2))) \ 785 if (C1 (Z1) OP C2 (m2.data (i2))) \
786 { \ 786 { \
787 r.ridx (nel) = m2.ridx (i2); \ 787 r.ridx (nel) = m2.ridx (i2); \
788 r.data (nel++) = true; \ 788 r.data (nel++) = true; \
789 } \ 789 } \
790 i2++; \ 790 i2++; \
791 } \ 791 } \
792 else if (i2 == e2 || m1.ridx (i1) < m2.ridx (i2)) \ 792 else if (i2 == e2 || m1.ridx (i1) < m2.ridx (i2)) \
793 { \ 793 { \
794 if (C1 (m1.data (i1)) OP C2 (Z2)) \ 794 if (C1 (m1.data (i1)) OP C2 (Z2)) \
795 { \ 795 { \
796 r.ridx (nel) = m1.ridx (i1); \ 796 r.ridx (nel) = m1.ridx (i1); \
797 r.data (nel++) = true; \ 797 r.data (nel++) = true; \
798 } \ 798 } \
799 i1++; \ 799 i1++; \
800 } \ 800 } \
801 else \ 801 else \
802 { \ 802 { \
803 if (C1 (m1.data (i1)) OP C2 (m2.data (i2))) \ 803 if (C1 (m1.data (i1)) OP C2 (m2.data (i2))) \
804 { \ 804 { \
805 r.ridx (nel) = m1.ridx (i1); \ 805 r.ridx (nel) = m1.ridx (i1); \
806 r.data (nel++) = true; \ 806 r.data (nel++) = true; \
807 } \ 807 } \
808 i1++; \ 808 i1++; \
809 i2++; \ 809 i2++; \
810 } \ 810 } \
811 } \ 811 } \
812 r.cidx (j + 1) = nel; \ 812 r.cidx (j + 1) = nel; \
813 } \ 813 } \
814 r.maybe_compress (false); \ 814 r.maybe_compress (false); \
815 } \ 815 } \
816 } \ 816 } \
817 } \ 817 } \
818 else \ 818 else \
819 { \ 819 { \
820 if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0)) \ 820 if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0)) \
821 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \ 821 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \
822 } \ 822 } \
823 return r; \ 823 return r; \
824 } 824 }
825 825
826 #define SPARSE_SMSM_CMP_OPS(M1, Z1, C1, M2, Z2, C2) \ 826 #define SPARSE_SMSM_CMP_OPS(M1, Z1, C1, M2, Z2, C2) \
827 SPARSE_SMSM_CMP_OP (mx_el_lt, <, M1, Z1, , M2, Z2, ) \ 827 SPARSE_SMSM_CMP_OP (mx_el_lt, <, M1, Z1, , M2, Z2, ) \
828 SPARSE_SMSM_CMP_OP (mx_el_le, <=, M1, Z1, , M2, Z2, ) \ 828 SPARSE_SMSM_CMP_OP (mx_el_le, <=, M1, Z1, , M2, Z2, ) \
829 SPARSE_SMSM_CMP_OP (mx_el_ge, >=, M1, Z1, , M2, Z2, ) \ 829 SPARSE_SMSM_CMP_OP (mx_el_ge, >=, M1, Z1, , M2, Z2, ) \
830 SPARSE_SMSM_CMP_OP (mx_el_gt, >, M1, Z1, , M2, Z2, ) \ 830 SPARSE_SMSM_CMP_OP (mx_el_gt, >, M1, Z1, , M2, Z2, ) \
831 SPARSE_SMSM_CMP_OP (mx_el_eq, ==, M1, Z1, , M2, Z2, ) \ 831 SPARSE_SMSM_CMP_OP (mx_el_eq, ==, M1, Z1, , M2, Z2, ) \
832 SPARSE_SMSM_CMP_OP (mx_el_ne, !=, M1, Z1, , M2, Z2, ) 832 SPARSE_SMSM_CMP_OP (mx_el_ne, !=, M1, Z1, , M2, Z2, )
833 833
834 #define SPARSE_SMSM_EQNE_OPS(M1, Z1, C1, M2, Z2, C2) \ 834 #define SPARSE_SMSM_EQNE_OPS(M1, Z1, C1, M2, Z2, C2) \
835 SPARSE_SMSM_CMP_OP (mx_el_eq, ==, M1, Z1, , M2, Z2, ) \ 835 SPARSE_SMSM_CMP_OP (mx_el_eq, ==, M1, Z1, , M2, Z2, ) \
836 SPARSE_SMSM_CMP_OP (mx_el_ne, !=, M1, Z1, , M2, Z2, ) 836 SPARSE_SMSM_CMP_OP (mx_el_ne, !=, M1, Z1, , M2, Z2, )
837 837
838 // FIXME: this macro duplicates the bodies of the template functions 838 // FIXME: this macro duplicates the bodies of the template functions
839 // defined in the SPARSE_SSM_BOOL_OP and SPARSE_SMS_BOOL_OP macros. 839 // defined in the SPARSE_SSM_BOOL_OP and SPARSE_SMS_BOOL_OP macros.
840 840
841 #define SPARSE_SMSM_BOOL_OP(F, OP, M1, M2, LHS_ZERO, RHS_ZERO) \ 841 #define SPARSE_SMSM_BOOL_OP(F, OP, M1, M2, LHS_ZERO, RHS_ZERO) \
842 SparseBoolMatrix \ 842 SparseBoolMatrix \
843 F (const M1& m1, const M2& m2) \ 843 F (const M1& m1, const M2& m2) \
844 { \ 844 { \
845 SparseBoolMatrix r; \ 845 SparseBoolMatrix r; \
846 \ 846 \
847 octave_idx_type m1_nr = m1.rows (); \ 847 octave_idx_type m1_nr = m1.rows (); \
848 octave_idx_type m1_nc = m1.cols (); \ 848 octave_idx_type m1_nc = m1.cols (); \
849 \ 849 \
850 octave_idx_type m2_nr = m2.rows (); \ 850 octave_idx_type m2_nr = m2.rows (); \
851 octave_idx_type m2_nc = m2.cols (); \ 851 octave_idx_type m2_nc = m2.cols (); \
852 \ 852 \
853 if (m1_nr == 1 && m1_nc == 1) \ 853 if (m1_nr == 1 && m1_nc == 1) \
854 { \ 854 { \
855 if (m2_nr > 0 && m2_nc > 0) \ 855 if (m2_nr > 0 && m2_nc > 0) \
856 { \ 856 { \
857 if ((m1.elem (0,0) != LHS_ZERO) OP RHS_ZERO) \ 857 if ((m1.elem (0,0) != LHS_ZERO) OP RHS_ZERO) \
858 { \ 858 { \
859 r = SparseBoolMatrix (m2_nr, m2_nc, true); \ 859 r = SparseBoolMatrix (m2_nr, m2_nc, true); \
860 for (octave_idx_type j = 0; j < m2_nc; j++) \ 860 for (octave_idx_type j = 0; j < m2_nc; j++) \
861 for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \ 861 for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \
862 if (! ((m1.elem (0,0) != LHS_ZERO) OP (m2.data (i) != RHS_ZERO))) \ 862 if (! ((m1.elem (0,0) != LHS_ZERO) OP (m2.data (i) != RHS_ZERO))) \
863 r.data (m2.ridx (i) + j * m2_nr) = false; \ 863 r.data (m2.ridx (i) + j * m2_nr) = false; \
864 r.maybe_compress (true); \ 864 r.maybe_compress (true); \
865 } \ 865 } \
866 else \ 866 else \
867 { \ 867 { \
868 r = SparseBoolMatrix (m2_nr, m2_nc, m2.nnz ()); \ 868 r = SparseBoolMatrix (m2_nr, m2_nc, m2.nnz ()); \
869 r.cidx (0) = static_cast<octave_idx_type> (0); \ 869 r.cidx (0) = static_cast<octave_idx_type> (0); \
870 octave_idx_type nel = 0; \ 870 octave_idx_type nel = 0; \
871 for (octave_idx_type j = 0; j < m2_nc; j++) \ 871 for (octave_idx_type j = 0; j < m2_nc; j++) \
872 { \ 872 { \
873 for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \ 873 for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \
874 if ((m1.elem (0,0) != LHS_ZERO) OP (m2.data (i) != RHS_ZERO)) \ 874 if ((m1.elem (0,0) != LHS_ZERO) OP (m2.data (i) != RHS_ZERO)) \
875 { \ 875 { \
876 r.ridx (nel) = m2.ridx (i); \ 876 r.ridx (nel) = m2.ridx (i); \
877 r.data (nel++) = true; \ 877 r.data (nel++) = true; \
878 } \ 878 } \
879 r.cidx (j + 1) = nel; \ 879 r.cidx (j + 1) = nel; \
880 } \ 880 } \
881 r.maybe_compress (false); \ 881 r.maybe_compress (false); \
882 } \ 882 } \
883 } \ 883 } \
884 } \ 884 } \
885 else if (m2_nr == 1 && m2_nc == 1) \ 885 else if (m2_nr == 1 && m2_nc == 1) \
886 { \ 886 { \
887 if (m1_nr > 0 && m1_nc > 0) \ 887 if (m1_nr > 0 && m1_nc > 0) \
888 { \ 888 { \
889 if (LHS_ZERO OP (m2.elem (0,0) != RHS_ZERO)) \ 889 if (LHS_ZERO OP (m2.elem (0,0) != RHS_ZERO)) \
890 { \ 890 { \
891 r = SparseBoolMatrix (m1_nr, m1_nc, true); \ 891 r = SparseBoolMatrix (m1_nr, m1_nc, true); \
892 for (octave_idx_type j = 0; j < m1_nc; j++) \ 892 for (octave_idx_type j = 0; j < m1_nc; j++) \
893 for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \ 893 for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \
894 if (! ((m1.data (i) != LHS_ZERO) OP (m2.elem (0,0) != RHS_ZERO))) \ 894 if (! ((m1.data (i) != LHS_ZERO) OP (m2.elem (0,0) != RHS_ZERO))) \
895 r.data (m1.ridx (i) + j * m1_nr) = false; \ 895 r.data (m1.ridx (i) + j * m1_nr) = false; \
896 r.maybe_compress (true); \ 896 r.maybe_compress (true); \
897 } \ 897 } \
898 else \ 898 else \
899 { \ 899 { \
900 r = SparseBoolMatrix (m1_nr, m1_nc, m1.nnz ()); \ 900 r = SparseBoolMatrix (m1_nr, m1_nc, m1.nnz ()); \
901 r.cidx (0) = static_cast<octave_idx_type> (0); \ 901 r.cidx (0) = static_cast<octave_idx_type> (0); \
902 octave_idx_type nel = 0; \ 902 octave_idx_type nel = 0; \
903 for (octave_idx_type j = 0; j < m1_nc; j++) \ 903 for (octave_idx_type j = 0; j < m1_nc; j++) \
904 { \ 904 { \
905 for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \ 905 for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \
906 if ((m1.data (i) != LHS_ZERO) OP (m2.elem (0,0) != RHS_ZERO)) \ 906 if ((m1.data (i) != LHS_ZERO) OP (m2.elem (0,0) != RHS_ZERO)) \
907 { \ 907 { \
908 r.ridx (nel) = m1.ridx (i); \ 908 r.ridx (nel) = m1.ridx (i); \
909 r.data (nel++) = true; \ 909 r.data (nel++) = true; \
910 } \ 910 } \
911 r.cidx (j + 1) = nel; \ 911 r.cidx (j + 1) = nel; \
912 } \ 912 } \
913 r.maybe_compress (false); \ 913 r.maybe_compress (false); \
914 } \ 914 } \
915 } \ 915 } \
916 } \ 916 } \
917 else if (m1_nr == m2_nr && m1_nc == m2_nc) \ 917 else if (m1_nr == m2_nr && m1_nc == m2_nc) \
918 { \ 918 { \
919 if (m1_nr != 0 || m1_nc != 0) \ 919 if (m1_nr != 0 || m1_nc != 0) \
920 { \ 920 { \
921 r = SparseBoolMatrix (m1_nr, m1_nc, m1.nnz () + m2.nnz ()); \ 921 r = SparseBoolMatrix (m1_nr, m1_nc, m1.nnz () + m2.nnz ()); \
922 r.cidx (0) = static_cast<octave_idx_type> (0); \ 922 r.cidx (0) = static_cast<octave_idx_type> (0); \
923 octave_idx_type nel = 0; \ 923 octave_idx_type nel = 0; \
924 for (octave_idx_type j = 0; j < m1_nc; j++) \ 924 for (octave_idx_type j = 0; j < m1_nc; j++) \
925 { \ 925 { \
926 octave_idx_type i1 = m1.cidx (j); \ 926 octave_idx_type i1 = m1.cidx (j); \
927 octave_idx_type e1 = m1.cidx (j+1); \ 927 octave_idx_type e1 = m1.cidx (j+1); \
928 octave_idx_type i2 = m2.cidx (j); \ 928 octave_idx_type i2 = m2.cidx (j); \
929 octave_idx_type e2 = m2.cidx (j+1); \ 929 octave_idx_type e2 = m2.cidx (j+1); \
930 while (i1 < e1 || i2 < e2) \ 930 while (i1 < e1 || i2 < e2) \
931 { \ 931 { \
932 if (i1 == e1 || (i2 < e2 && m1.ridx (i1) > m2.ridx (i2))) \ 932 if (i1 == e1 || (i2 < e2 && m1.ridx (i1) > m2.ridx (i2))) \
933 { \ 933 { \
934 if (LHS_ZERO OP m2.data (i2) != RHS_ZERO) \ 934 if (LHS_ZERO OP m2.data (i2) != RHS_ZERO) \
935 { \ 935 { \
936 r.ridx (nel) = m2.ridx (i2); \ 936 r.ridx (nel) = m2.ridx (i2); \
937 r.data (nel++) = true; \ 937 r.data (nel++) = true; \
938 } \ 938 } \
939 i2++; \ 939 i2++; \
940 } \ 940 } \
941 else if (i2 == e2 || m1.ridx (i1) < m2.ridx (i2)) \ 941 else if (i2 == e2 || m1.ridx (i1) < m2.ridx (i2)) \
942 { \ 942 { \
943 if (m1.data (i1) != LHS_ZERO OP RHS_ZERO) \ 943 if (m1.data (i1) != LHS_ZERO OP RHS_ZERO) \
944 { \ 944 { \
945 r.ridx (nel) = m1.ridx (i1); \ 945 r.ridx (nel) = m1.ridx (i1); \
946 r.data (nel++) = true; \ 946 r.data (nel++) = true; \
947 } \ 947 } \
948 i1++; \ 948 i1++; \
949 } \ 949 } \
950 else \ 950 else \
951 { \ 951 { \
952 if (m1.data (i1) != LHS_ZERO OP m2.data (i2) != RHS_ZERO) \ 952 if (m1.data (i1) != LHS_ZERO OP m2.data (i2) != RHS_ZERO) \
953 { \ 953 { \
954 r.ridx (nel) = m1.ridx (i1); \ 954 r.ridx (nel) = m1.ridx (i1); \
955 r.data (nel++) = true; \ 955 r.data (nel++) = true; \
956 } \ 956 } \
957 i1++; \ 957 i1++; \
958 i2++; \ 958 i2++; \
959 } \ 959 } \
960 } \ 960 } \
961 r.cidx (j + 1) = nel; \ 961 r.cidx (j + 1) = nel; \
962 } \ 962 } \
963 r.maybe_compress (false); \ 963 r.maybe_compress (false); \
964 } \ 964 } \
965 } \ 965 } \
966 else \ 966 else \
967 { \ 967 { \
968 if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0)) \ 968 if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0)) \
969 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \ 969 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \
970 } \ 970 } \
971 return r; \ 971 return r; \
972 } 972 }
973 973
974 #define SPARSE_SMSM_BOOL_OPS2(M1, M2, LHS_ZERO, RHS_ZERO) \ 974 #define SPARSE_SMSM_BOOL_OPS2(M1, M2, LHS_ZERO, RHS_ZERO) \
975 SPARSE_SMSM_BOOL_OP (mx_el_and, &&, M1, M2, LHS_ZERO, RHS_ZERO) \ 975 SPARSE_SMSM_BOOL_OP (mx_el_and, &&, M1, M2, LHS_ZERO, RHS_ZERO) \
976 SPARSE_SMSM_BOOL_OP (mx_el_or, ||, M1, M2, LHS_ZERO, RHS_ZERO) 976 SPARSE_SMSM_BOOL_OP (mx_el_or, ||, M1, M2, LHS_ZERO, RHS_ZERO)
977 977
978 #define SPARSE_SMSM_BOOL_OPS(M1, M2, ZERO) \ 978 #define SPARSE_SMSM_BOOL_OPS(M1, M2, ZERO) \
979 SPARSE_SMSM_BOOL_OPS2(M1, M2, ZERO, ZERO) 979 SPARSE_SMSM_BOOL_OPS2(M1, M2, ZERO, ZERO)
980 980
981 // matrix by sparse matrix operations. 981 // matrix by sparse matrix operations.
982 982
983 #define SPARSE_MSM_BIN_OP_1(R, F, OP, M1, M2) \ 983 #define SPARSE_MSM_BIN_OP_1(R, F, OP, M1, M2) \
984 R \ 984 R \
985 F (const M1& m1, const M2& m2) \ 985 F (const M1& m1, const M2& m2) \
986 { \ 986 { \
987 R r; \ 987 R r; \
988 \ 988 \
989 octave_idx_type m1_nr = m1.rows (); \ 989 octave_idx_type m1_nr = m1.rows (); \
990 octave_idx_type m1_nc = m1.cols (); \ 990 octave_idx_type m1_nc = m1.cols (); \
991 \ 991 \
992 octave_idx_type m2_nr = m2.rows (); \ 992 octave_idx_type m2_nr = m2.rows (); \
993 octave_idx_type m2_nc = m2.cols (); \ 993 octave_idx_type m2_nc = m2.cols (); \
994 \ 994 \
995 if (m2_nr == 1 && m2_nc == 1) \ 995 if (m2_nr == 1 && m2_nc == 1) \
996 r = R (m1 OP m2.elem (0,0)); \ 996 r = R (m1 OP m2.elem (0,0)); \
997 else if (m1_nr != m2_nr || m1_nc != m2_nc) \ 997 else if (m1_nr != m2_nr || m1_nc != m2_nc) \
998 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \ 998 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \
999 else \ 999 else \
1000 { \ 1000 { \
1001 r = R (F (m1, m2.matrix_value ())); \ 1001 r = R (F (m1, m2.matrix_value ())); \
1002 } \ 1002 } \
1003 return r; \ 1003 return r; \
1004 } 1004 }
1005 1005
1006 #define SPARSE_MSM_BIN_OP_2(R, F, OP, M1, M2) \ 1006 #define SPARSE_MSM_BIN_OP_2(R, F, OP, M1, M2) \
1007 R \ 1007 R \
1008 F (const M1& m1, const M2& m2) \ 1008 F (const M1& m1, const M2& m2) \
1009 { \ 1009 { \
1010 R r; \ 1010 R r; \
1011 \ 1011 \
1012 octave_idx_type m1_nr = m1.rows (); \ 1012 octave_idx_type m1_nr = m1.rows (); \
1013 octave_idx_type m1_nc = m1.cols (); \ 1013 octave_idx_type m1_nc = m1.cols (); \
1014 \ 1014 \
1015 octave_idx_type m2_nr = m2.rows (); \ 1015 octave_idx_type m2_nr = m2.rows (); \
1016 octave_idx_type m2_nc = m2.cols (); \ 1016 octave_idx_type m2_nc = m2.cols (); \
1017 \ 1017 \
1018 if (m2_nr == 1 && m2_nc == 1) \ 1018 if (m2_nr == 1 && m2_nc == 1) \
1019 r = R (m1 OP m2.elem (0,0)); \ 1019 r = R (m1 OP m2.elem (0,0)); \
1020 else if (m1_nr != m2_nr || m1_nc != m2_nc) \ 1020 else if (m1_nr != m2_nr || m1_nc != m2_nc) \
1021 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \ 1021 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \
1022 else \ 1022 else \
1023 { \ 1023 { \
1024 if (do_mx_check (m1, mx_inline_all_finite<M1::element_type>)) \ 1024 if (do_mx_check (m1, mx_inline_all_finite<M1::element_type>)) \
1025 { \ 1025 { \
1026 /* Sparsity pattern is preserved. */ \ 1026 /* Sparsity pattern is preserved. */ \
1027 octave_idx_type m2_nz = m2.nnz (); \ 1027 octave_idx_type m2_nz = m2.nnz (); \
1028 r = R (m2_nr, m2_nc, m2_nz); \ 1028 r = R (m2_nr, m2_nc, m2_nz); \
1029 for (octave_idx_type j = 0, k = 0; j < m2_nc; j++) \ 1029 for (octave_idx_type j = 0, k = 0; j < m2_nc; j++) \
1030 { \ 1030 { \
1031 octave_quit (); \ 1031 octave_quit (); \
1032 for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \ 1032 for (octave_idx_type i = m2.cidx (j); i < m2.cidx (j+1); i++) \
1033 { \ 1033 { \
1034 octave_idx_type mri = m2.ridx (i); \ 1034 octave_idx_type mri = m2.ridx (i); \
1035 R::element_type x = m1(mri, j) OP m2.data (i); \ 1035 R::element_type x = m1(mri, j) OP m2.data (i); \
1036 if (x != 0.0) \ 1036 if (x != 0.0) \
1037 { \ 1037 { \
1038 r.xdata (k) = x; \ 1038 r.xdata (k) = x; \
1039 r.xridx (k) = m2.ridx (i); \ 1039 r.xridx (k) = m2.ridx (i); \
1040 k++; \ 1040 k++; \
1041 } \ 1041 } \
1042 } \ 1042 } \
1043 r.xcidx (j+1) = k; \ 1043 r.xcidx (j+1) = k; \
1044 } \ 1044 } \
1045 r.maybe_compress (false); \ 1045 r.maybe_compress (false); \
1046 return r; \ 1046 return r; \
1047 } \ 1047 } \
1048 else \ 1048 else \
1049 r = R (F (m1, m2.matrix_value ())); \ 1049 r = R (F (m1, m2.matrix_value ())); \
1050 } \ 1050 } \
1051 \ 1051 \
1052 return r; \ 1052 return r; \
1053 } 1053 }
1054 1054
1055 // FIXME: Pass a specific ZERO value 1055 // FIXME: Pass a specific ZERO value
1056 #define SPARSE_MSM_BIN_OPS(R1, R2, M1, M2) \ 1056 #define SPARSE_MSM_BIN_OPS(R1, R2, M1, M2) \
1057 SPARSE_MSM_BIN_OP_1 (R1, operator +, +, M1, M2) \ 1057 SPARSE_MSM_BIN_OP_1 (R1, operator +, +, M1, M2) \
1058 SPARSE_MSM_BIN_OP_1 (R1, operator -, -, M1, M2) \ 1058 SPARSE_MSM_BIN_OP_1 (R1, operator -, -, M1, M2) \
1059 SPARSE_MSM_BIN_OP_2 (R2, product, *, M1, M2) \ 1059 SPARSE_MSM_BIN_OP_2 (R2, product, *, M1, M2) \
1060 SPARSE_MSM_BIN_OP_1 (R2, quotient, /, M1, M2) 1060 SPARSE_MSM_BIN_OP_1 (R2, quotient, /, M1, M2)
1061 1061
1062 #define SPARSE_MSM_CMP_OP(F, OP, M1, C1, M2, C2) \ 1062 #define SPARSE_MSM_CMP_OP(F, OP, M1, C1, M2, C2) \
1063 SparseBoolMatrix \ 1063 SparseBoolMatrix \
1064 F (const M1& m1, const M2& m2) \ 1064 F (const M1& m1, const M2& m2) \
1065 { \ 1065 { \
1066 SparseBoolMatrix r; \ 1066 SparseBoolMatrix r; \
1067 \ 1067 \
1068 octave_idx_type m1_nr = m1.rows (); \ 1068 octave_idx_type m1_nr = m1.rows (); \
1069 octave_idx_type m1_nc = m1.cols (); \ 1069 octave_idx_type m1_nc = m1.cols (); \
1070 \ 1070 \
1071 octave_idx_type m2_nr = m2.rows (); \ 1071 octave_idx_type m2_nr = m2.rows (); \
1072 octave_idx_type m2_nc = m2.cols (); \ 1072 octave_idx_type m2_nc = m2.cols (); \
1073 \ 1073 \
1074 if (m2_nr == 1 && m2_nc == 1) \ 1074 if (m2_nr == 1 && m2_nc == 1) \
1075 r = SparseBoolMatrix (F (m1, m2.elem (0,0))); \ 1075 r = SparseBoolMatrix (F (m1, m2.elem (0,0))); \
1076 else if (m1_nr == m2_nr && m1_nc == m2_nc) \ 1076 else if (m1_nr == m2_nr && m1_nc == m2_nc) \
1077 { \ 1077 { \
1078 if (m1_nr != 0 || m1_nc != 0) \ 1078 if (m1_nr != 0 || m1_nc != 0) \
1079 { \ 1079 { \
1080 /* Count num of nonzero elements */ \ 1080 /* Count num of nonzero elements */ \
1081 octave_idx_type nel = 0; \ 1081 octave_idx_type nel = 0; \
1082 for (octave_idx_type j = 0; j < m1_nc; j++) \ 1082 for (octave_idx_type j = 0; j < m1_nc; j++) \
1083 for (octave_idx_type i = 0; i < m1_nr; i++) \ 1083 for (octave_idx_type i = 0; i < m1_nr; i++) \
1084 if (C1 (m1.elem (i, j)) OP C2 (m2.elem (i, j))) \ 1084 if (C1 (m1.elem (i, j)) OP C2 (m2.elem (i, j))) \
1085 nel++; \ 1085 nel++; \
1086 \ 1086 \
1087 r = SparseBoolMatrix (m1_nr, m1_nc, nel); \ 1087 r = SparseBoolMatrix (m1_nr, m1_nc, nel); \
1088 \ 1088 \
1089 octave_idx_type ii = 0; \ 1089 octave_idx_type ii = 0; \
1090 r.cidx (0) = 0; \ 1090 r.cidx (0) = 0; \
1091 for (octave_idx_type j = 0; j < m1_nc; j++) \ 1091 for (octave_idx_type j = 0; j < m1_nc; j++) \
1092 { \ 1092 { \
1093 for (octave_idx_type i = 0; i < m1_nr; i++) \ 1093 for (octave_idx_type i = 0; i < m1_nr; i++) \
1094 { \ 1094 { \
1095 bool el = C1 (m1.elem (i, j)) OP C2 (m2.elem (i, j)); \ 1095 bool el = C1 (m1.elem (i, j)) OP C2 (m2.elem (i, j)); \
1096 if (el) \ 1096 if (el) \
1097 { \ 1097 { \
1098 r.data (ii) = el; \ 1098 r.data (ii) = el; \
1099 r.ridx (ii++) = i; \ 1099 r.ridx (ii++) = i; \
1100 } \ 1100 } \
1101 } \ 1101 } \
1102 r.cidx (j+1) = ii; \ 1102 r.cidx (j+1) = ii; \
1103 } \ 1103 } \
1104 } \ 1104 } \
1105 } \ 1105 } \
1106 else \ 1106 else \
1107 { \ 1107 { \
1108 if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0)) \ 1108 if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0)) \
1109 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \ 1109 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \
1110 } \ 1110 } \
1111 return r; \ 1111 return r; \
1112 } 1112 }
1113 1113
1114 #define SPARSE_MSM_CMP_OPS(M1, Z1, C1, M2, Z2, C2) \ 1114 #define SPARSE_MSM_CMP_OPS(M1, Z1, C1, M2, Z2, C2) \
1115 SPARSE_MSM_CMP_OP (mx_el_lt, <, M1, , M2, ) \ 1115 SPARSE_MSM_CMP_OP (mx_el_lt, <, M1, , M2, ) \
1116 SPARSE_MSM_CMP_OP (mx_el_le, <=, M1, , M2, ) \ 1116 SPARSE_MSM_CMP_OP (mx_el_le, <=, M1, , M2, ) \
1117 SPARSE_MSM_CMP_OP (mx_el_ge, >=, M1, , M2, ) \ 1117 SPARSE_MSM_CMP_OP (mx_el_ge, >=, M1, , M2, ) \
1118 SPARSE_MSM_CMP_OP (mx_el_gt, >, M1, , M2, ) \ 1118 SPARSE_MSM_CMP_OP (mx_el_gt, >, M1, , M2, ) \
1119 SPARSE_MSM_CMP_OP (mx_el_eq, ==, M1, , M2, ) \ 1119 SPARSE_MSM_CMP_OP (mx_el_eq, ==, M1, , M2, ) \
1120 SPARSE_MSM_CMP_OP (mx_el_ne, !=, M1, , M2, ) 1120 SPARSE_MSM_CMP_OP (mx_el_ne, !=, M1, , M2, )
1121 1121
1122 #define SPARSE_MSM_EQNE_OPS(M1, Z1, C1, M2, Z2, C2) \ 1122 #define SPARSE_MSM_EQNE_OPS(M1, Z1, C1, M2, Z2, C2) \
1123 SPARSE_MSM_CMP_OP (mx_el_eq, ==, M1, , M2, ) \ 1123 SPARSE_MSM_CMP_OP (mx_el_eq, ==, M1, , M2, ) \
1124 SPARSE_MSM_CMP_OP (mx_el_ne, !=, M1, , M2, ) 1124 SPARSE_MSM_CMP_OP (mx_el_ne, !=, M1, , M2, )
1125 1125
1126 #define SPARSE_MSM_BOOL_OP(F, OP, M1, M2, LHS_ZERO, RHS_ZERO) \ 1126 #define SPARSE_MSM_BOOL_OP(F, OP, M1, M2, LHS_ZERO, RHS_ZERO) \
1127 SparseBoolMatrix \ 1127 SparseBoolMatrix \
1128 F (const M1& m1, const M2& m2) \ 1128 F (const M1& m1, const M2& m2) \
1129 { \ 1129 { \
1130 SparseBoolMatrix r; \ 1130 SparseBoolMatrix r; \
1131 \ 1131 \
1132 octave_idx_type m1_nr = m1.rows (); \ 1132 octave_idx_type m1_nr = m1.rows (); \
1133 octave_idx_type m1_nc = m1.cols (); \ 1133 octave_idx_type m1_nc = m1.cols (); \
1134 \ 1134 \
1135 octave_idx_type m2_nr = m2.rows (); \ 1135 octave_idx_type m2_nr = m2.rows (); \
1136 octave_idx_type m2_nc = m2.cols (); \ 1136 octave_idx_type m2_nc = m2.cols (); \
1137 \ 1137 \
1138 if (m2_nr == 1 && m2_nc == 1) \ 1138 if (m2_nr == 1 && m2_nc == 1) \
1139 r = SparseBoolMatrix (F (m1, m2.elem (0,0))); \ 1139 r = SparseBoolMatrix (F (m1, m2.elem (0,0))); \
1140 else if (m1_nr == m2_nr && m1_nc == m2_nc) \ 1140 else if (m1_nr == m2_nr && m1_nc == m2_nc) \
1141 { \ 1141 { \
1142 if (m1_nr != 0 || m1_nc != 0) \ 1142 if (m1_nr != 0 || m1_nc != 0) \
1143 { \ 1143 { \
1144 /* Count num of nonzero elements */ \ 1144 /* Count num of nonzero elements */ \
1145 octave_idx_type nel = 0; \ 1145 octave_idx_type nel = 0; \
1146 for (octave_idx_type j = 0; j < m1_nc; j++) \ 1146 for (octave_idx_type j = 0; j < m1_nc; j++) \
1147 for (octave_idx_type i = 0; i < m1_nr; i++) \ 1147 for (octave_idx_type i = 0; i < m1_nr; i++) \
1148 if ((m1.elem (i, j) != LHS_ZERO) \ 1148 if ((m1.elem (i, j) != LHS_ZERO) \
1149 OP (m2.elem (i, j) != RHS_ZERO)) \ 1149 OP (m2.elem (i, j) != RHS_ZERO)) \
1150 nel++; \ 1150 nel++; \
1151 \ 1151 \
1152 r = SparseBoolMatrix (m1_nr, m1_nc, nel); \ 1152 r = SparseBoolMatrix (m1_nr, m1_nc, nel); \
1153 \ 1153 \
1154 octave_idx_type ii = 0; \ 1154 octave_idx_type ii = 0; \
1155 r.cidx (0) = 0; \ 1155 r.cidx (0) = 0; \
1156 for (octave_idx_type j = 0; j < m1_nc; j++) \ 1156 for (octave_idx_type j = 0; j < m1_nc; j++) \
1157 { \ 1157 { \
1158 for (octave_idx_type i = 0; i < m1_nr; i++) \ 1158 for (octave_idx_type i = 0; i < m1_nr; i++) \
1159 { \ 1159 { \
1160 bool el = (m1.elem (i, j) != LHS_ZERO) \ 1160 bool el = (m1.elem (i, j) != LHS_ZERO) \
1161 OP (m2.elem (i, j) != RHS_ZERO); \ 1161 OP (m2.elem (i, j) != RHS_ZERO); \
1162 if (el) \ 1162 if (el) \
1163 { \ 1163 { \
1164 r.data (ii) = el; \ 1164 r.data (ii) = el; \
1165 r.ridx (ii++) = i; \ 1165 r.ridx (ii++) = i; \
1166 } \ 1166 } \
1167 } \ 1167 } \
1168 r.cidx (j+1) = ii; \ 1168 r.cidx (j+1) = ii; \
1169 } \ 1169 } \
1170 } \ 1170 } \
1171 } \ 1171 } \
1172 else \ 1172 else \
1173 { \ 1173 { \
1174 if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0)) \ 1174 if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0)) \
1175 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \ 1175 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \
1176 } \ 1176 } \
1177 return r; \ 1177 return r; \
1178 } 1178 }
1179 1179
1180 #define SPARSE_MSM_BOOL_OPS2(M1, M2, LHS_ZERO, RHS_ZERO) \ 1180 #define SPARSE_MSM_BOOL_OPS2(M1, M2, LHS_ZERO, RHS_ZERO) \
1181 SPARSE_MSM_BOOL_OP (mx_el_and, &&, M1, M2, LHS_ZERO, RHS_ZERO) \ 1181 SPARSE_MSM_BOOL_OP (mx_el_and, &&, M1, M2, LHS_ZERO, RHS_ZERO) \
1182 SPARSE_MSM_BOOL_OP (mx_el_or, ||, M1, M2, LHS_ZERO, RHS_ZERO) 1182 SPARSE_MSM_BOOL_OP (mx_el_or, ||, M1, M2, LHS_ZERO, RHS_ZERO)
1183 1183
1184 #define SPARSE_MSM_BOOL_OPS(M1, M2, ZERO) \ 1184 #define SPARSE_MSM_BOOL_OPS(M1, M2, ZERO) \
1185 SPARSE_MSM_BOOL_OPS2(M1, M2, ZERO, ZERO) 1185 SPARSE_MSM_BOOL_OPS2(M1, M2, ZERO, ZERO)
1186 1186
1187 // sparse matrix by matrix operations. 1187 // sparse matrix by matrix operations.
1188 1188
1189 #define SPARSE_SMM_BIN_OP_1(R, F, OP, M1, M2) \ 1189 #define SPARSE_SMM_BIN_OP_1(R, F, OP, M1, M2) \
1190 R \ 1190 R \
1191 F (const M1& m1, const M2& m2) \ 1191 F (const M1& m1, const M2& m2) \
1192 { \ 1192 { \
1193 R r; \ 1193 R r; \
1194 \ 1194 \
1195 octave_idx_type m1_nr = m1.rows (); \ 1195 octave_idx_type m1_nr = m1.rows (); \
1196 octave_idx_type m1_nc = m1.cols (); \ 1196 octave_idx_type m1_nc = m1.cols (); \
1197 \ 1197 \
1198 octave_idx_type m2_nr = m2.rows (); \ 1198 octave_idx_type m2_nr = m2.rows (); \
1199 octave_idx_type m2_nc = m2.cols (); \ 1199 octave_idx_type m2_nc = m2.cols (); \
1200 \ 1200 \
1201 if (m1_nr == 1 && m1_nc == 1) \ 1201 if (m1_nr == 1 && m1_nc == 1) \
1202 r = R (m1.elem (0,0) OP m2); \ 1202 r = R (m1.elem (0,0) OP m2); \
1203 else if (m1_nr != m2_nr || m1_nc != m2_nc) \ 1203 else if (m1_nr != m2_nr || m1_nc != m2_nc) \
1204 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \ 1204 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \
1205 else \ 1205 else \
1206 { \ 1206 { \
1207 r = R (m1.matrix_value () OP m2); \ 1207 r = R (m1.matrix_value () OP m2); \
1208 } \ 1208 } \
1209 return r; \ 1209 return r; \
1210 } 1210 }
1211 1211
1212 // sm .* m preserves sparsity if m contains no Infs nor Nans. 1212 // sm .* m preserves sparsity if m contains no Infs nor Nans.
1213 #define SPARSE_SMM_BIN_OP_2_CHECK_product(ET) \ 1213 #define SPARSE_SMM_BIN_OP_2_CHECK_product(ET) \
1214 do_mx_check (m2, mx_inline_all_finite<ET>) 1214 do_mx_check (m2, mx_inline_all_finite<ET>)
1215 1215
1216 // sm ./ m preserves sparsity if m contains no NaNs or zeros. 1216 // sm ./ m preserves sparsity if m contains no NaNs or zeros.
1217 #define SPARSE_SMM_BIN_OP_2_CHECK_quotient(ET) \ 1217 #define SPARSE_SMM_BIN_OP_2_CHECK_quotient(ET) \
1218 ! do_mx_check (m2, mx_inline_any_nan<ET>) && m2.nnz () == m2.numel () 1218 ! do_mx_check (m2, mx_inline_any_nan<ET>) && m2.nnz () == m2.numel ()
1219 1219
1220 #define SPARSE_SMM_BIN_OP_2(R, F, OP, M1, M2) \ 1220 #define SPARSE_SMM_BIN_OP_2(R, F, OP, M1, M2) \
1221 R \ 1221 R \
1222 F (const M1& m1, const M2& m2) \ 1222 F (const M1& m1, const M2& m2) \
1223 { \ 1223 { \
1224 R r; \ 1224 R r; \
1225 \ 1225 \
1226 octave_idx_type m1_nr = m1.rows (); \ 1226 octave_idx_type m1_nr = m1.rows (); \
1227 octave_idx_type m1_nc = m1.cols (); \ 1227 octave_idx_type m1_nc = m1.cols (); \
1228 \ 1228 \
1229 octave_idx_type m2_nr = m2.rows (); \ 1229 octave_idx_type m2_nr = m2.rows (); \
1230 octave_idx_type m2_nc = m2.cols (); \ 1230 octave_idx_type m2_nc = m2.cols (); \
1231 \ 1231 \
1232 if (m1_nr == 1 && m1_nc == 1) \ 1232 if (m1_nr == 1 && m1_nc == 1) \
1233 r = R (m1.elem (0,0) OP m2); \ 1233 r = R (m1.elem (0,0) OP m2); \
1234 else if (m1_nr != m2_nr || m1_nc != m2_nc) \ 1234 else if (m1_nr != m2_nr || m1_nc != m2_nc) \
1235 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \ 1235 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \
1236 else \ 1236 else \
1237 { \ 1237 { \
1238 if (SPARSE_SMM_BIN_OP_2_CHECK_ ## F(M2::element_type)) \ 1238 if (SPARSE_SMM_BIN_OP_2_CHECK_ ## F(M2::element_type)) \
1239 { \ 1239 { \
1240 /* Sparsity pattern is preserved. */ \ 1240 /* Sparsity pattern is preserved. */ \
1241 octave_idx_type m1_nz = m1.nnz (); \ 1241 octave_idx_type m1_nz = m1.nnz (); \
1242 r = R (m1_nr, m1_nc, m1_nz); \ 1242 r = R (m1_nr, m1_nc, m1_nz); \
1243 for (octave_idx_type j = 0, k = 0; j < m1_nc; j++) \ 1243 for (octave_idx_type j = 0, k = 0; j < m1_nc; j++) \
1244 { \ 1244 { \
1245 octave_quit (); \ 1245 octave_quit (); \
1246 for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \ 1246 for (octave_idx_type i = m1.cidx (j); i < m1.cidx (j+1); i++) \
1247 { \ 1247 { \
1248 octave_idx_type mri = m1.ridx (i); \ 1248 octave_idx_type mri = m1.ridx (i); \
1249 R::element_type x = m1.data (i) OP m2 (mri, j); \ 1249 R::element_type x = m1.data (i) OP m2 (mri, j); \
1250 if (x != 0.0) \ 1250 if (x != 0.0) \
1251 { \ 1251 { \
1252 r.xdata (k) = x; \ 1252 r.xdata (k) = x; \
1253 r.xridx (k) = m1.ridx (i); \ 1253 r.xridx (k) = m1.ridx (i); \
1254 k++; \ 1254 k++; \
1255 } \ 1255 } \
1256 } \ 1256 } \
1257 r.xcidx (j+1) = k; \ 1257 r.xcidx (j+1) = k; \
1258 } \ 1258 } \
1259 r.maybe_compress (false); \ 1259 r.maybe_compress (false); \
1260 return r; \ 1260 return r; \
1261 } \ 1261 } \
1262 else \ 1262 else \
1263 r = R (F (m1.matrix_value (), m2)); \ 1263 r = R (F (m1.matrix_value (), m2)); \
1264 } \ 1264 } \
1265 \ 1265 \
1266 return r; \ 1266 return r; \
1267 } 1267 }
1268 1268
1269 #define SPARSE_SMM_BIN_OPS(R1, R2, M1, M2) \ 1269 #define SPARSE_SMM_BIN_OPS(R1, R2, M1, M2) \
1270 SPARSE_SMM_BIN_OP_1 (R1, operator +, +, M1, M2) \ 1270 SPARSE_SMM_BIN_OP_1 (R1, operator +, +, M1, M2) \
1271 SPARSE_SMM_BIN_OP_1 (R1, operator -, -, M1, M2) \ 1271 SPARSE_SMM_BIN_OP_1 (R1, operator -, -, M1, M2) \
1272 SPARSE_SMM_BIN_OP_2 (R2, product, *, M1, M2) \ 1272 SPARSE_SMM_BIN_OP_2 (R2, product, *, M1, M2) \
1273 SPARSE_SMM_BIN_OP_2 (R2, quotient, /, M1, M2) 1273 SPARSE_SMM_BIN_OP_2 (R2, quotient, /, M1, M2)
1274 1274
1275 #define SPARSE_SMM_CMP_OP(F, OP, M1, C1, M2, C2) \ 1275 #define SPARSE_SMM_CMP_OP(F, OP, M1, C1, M2, C2) \
1276 SparseBoolMatrix \ 1276 SparseBoolMatrix \
1277 F (const M1& m1, const M2& m2) \ 1277 F (const M1& m1, const M2& m2) \
1278 { \ 1278 { \
1279 SparseBoolMatrix r; \ 1279 SparseBoolMatrix r; \
1280 \ 1280 \
1281 octave_idx_type m1_nr = m1.rows (); \ 1281 octave_idx_type m1_nr = m1.rows (); \
1282 octave_idx_type m1_nc = m1.cols (); \ 1282 octave_idx_type m1_nc = m1.cols (); \
1283 \ 1283 \
1284 octave_idx_type m2_nr = m2.rows (); \ 1284 octave_idx_type m2_nr = m2.rows (); \
1285 octave_idx_type m2_nc = m2.cols (); \ 1285 octave_idx_type m2_nc = m2.cols (); \
1286 \ 1286 \
1287 if (m1_nr == 1 && m1_nc == 1) \ 1287 if (m1_nr == 1 && m1_nc == 1) \
1288 r = SparseBoolMatrix (F (m1.elem (0,0), m2)); \ 1288 r = SparseBoolMatrix (F (m1.elem (0,0), m2)); \
1289 else if (m1_nr == m2_nr && m1_nc == m2_nc) \ 1289 else if (m1_nr == m2_nr && m1_nc == m2_nc) \
1290 { \ 1290 { \
1291 if (m1_nr != 0 || m1_nc != 0) \ 1291 if (m1_nr != 0 || m1_nc != 0) \
1292 { \ 1292 { \
1293 /* Count num of nonzero elements */ \ 1293 /* Count num of nonzero elements */ \
1294 octave_idx_type nel = 0; \ 1294 octave_idx_type nel = 0; \
1295 for (octave_idx_type j = 0; j < m1_nc; j++) \ 1295 for (octave_idx_type j = 0; j < m1_nc; j++) \
1296 for (octave_idx_type i = 0; i < m1_nr; i++) \ 1296 for (octave_idx_type i = 0; i < m1_nr; i++) \
1297 if (C1 (m1.elem (i, j)) OP C2 (m2.elem (i, j))) \ 1297 if (C1 (m1.elem (i, j)) OP C2 (m2.elem (i, j))) \
1298 nel++; \ 1298 nel++; \
1299 \ 1299 \
1300 r = SparseBoolMatrix (m1_nr, m1_nc, nel); \ 1300 r = SparseBoolMatrix (m1_nr, m1_nc, nel); \
1301 \ 1301 \
1302 octave_idx_type ii = 0; \ 1302 octave_idx_type ii = 0; \
1303 r.cidx (0) = 0; \ 1303 r.cidx (0) = 0; \
1304 for (octave_idx_type j = 0; j < m1_nc; j++) \ 1304 for (octave_idx_type j = 0; j < m1_nc; j++) \
1305 { \ 1305 { \
1306 for (octave_idx_type i = 0; i < m1_nr; i++) \ 1306 for (octave_idx_type i = 0; i < m1_nr; i++) \
1307 { \ 1307 { \
1308 bool el = C1 (m1.elem (i, j)) OP C2 (m2.elem (i, j)); \ 1308 bool el = C1 (m1.elem (i, j)) OP C2 (m2.elem (i, j)); \
1309 if (el) \ 1309 if (el) \
1310 { \ 1310 { \
1311 r.data (ii) = el; \ 1311 r.data (ii) = el; \
1312 r.ridx (ii++) = i; \ 1312 r.ridx (ii++) = i; \
1313 } \ 1313 } \
1314 } \ 1314 } \
1315 r.cidx (j+1) = ii; \ 1315 r.cidx (j+1) = ii; \
1316 } \ 1316 } \
1317 } \ 1317 } \
1318 } \ 1318 } \
1319 else \ 1319 else \
1320 { \ 1320 { \
1321 if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0)) \ 1321 if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0)) \
1322 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \ 1322 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \
1323 } \ 1323 } \
1324 return r; \ 1324 return r; \
1325 } 1325 }
1326 1326
1327 #define SPARSE_SMM_CMP_OPS(M1, Z1, C1, M2, Z2, C2) \ 1327 #define SPARSE_SMM_CMP_OPS(M1, Z1, C1, M2, Z2, C2) \
1328 SPARSE_SMM_CMP_OP (mx_el_lt, <, M1, , M2, ) \ 1328 SPARSE_SMM_CMP_OP (mx_el_lt, <, M1, , M2, ) \
1329 SPARSE_SMM_CMP_OP (mx_el_le, <=, M1, , M2, ) \ 1329 SPARSE_SMM_CMP_OP (mx_el_le, <=, M1, , M2, ) \
1330 SPARSE_SMM_CMP_OP (mx_el_ge, >=, M1, , M2, ) \ 1330 SPARSE_SMM_CMP_OP (mx_el_ge, >=, M1, , M2, ) \
1331 SPARSE_SMM_CMP_OP (mx_el_gt, >, M1, , M2, ) \ 1331 SPARSE_SMM_CMP_OP (mx_el_gt, >, M1, , M2, ) \
1332 SPARSE_SMM_CMP_OP (mx_el_eq, ==, M1, , M2, ) \ 1332 SPARSE_SMM_CMP_OP (mx_el_eq, ==, M1, , M2, ) \
1333 SPARSE_SMM_CMP_OP (mx_el_ne, !=, M1, , M2, ) 1333 SPARSE_SMM_CMP_OP (mx_el_ne, !=, M1, , M2, )
1334 1334
1335 #define SPARSE_SMM_EQNE_OPS(M1, Z1, C1, M2, Z2, C2) \ 1335 #define SPARSE_SMM_EQNE_OPS(M1, Z1, C1, M2, Z2, C2) \
1336 SPARSE_SMM_CMP_OP (mx_el_eq, ==, M1, , M2, ) \ 1336 SPARSE_SMM_CMP_OP (mx_el_eq, ==, M1, , M2, ) \
1337 SPARSE_SMM_CMP_OP (mx_el_ne, !=, M1, , M2, ) 1337 SPARSE_SMM_CMP_OP (mx_el_ne, !=, M1, , M2, )
1338 1338
1339 #define SPARSE_SMM_BOOL_OP(F, OP, M1, M2, LHS_ZERO, RHS_ZERO) \ 1339 #define SPARSE_SMM_BOOL_OP(F, OP, M1, M2, LHS_ZERO, RHS_ZERO) \
1340 SparseBoolMatrix \ 1340 SparseBoolMatrix \
1341 F (const M1& m1, const M2& m2) \ 1341 F (const M1& m1, const M2& m2) \
1342 { \ 1342 { \
1343 SparseBoolMatrix r; \ 1343 SparseBoolMatrix r; \
1344 \ 1344 \
1345 octave_idx_type m1_nr = m1.rows (); \ 1345 octave_idx_type m1_nr = m1.rows (); \
1346 octave_idx_type m1_nc = m1.cols (); \ 1346 octave_idx_type m1_nc = m1.cols (); \
1347 \ 1347 \
1348 octave_idx_type m2_nr = m2.rows (); \ 1348 octave_idx_type m2_nr = m2.rows (); \
1349 octave_idx_type m2_nc = m2.cols (); \ 1349 octave_idx_type m2_nc = m2.cols (); \
1350 \ 1350 \
1351 if (m1_nr == 1 && m1_nc == 1) \ 1351 if (m1_nr == 1 && m1_nc == 1) \
1352 r = SparseBoolMatrix (F (m1.elem (0,0), m2)); \ 1352 r = SparseBoolMatrix (F (m1.elem (0,0), m2)); \
1353 else if (m1_nr == m2_nr && m1_nc == m2_nc) \ 1353 else if (m1_nr == m2_nr && m1_nc == m2_nc) \
1354 { \ 1354 { \
1355 if (m1_nr != 0 || m1_nc != 0) \ 1355 if (m1_nr != 0 || m1_nc != 0) \
1356 { \ 1356 { \
1357 /* Count num of nonzero elements */ \ 1357 /* Count num of nonzero elements */ \
1358 octave_idx_type nel = 0; \ 1358 octave_idx_type nel = 0; \
1359 for (octave_idx_type j = 0; j < m1_nc; j++) \ 1359 for (octave_idx_type j = 0; j < m1_nc; j++) \
1360 for (octave_idx_type i = 0; i < m1_nr; i++) \ 1360 for (octave_idx_type i = 0; i < m1_nr; i++) \
1361 if ((m1.elem (i, j) != LHS_ZERO) \ 1361 if ((m1.elem (i, j) != LHS_ZERO) \
1362 OP (m2.elem (i, j) != RHS_ZERO)) \ 1362 OP (m2.elem (i, j) != RHS_ZERO)) \
1363 nel++; \ 1363 nel++; \
1364 \ 1364 \
1365 r = SparseBoolMatrix (m1_nr, m1_nc, nel); \ 1365 r = SparseBoolMatrix (m1_nr, m1_nc, nel); \
1366 \ 1366 \
1367 octave_idx_type ii = 0; \ 1367 octave_idx_type ii = 0; \
1368 r.cidx (0) = 0; \ 1368 r.cidx (0) = 0; \
1369 for (octave_idx_type j = 0; j < m1_nc; j++) \ 1369 for (octave_idx_type j = 0; j < m1_nc; j++) \
1370 { \ 1370 { \
1371 for (octave_idx_type i = 0; i < m1_nr; i++) \ 1371 for (octave_idx_type i = 0; i < m1_nr; i++) \
1372 { \ 1372 { \
1373 bool el = (m1.elem (i, j) != LHS_ZERO) \ 1373 bool el = (m1.elem (i, j) != LHS_ZERO) \
1374 OP (m2.elem (i, j) != RHS_ZERO); \ 1374 OP (m2.elem (i, j) != RHS_ZERO); \
1375 if (el) \ 1375 if (el) \
1376 { \ 1376 { \
1377 r.data (ii) = el; \ 1377 r.data (ii) = el; \
1378 r.ridx (ii++) = i; \ 1378 r.ridx (ii++) = i; \
1379 } \ 1379 } \
1380 } \ 1380 } \
1381 r.cidx (j+1) = ii; \ 1381 r.cidx (j+1) = ii; \
1382 } \ 1382 } \
1383 } \ 1383 } \
1384 } \ 1384 } \
1385 else \ 1385 else \
1386 { \ 1386 { \
1387 if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0)) \ 1387 if ((m1_nr != 0 || m1_nc != 0) && (m2_nr != 0 || m2_nc != 0)) \
1388 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \ 1388 err_nonconformant (#F, m1_nr, m1_nc, m2_nr, m2_nc); \
1389 } \ 1389 } \
1390 return r; \ 1390 return r; \
1391 } 1391 }
1392 1392
1393 #define SPARSE_SMM_BOOL_OPS2(M1, M2, LHS_ZERO, RHS_ZERO) \ 1393 #define SPARSE_SMM_BOOL_OPS2(M1, M2, LHS_ZERO, RHS_ZERO) \
1394 SPARSE_SMM_BOOL_OP (mx_el_and, &&, M1, M2, LHS_ZERO, RHS_ZERO) \ 1394 SPARSE_SMM_BOOL_OP (mx_el_and, &&, M1, M2, LHS_ZERO, RHS_ZERO) \
1395 SPARSE_SMM_BOOL_OP (mx_el_or, ||, M1, M2, LHS_ZERO, RHS_ZERO) 1395 SPARSE_SMM_BOOL_OP (mx_el_or, ||, M1, M2, LHS_ZERO, RHS_ZERO)
1396 1396
1397 #define SPARSE_SMM_BOOL_OPS(M1, M2, ZERO) \ 1397 #define SPARSE_SMM_BOOL_OPS(M1, M2, ZERO) \
1398 SPARSE_SMM_BOOL_OPS2(M1, M2, ZERO, ZERO) 1398 SPARSE_SMM_BOOL_OPS2(M1, M2, ZERO, ZERO)
1399 1399
1400 // Avoid some code duplication. Maybe we should use templates. 1400 // Avoid some code duplication. Maybe we should use templates.
1401 1401
1402 #define SPARSE_CUMSUM(RET_TYPE, ELT_TYPE, FCN) \ 1402 #define SPARSE_CUMSUM(RET_TYPE, ELT_TYPE, FCN) \
1403 \ 1403 \
1404 octave_idx_type nr = rows (); \ 1404 octave_idx_type nr = rows (); \
1405 octave_idx_type nc = cols (); \ 1405 octave_idx_type nc = cols (); \
1406 \ 1406 \
1407 RET_TYPE retval; \ 1407 RET_TYPE retval; \
1408 \ 1408 \
1409 if (nr > 0 && nc > 0) \ 1409 if (nr > 0 && nc > 0) \
1410 { \ 1410 { \
1411 if ((nr == 1 && dim == -1) || dim == 1) \ 1411 if ((nr == 1 && dim == -1) || dim == 1) \
1412 /* Ugly!! Is there a better way? */ \ 1412 /* Ugly!! Is there a better way? */ \
1413 retval = transpose (). FCN (0) .transpose (); \ 1413 retval = transpose (). FCN (0) .transpose (); \
1414 else \ 1414 else \
1415 { \ 1415 { \
1416 octave_idx_type nel = 0; \ 1416 octave_idx_type nel = 0; \
1417 for (octave_idx_type i = 0; i < nc; i++) \ 1417 for (octave_idx_type i = 0; i < nc; i++) \
1418 { \ 1418 { \
1419 ELT_TYPE t = ELT_TYPE (); \ 1419 ELT_TYPE t = ELT_TYPE (); \
1420 for (octave_idx_type j = cidx (i); j < cidx (i+1); j++) \ 1420 for (octave_idx_type j = cidx (i); j < cidx (i+1); j++) \
1421 { \ 1421 { \
1422 t += data (j); \ 1422 t += data (j); \
1423 if (t != ELT_TYPE ()) \ 1423 if (t != ELT_TYPE ()) \
1424 { \ 1424 { \
1425 if (j == cidx (i+1) - 1) \ 1425 if (j == cidx (i+1) - 1) \
1426 nel += nr - ridx (j); \ 1426 nel += nr - ridx (j); \
1427 else \ 1427 else \
1428 nel += ridx (j+1) - ridx (j); \ 1428 nel += ridx (j+1) - ridx (j); \
1429 } \ 1429 } \
1430 } \ 1430 } \
1431 } \ 1431 } \
1432 retval = RET_TYPE (nr, nc, nel); \ 1432 retval = RET_TYPE (nr, nc, nel); \
1433 retval.cidx (0) = 0; \ 1433 retval.cidx (0) = 0; \
1434 octave_idx_type ii = 0; \ 1434 octave_idx_type ii = 0; \
1435 for (octave_idx_type i = 0; i < nc; i++) \ 1435 for (octave_idx_type i = 0; i < nc; i++) \
1436 { \ 1436 { \
1437 ELT_TYPE t = ELT_TYPE (); \ 1437 ELT_TYPE t = ELT_TYPE (); \
1438 for (octave_idx_type j = cidx (i); j < cidx (i+1); j++) \ 1438 for (octave_idx_type j = cidx (i); j < cidx (i+1); j++) \
1439 { \ 1439 { \
1440 t += data (j); \ 1440 t += data (j); \
1441 if (t != ELT_TYPE ()) \ 1441 if (t != ELT_TYPE ()) \
1442 { \ 1442 { \
1443 if (j == cidx (i+1) - 1) \ 1443 if (j == cidx (i+1) - 1) \
1444 { \ 1444 { \
1445 for (octave_idx_type k = ridx (j); k < nr; k++) \ 1445 for (octave_idx_type k = ridx (j); k < nr; k++) \
1446 { \ 1446 { \
1447 retval.data (ii) = t; \ 1447 retval.data (ii) = t; \
1448 retval.ridx (ii++) = k; \ 1448 retval.ridx (ii++) = k; \
1449 } \ 1449 } \
1450 } \ 1450 } \
1451 else \ 1451 else \
1452 { \ 1452 { \
1453 for (octave_idx_type k = ridx (j); k < ridx (j+1); k++) \ 1453 for (octave_idx_type k = ridx (j); k < ridx (j+1); k++) \
1454 { \ 1454 { \
1455 retval.data (ii) = t; \ 1455 retval.data (ii) = t; \
1456 retval.ridx (ii++) = k; \ 1456 retval.ridx (ii++) = k; \
1457 } \ 1457 } \
1458 } \ 1458 } \
1459 } \ 1459 } \
1460 } \ 1460 } \
1461 retval.cidx (i+1) = ii; \ 1461 retval.cidx (i+1) = ii; \
1462 } \ 1462 } \
1463 } \ 1463 } \
1464 } \ 1464 } \
1465 else \ 1465 else \
1466 retval = RET_TYPE (nr,nc); \ 1466 retval = RET_TYPE (nr,nc); \
1467 \ 1467 \
1468 return retval 1468 return retval
1469 1469
1470 #define SPARSE_CUMPROD(RET_TYPE, ELT_TYPE, FCN) \ 1470 #define SPARSE_CUMPROD(RET_TYPE, ELT_TYPE, FCN) \
1471 \ 1471 \
1472 octave_idx_type nr = rows (); \ 1472 octave_idx_type nr = rows (); \
1473 octave_idx_type nc = cols (); \ 1473 octave_idx_type nc = cols (); \
1474 \ 1474 \
1475 RET_TYPE retval; \ 1475 RET_TYPE retval; \
1476 \ 1476 \
1477 if (nr > 0 && nc > 0) \ 1477 if (nr > 0 && nc > 0) \
1478 { \ 1478 { \
1479 if ((nr == 1 && dim == -1) || dim == 1) \ 1479 if ((nr == 1 && dim == -1) || dim == 1) \
1480 /* Ugly!! Is there a better way? */ \ 1480 /* Ugly!! Is there a better way? */ \
1481 retval = transpose (). FCN (0) .transpose (); \ 1481 retval = transpose (). FCN (0) .transpose (); \
1482 else \ 1482 else \
1483 { \ 1483 { \
1484 octave_idx_type nel = 0; \ 1484 octave_idx_type nel = 0; \
1485 for (octave_idx_type i = 0; i < nc; i++) \ 1485 for (octave_idx_type i = 0; i < nc; i++) \
1486 { \ 1486 { \
1487 octave_idx_type jj = 0; \ 1487 octave_idx_type jj = 0; \
1488 for (octave_idx_type j = cidx (i); j < cidx (i+1); j++) \ 1488 for (octave_idx_type j = cidx (i); j < cidx (i+1); j++) \
1489 { \ 1489 { \
1490 if (jj == ridx (j)) \ 1490 if (jj == ridx (j)) \
1491 { \ 1491 { \
1492 nel++; \ 1492 nel++; \
1493 jj++; \ 1493 jj++; \
1494 } \ 1494 } \
1495 else \ 1495 else \
1496 break; \ 1496 break; \
1497 } \ 1497 } \
1498 } \ 1498 } \
1499 retval = RET_TYPE (nr, nc, nel); \ 1499 retval = RET_TYPE (nr, nc, nel); \
1500 retval.cidx (0) = 0; \ 1500 retval.cidx (0) = 0; \
1501 octave_idx_type ii = 0; \ 1501 octave_idx_type ii = 0; \
1502 for (octave_idx_type i = 0; i < nc; i++) \ 1502 for (octave_idx_type i = 0; i < nc; i++) \
1503 { \ 1503 { \
1504 ELT_TYPE t = ELT_TYPE (1.); \ 1504 ELT_TYPE t = ELT_TYPE (1.); \
1505 octave_idx_type jj = 0; \ 1505 octave_idx_type jj = 0; \
1506 for (octave_idx_type j = cidx (i); j < cidx (i+1); j++) \ 1506 for (octave_idx_type j = cidx (i); j < cidx (i+1); j++) \
1507 { \ 1507 { \
1508 if (jj == ridx (j)) \ 1508 if (jj == ridx (j)) \
1509 { \ 1509 { \
1510 t *= data (j); \ 1510 t *= data (j); \
1511 retval.data (ii) = t; \ 1511 retval.data (ii) = t; \
1512 retval.ridx (ii++) = jj++; \ 1512 retval.ridx (ii++) = jj++; \
1513 } \ 1513 } \
1514 else \ 1514 else \
1515 break; \ 1515 break; \
1516 } \ 1516 } \
1517 retval.cidx (i+1) = ii; \ 1517 retval.cidx (i+1) = ii; \
1518 } \ 1518 } \
1519 } \ 1519 } \
1520 } \ 1520 } \
1521 else \ 1521 else \
1522 retval = RET_TYPE (nr,nc); \ 1522 retval = RET_TYPE (nr,nc); \
1523 \ 1523 \
1524 return retval 1524 return retval
1525 1525
1526 #define SPARSE_BASE_REDUCTION_OP(RET_TYPE, EL_TYPE, ROW_EXPR, COL_EXPR, \ 1526 #define SPARSE_BASE_REDUCTION_OP(RET_TYPE, EL_TYPE, ROW_EXPR, COL_EXPR, \
1527 INIT_VAL, MT_RESULT) \ 1527 INIT_VAL, MT_RESULT) \
1528 \ 1528 \
1529 octave_idx_type nr = rows (); \ 1529 octave_idx_type nr = rows (); \
1530 octave_idx_type nc = cols (); \ 1530 octave_idx_type nc = cols (); \
1531 \ 1531 \
1532 RET_TYPE retval; \ 1532 RET_TYPE retval; \
1533 \ 1533 \
1534 if (nr > 0 && nc > 0) \ 1534 if (nr > 0 && nc > 0) \
1535 { \ 1535 { \
1536 if ((nr == 1 && dim == -1) || dim == 1) \ 1536 if ((nr == 1 && dim == -1) || dim == 1) \
1537 { \ 1537 { \
1538 /* Define j here to allow fancy definition for prod method */ \ 1538 /* Define j here to allow fancy definition for prod method */ \
1539 octave_idx_type j = 0; \ 1539 octave_idx_type j = 0; \
1540 OCTAVE_LOCAL_BUFFER (EL_TYPE, tmp, nr); \ 1540 OCTAVE_LOCAL_BUFFER (EL_TYPE, tmp, nr); \
1541 \ 1541 \
1542 for (octave_idx_type i = 0; i < nr; i++) \ 1542 for (octave_idx_type i = 0; i < nr; i++) \
1543 tmp[i] = INIT_VAL; \ 1543 tmp[i] = INIT_VAL; \
1544 for (j = 0; j < nc; j++) \ 1544 for (j = 0; j < nc; j++) \
1545 { \ 1545 { \
1546 for (octave_idx_type i = cidx (j); i < cidx (j + 1); i++) \ 1546 for (octave_idx_type i = cidx (j); i < cidx (j + 1); i++) \
1547 { \ 1547 { \
1548 ROW_EXPR; \ 1548 ROW_EXPR; \
1549 } \ 1549 } \
1550 } \ 1550 } \
1551 octave_idx_type nel = 0; \ 1551 octave_idx_type nel = 0; \
1552 for (octave_idx_type i = 0; i < nr; i++) \ 1552 for (octave_idx_type i = 0; i < nr; i++) \
1553 if (tmp[i] != EL_TYPE ()) \ 1553 if (tmp[i] != EL_TYPE ()) \
1554 nel++; \ 1554 nel++; \
1555 retval = RET_TYPE (nr, static_cast<octave_idx_type> (1), nel); \ 1555 retval = RET_TYPE (nr, static_cast<octave_idx_type> (1), nel); \
1556 retval.cidx (0) = 0; \ 1556 retval.cidx (0) = 0; \
1557 retval.cidx (1) = nel; \ 1557 retval.cidx (1) = nel; \
1558 nel = 0; \ 1558 nel = 0; \
1559 for (octave_idx_type i = 0; i < nr; i++) \ 1559 for (octave_idx_type i = 0; i < nr; i++) \
1560 if (tmp[i] != EL_TYPE ()) \ 1560 if (tmp[i] != EL_TYPE ()) \
1561 { \ 1561 { \
1562 retval.data (nel) = tmp[i]; \ 1562 retval.data (nel) = tmp[i]; \
1563 retval.ridx (nel++) = i; \ 1563 retval.ridx (nel++) = i; \
1564 } \ 1564 } \
1565 } \ 1565 } \
1566 else \ 1566 else \
1567 { \ 1567 { \
1568 OCTAVE_LOCAL_BUFFER (EL_TYPE, tmp, nc); \ 1568 OCTAVE_LOCAL_BUFFER (EL_TYPE, tmp, nc); \
1569 \ 1569 \
1570 for (octave_idx_type j = 0; j < nc; j++) \ 1570 for (octave_idx_type j = 0; j < nc; j++) \
1571 { \ 1571 { \
1572 tmp[j] = INIT_VAL; \ 1572 tmp[j] = INIT_VAL; \
1573 for (octave_idx_type i = cidx (j); i < cidx (j + 1); i++) \ 1573 for (octave_idx_type i = cidx (j); i < cidx (j + 1); i++) \
1574 { \ 1574 { \
1575 COL_EXPR; \ 1575 COL_EXPR; \
1576 } \ 1576 } \
1577 } \ 1577 } \
1578 octave_idx_type nel = 0; \ 1578 octave_idx_type nel = 0; \
1579 for (octave_idx_type i = 0; i < nc; i++) \ 1579 for (octave_idx_type i = 0; i < nc; i++) \
1580 if (tmp[i] != EL_TYPE ()) \ 1580 if (tmp[i] != EL_TYPE ()) \
1581 nel++; \ 1581 nel++; \
1582 retval = RET_TYPE (static_cast<octave_idx_type> (1), nc, nel); \ 1582 retval = RET_TYPE (static_cast<octave_idx_type> (1), nc, nel); \
1583 retval.cidx (0) = 0; \ 1583 retval.cidx (0) = 0; \
1584 nel = 0; \ 1584 nel = 0; \
1585 for (octave_idx_type i = 0; i < nc; i++) \ 1585 for (octave_idx_type i = 0; i < nc; i++) \
1586 if (tmp[i] != EL_TYPE ()) \ 1586 if (tmp[i] != EL_TYPE ()) \
1587 { \ 1587 { \
1588 retval.data (nel) = tmp[i]; \ 1588 retval.data (nel) = tmp[i]; \
1589 retval.ridx (nel++) = 0; \ 1589 retval.ridx (nel++) = 0; \
1590 retval.cidx (i+1) = retval.cidx (i) + 1; \ 1590 retval.cidx (i+1) = retval.cidx (i) + 1; \
1591 } \ 1591 } \
1592 else \ 1592 else \
1593 retval.cidx (i+1) = retval.cidx (i); \ 1593 retval.cidx (i+1) = retval.cidx (i); \
1594 } \ 1594 } \
1595 } \ 1595 } \
1596 else if (nc == 0 && (nr == 0 || (nr == 1 && dim == -1))) \ 1596 else if (nc == 0 && (nr == 0 || (nr == 1 && dim == -1))) \
1597 { \ 1597 { \
1598 if (MT_RESULT) \ 1598 if (MT_RESULT) \
1599 { \ 1599 { \
1600 retval = RET_TYPE (static_cast<octave_idx_type> (1), \ 1600 retval = RET_TYPE (static_cast<octave_idx_type> (1), \
1601 static_cast<octave_idx_type> (1), \ 1601 static_cast<octave_idx_type> (1), \
1602 static_cast<octave_idx_type> (1)); \ 1602 static_cast<octave_idx_type> (1)); \
1603 retval.cidx (0) = 0; \ 1603 retval.cidx (0) = 0; \
1604 retval.cidx (1) = 1; \ 1604 retval.cidx (1) = 1; \
1605 retval.ridx (0) = 0; \ 1605 retval.ridx (0) = 0; \
1606 retval.data (0) = MT_RESULT; \ 1606 retval.data (0) = MT_RESULT; \
1607 } \ 1607 } \
1608 else \ 1608 else \
1609 retval = RET_TYPE (static_cast<octave_idx_type> (1), \ 1609 retval = RET_TYPE (static_cast<octave_idx_type> (1), \
1610 static_cast<octave_idx_type> (1), \ 1610 static_cast<octave_idx_type> (1), \
1611 static_cast<octave_idx_type> (0)); \ 1611 static_cast<octave_idx_type> (0)); \
1612 } \ 1612 } \
1613 else if (nr == 0 && (dim == 0 || dim == -1)) \ 1613 else if (nr == 0 && (dim == 0 || dim == -1)) \
1614 { \ 1614 { \
1615 if (MT_RESULT) \ 1615 if (MT_RESULT) \
1616 { \ 1616 { \
1617 retval = RET_TYPE (static_cast<octave_idx_type> (1), nc, nc); \ 1617 retval = RET_TYPE (static_cast<octave_idx_type> (1), nc, nc); \
1618 retval.cidx (0) = 0; \ 1618 retval.cidx (0) = 0; \
1619 for (octave_idx_type i = 0; i < nc ; i++) \ 1619 for (octave_idx_type i = 0; i < nc ; i++) \
1620 { \ 1620 { \
1621 retval.ridx (i) = 0; \ 1621 retval.ridx (i) = 0; \
1622 retval.cidx (i+1) = i+1; \ 1622 retval.cidx (i+1) = i+1; \
1623 retval.data (i) = MT_RESULT; \ 1623 retval.data (i) = MT_RESULT; \
1624 } \ 1624 } \
1625 } \ 1625 } \
1626 else \ 1626 else \
1627 retval = RET_TYPE (static_cast<octave_idx_type> (1), nc, \ 1627 retval = RET_TYPE (static_cast<octave_idx_type> (1), nc, \
1628 static_cast<octave_idx_type> (0)); \ 1628 static_cast<octave_idx_type> (0)); \
1629 } \ 1629 } \
1630 else if (nc == 0 && dim == 1) \ 1630 else if (nc == 0 && dim == 1) \
1631 { \ 1631 { \
1632 if (MT_RESULT) \ 1632 if (MT_RESULT) \
1633 { \ 1633 { \
1634 retval = RET_TYPE (nr, static_cast<octave_idx_type> (1), nr); \ 1634 retval = RET_TYPE (nr, static_cast<octave_idx_type> (1), nr); \
1635 retval.cidx (0) = 0; \ 1635 retval.cidx (0) = 0; \
1636 retval.cidx (1) = nr; \ 1636 retval.cidx (1) = nr; \
1637 for (octave_idx_type i = 0; i < nr; i++) \ 1637 for (octave_idx_type i = 0; i < nr; i++) \
1638 { \ 1638 { \
1639 retval.ridx (i) = i; \ 1639 retval.ridx (i) = i; \
1640 retval.data (i) = MT_RESULT; \ 1640 retval.data (i) = MT_RESULT; \
1641 } \ 1641 } \
1642 } \ 1642 } \
1643 else \ 1643 else \
1644 retval = RET_TYPE (nr, static_cast<octave_idx_type> (1), \ 1644 retval = RET_TYPE (nr, static_cast<octave_idx_type> (1), \
1645 static_cast<octave_idx_type> (0)); \ 1645 static_cast<octave_idx_type> (0)); \
1646 } \ 1646 } \
1647 else \ 1647 else \
1648 retval.resize (nr > 0, nc > 0); \ 1648 retval.resize (nr > 0, nc > 0); \
1649 \ 1649 \
1650 return retval 1650 return retval
1651 1651
1652 #define SPARSE_REDUCTION_OP_ROW_EXPR(OP) \ 1652 #define SPARSE_REDUCTION_OP_ROW_EXPR(OP) \
1653 tmp[ridx (i)] OP data (i) 1653 tmp[ridx (i)] OP data (i)
1654 1654
1655 #define SPARSE_REDUCTION_OP_COL_EXPR(OP) \ 1655 #define SPARSE_REDUCTION_OP_COL_EXPR(OP) \
1656 tmp[j] OP data (i) 1656 tmp[j] OP data (i)
1657 1657
1658 #define SPARSE_REDUCTION_OP(RET_TYPE, EL_TYPE, OP, INIT_VAL, MT_RESULT) \ 1658 #define SPARSE_REDUCTION_OP(RET_TYPE, EL_TYPE, OP, INIT_VAL, MT_RESULT) \
1659 SPARSE_BASE_REDUCTION_OP (RET_TYPE, EL_TYPE, \ 1659 SPARSE_BASE_REDUCTION_OP (RET_TYPE, EL_TYPE, \
1660 SPARSE_REDUCTION_OP_ROW_EXPR (OP), \ 1660 SPARSE_REDUCTION_OP_ROW_EXPR (OP), \
1661 SPARSE_REDUCTION_OP_COL_EXPR (OP), \ 1661 SPARSE_REDUCTION_OP_COL_EXPR (OP), \
1662 INIT_VAL, MT_RESULT) 1662 INIT_VAL, MT_RESULT)
1663 1663
1664 // Don't break from this loop if the test succeeds because 1664 // Don't break from this loop if the test succeeds because
1665 // we are looping over the rows and not the columns in the inner loop. 1665 // we are looping over the rows and not the columns in the inner loop.
1666 #define SPARSE_ANY_ALL_OP_ROW_CODE(TEST_OP, TEST_TRUE_VAL) \ 1666 #define SPARSE_ANY_ALL_OP_ROW_CODE(TEST_OP, TEST_TRUE_VAL) \
1667 if (data (i) TEST_OP 0.0) \ 1667 if (data (i) TEST_OP 0.0) \
1668 tmp[ridx (i)] = TEST_TRUE_VAL; 1668 tmp[ridx (i)] = TEST_TRUE_VAL;
1669 1669
1670 #define SPARSE_ANY_ALL_OP_COL_CODE(TEST_OP, TEST_TRUE_VAL) \ 1670 #define SPARSE_ANY_ALL_OP_COL_CODE(TEST_OP, TEST_TRUE_VAL) \
1671 if (data (i) TEST_OP 0.0) \ 1671 if (data (i) TEST_OP 0.0) \
1672 { \ 1672 { \
1673 tmp[j] = TEST_TRUE_VAL; \ 1673 tmp[j] = TEST_TRUE_VAL; \
1674 break; \ 1674 break; \
1675 } 1675 }
1676 1676
1677 #define SPARSE_ANY_ALL_OP(DIM, INIT_VAL, MT_RESULT, TEST_OP, TEST_TRUE_VAL) \ 1677 #define SPARSE_ANY_ALL_OP(DIM, INIT_VAL, MT_RESULT, TEST_OP, TEST_TRUE_VAL) \
1678 SPARSE_BASE_REDUCTION_OP (SparseBoolMatrix, char, \ 1678 SPARSE_BASE_REDUCTION_OP (SparseBoolMatrix, char, \
1679 SPARSE_ANY_ALL_OP_ROW_CODE (TEST_OP, TEST_TRUE_VAL), \ 1679 SPARSE_ANY_ALL_OP_ROW_CODE (TEST_OP, TEST_TRUE_VAL), \
1680 SPARSE_ANY_ALL_OP_COL_CODE (TEST_OP, TEST_TRUE_VAL), \ 1680 SPARSE_ANY_ALL_OP_COL_CODE (TEST_OP, TEST_TRUE_VAL), \
1681 INIT_VAL, MT_RESULT) 1681 INIT_VAL, MT_RESULT)
1682 1682
1683 #define SPARSE_ALL_OP(DIM) \ 1683 #define SPARSE_ALL_OP(DIM) \
1684 if ((rows () == 1 && dim == -1) || dim == 1) \ 1684 if ((rows () == 1 && dim == -1) || dim == 1) \
1685 return transpose (). all (0). transpose (); \ 1685 return transpose (). all (0). transpose (); \
1686 else \ 1686 else \
1687 { \ 1687 { \
1688 SPARSE_ANY_ALL_OP (DIM, (cidx (j+1) - cidx (j) < nr ? false : true), \ 1688 SPARSE_ANY_ALL_OP (DIM, (cidx (j+1) - cidx (j) < nr ? false : true), \
1689 true, ==, false); \ 1689 true, ==, false); \
1690 } 1690 }
1691 1691
1692 #define SPARSE_ANY_OP(DIM) SPARSE_ANY_ALL_OP (DIM, false, false, !=, true) 1692 #define SPARSE_ANY_OP(DIM) SPARSE_ANY_ALL_OP (DIM, false, false, !=, true)
1693 1693
1694 #define SPARSE_SPARSE_MUL(RET_TYPE, RET_EL_TYPE, EL_TYPE) \ 1694 #define SPARSE_SPARSE_MUL(RET_TYPE, RET_EL_TYPE, EL_TYPE) \
1695 octave_idx_type nr = m.rows (); \ 1695 octave_idx_type nr = m.rows (); \
1696 octave_idx_type nc = m.cols (); \ 1696 octave_idx_type nc = m.cols (); \
1697 \ 1697 \
1698 octave_idx_type a_nr = a.rows (); \ 1698 octave_idx_type a_nr = a.rows (); \
1699 octave_idx_type a_nc = a.cols (); \ 1699 octave_idx_type a_nc = a.cols (); \
1700 \ 1700 \
1701 if (nr == 1 && nc == 1) \ 1701 if (nr == 1 && nc == 1) \
1702 { \ 1702 { \
1703 RET_EL_TYPE s = m.elem (0,0); \ 1703 RET_EL_TYPE s = m.elem (0,0); \
1704 octave_idx_type nz = a.nnz (); \ 1704 octave_idx_type nz = a.nnz (); \
1705 RET_TYPE r (a_nr, a_nc, nz); \ 1705 RET_TYPE r (a_nr, a_nc, nz); \
1706 \ 1706 \
1707 for (octave_idx_type i = 0; i < nz; i++) \ 1707 for (octave_idx_type i = 0; i < nz; i++) \
1708 { \ 1708 { \
1709 octave_quit (); \ 1709 octave_quit (); \
1710 r.data (i) = s * a.data (i); \ 1710 r.data (i) = s * a.data (i); \
1711 r.ridx (i) = a.ridx (i); \ 1711 r.ridx (i) = a.ridx (i); \
1712 } \ 1712 } \
1713 for (octave_idx_type i = 0; i < a_nc + 1; i++) \ 1713 for (octave_idx_type i = 0; i < a_nc + 1; i++) \
1714 { \ 1714 { \
1715 octave_quit (); \ 1715 octave_quit (); \
1716 r.cidx (i) = a.cidx (i); \ 1716 r.cidx (i) = a.cidx (i); \
1717 } \ 1717 } \
1718 \ 1718 \
1719 r.maybe_compress (true); \ 1719 r.maybe_compress (true); \
1720 return r; \ 1720 return r; \
1721 } \ 1721 } \
1722 else if (a_nr == 1 && a_nc == 1) \ 1722 else if (a_nr == 1 && a_nc == 1) \
1723 { \ 1723 { \
1724 RET_EL_TYPE s = a.elem (0,0); \ 1724 RET_EL_TYPE s = a.elem (0,0); \
1725 octave_idx_type nz = m.nnz (); \ 1725 octave_idx_type nz = m.nnz (); \
1726 RET_TYPE r (nr, nc, nz); \ 1726 RET_TYPE r (nr, nc, nz); \
1727 \ 1727 \
1728 for (octave_idx_type i = 0; i < nz; i++) \ 1728 for (octave_idx_type i = 0; i < nz; i++) \
1729 { \ 1729 { \
1730 octave_quit (); \ 1730 octave_quit (); \
1731 r.data (i) = m.data (i) * s; \ 1731 r.data (i) = m.data (i) * s; \
1732 r.ridx (i) = m.ridx (i); \ 1732 r.ridx (i) = m.ridx (i); \
1733 } \ 1733 } \
1734 for (octave_idx_type i = 0; i < nc + 1; i++) \ 1734 for (octave_idx_type i = 0; i < nc + 1; i++) \
1735 { \ 1735 { \
1736 octave_quit (); \ 1736 octave_quit (); \
1737 r.cidx (i) = m.cidx (i); \ 1737 r.cidx (i) = m.cidx (i); \
1738 } \ 1738 } \
1739 \ 1739 \
1740 r.maybe_compress (true); \ 1740 r.maybe_compress (true); \
1741 return r; \ 1741 return r; \
1742 } \ 1742 } \
1743 else if (nc != a_nr) \ 1743 else if (nc != a_nr) \
1744 err_nonconformant ("operator *", nr, nc, a_nr, a_nc); \ 1744 err_nonconformant ("operator *", nr, nc, a_nr, a_nc); \
1745 else \ 1745 else \
1746 { \ 1746 { \
1747 OCTAVE_LOCAL_BUFFER (octave_idx_type, w, nr); \ 1747 OCTAVE_LOCAL_BUFFER (octave_idx_type, w, nr); \
1748 RET_TYPE retval (nr, a_nc, static_cast<octave_idx_type> (0)); \ 1748 RET_TYPE retval (nr, a_nc, static_cast<octave_idx_type> (0)); \
1749 for (octave_idx_type i = 0; i < nr; i++) \ 1749 for (octave_idx_type i = 0; i < nr; i++) \
1750 w[i] = 0; \ 1750 w[i] = 0; \
1751 retval.xcidx (0) = 0; \ 1751 retval.xcidx (0) = 0; \
1752 \ 1752 \
1753 octave_idx_type nel = 0; \ 1753 octave_idx_type nel = 0; \
1754 \ 1754 \
1755 for (octave_idx_type i = 0; i < a_nc; i++) \ 1755 for (octave_idx_type i = 0; i < a_nc; i++) \
1756 { \ 1756 { \
1757 for (octave_idx_type j = a.cidx (i); j < a.cidx (i+1); j++) \ 1757 for (octave_idx_type j = a.cidx (i); j < a.cidx (i+1); j++) \
1758 { \ 1758 { \
1759 octave_idx_type col = a.ridx (j); \ 1759 octave_idx_type col = a.ridx (j); \
1760 for (octave_idx_type k = m.cidx (col) ; k < m.cidx (col+1); k++) \ 1760 for (octave_idx_type k = m.cidx (col) ; k < m.cidx (col+1); k++) \
1761 { \ 1761 { \
1762 if (w[m.ridx (k)] < i + 1) \ 1762 if (w[m.ridx (k)] < i + 1) \
1763 { \ 1763 { \
1764 w[m.ridx (k)] = i + 1; \ 1764 w[m.ridx (k)] = i + 1; \
1765 nel++; \ 1765 nel++; \
1766 } \ 1766 } \
1767 octave_quit (); \ 1767 octave_quit (); \
1768 } \ 1768 } \
1769 } \ 1769 } \
1770 retval.xcidx (i+1) = nel; \ 1770 retval.xcidx (i+1) = nel; \
1771 } \ 1771 } \
1772 \ 1772 \
1773 if (nel == 0) \ 1773 if (nel == 0) \
1774 return RET_TYPE (nr, a_nc); \ 1774 return RET_TYPE (nr, a_nc); \
1775 else \ 1775 else \
1776 { \ 1776 { \
1777 for (octave_idx_type i = 0; i < nr; i++) \ 1777 for (octave_idx_type i = 0; i < nr; i++) \
1778 w[i] = 0; \ 1778 w[i] = 0; \
1779 \ 1779 \
1780 OCTAVE_LOCAL_BUFFER (RET_EL_TYPE, Xcol, nr); \ 1780 OCTAVE_LOCAL_BUFFER (RET_EL_TYPE, Xcol, nr); \
1781 \ 1781 \
1782 retval.change_capacity (nel); \ 1782 retval.change_capacity (nel); \
1783 /* The optimal break-point as estimated from simulations */ \ 1783 /* The optimal break-point as estimated from simulations */ \
1784 /* Note that Mergesort is O(nz log(nz)) while searching all */ \ 1784 /* Note that Mergesort is O(nz log(nz)) while searching all */ \
1785 /* values is O(nr), where nz here is nonzero per row of */ \ 1785 /* values is O(nr), where nz here is nonzero per row of */ \
1786 /* length nr. The test itself was then derived from the */ \ 1786 /* length nr. The test itself was then derived from the */ \
1787 /* simulation with random square matrices and the observation */ \ 1787 /* simulation with random square matrices and the observation */ \
1788 /* of the number of nonzero elements in the output matrix */ \ 1788 /* of the number of nonzero elements in the output matrix */ \
1789 /* it was found that the breakpoints were */ \ 1789 /* it was found that the breakpoints were */ \
1790 /* nr: 500 1000 2000 5000 10000 */ \ 1790 /* nr: 500 1000 2000 5000 10000 */ \
1791 /* nz: 6 25 97 585 2202 */ \ 1791 /* nz: 6 25 97 585 2202 */ \
1792 /* The below is a simplication of the 'polyfit'-ed parameters */ \ 1792 /* The below is a simplication of the 'polyfit'-ed parameters */ \
1793 /* to these breakpoints */ \ 1793 /* to these breakpoints */ \
1794 octave_idx_type n_per_col = (a_nc > 43000 ? 43000 : \ 1794 octave_idx_type n_per_col = (a_nc > 43000 ? 43000 : \
1795 (a_nc * a_nc) / 43000); \ 1795 (a_nc * a_nc) / 43000); \
1796 octave_idx_type ii = 0; \ 1796 octave_idx_type ii = 0; \
1797 octave_idx_type *ri = retval.xridx (); \ 1797 octave_idx_type *ri = retval.xridx (); \
1798 octave_sort<octave_idx_type> sort; \ 1798 octave_sort<octave_idx_type> sort; \
1799 \ 1799 \
1800 for (octave_idx_type i = 0; i < a_nc ; i++) \ 1800 for (octave_idx_type i = 0; i < a_nc ; i++) \
1801 { \ 1801 { \
1802 if (retval.xcidx (i+1) - retval.xcidx (i) > n_per_col) \ 1802 if (retval.xcidx (i+1) - retval.xcidx (i) > n_per_col) \
1803 { \ 1803 { \
1804 for (octave_idx_type j = a.cidx (i); j < a.cidx (i+1); j++) \ 1804 for (octave_idx_type j = a.cidx (i); j < a.cidx (i+1); j++) \
1805 { \ 1805 { \
1806 octave_idx_type col = a.ridx (j); \ 1806 octave_idx_type col = a.ridx (j); \
1807 EL_TYPE tmpval = a.data (j); \ 1807 EL_TYPE tmpval = a.data (j); \
1808 for (octave_idx_type k = m.cidx (col) ; \ 1808 for (octave_idx_type k = m.cidx (col) ; \
1809 k < m.cidx (col+1); k++) \ 1809 k < m.cidx (col+1); k++) \
1810 { \ 1810 { \
1811 octave_quit (); \ 1811 octave_quit (); \
1812 octave_idx_type row = m.ridx (k); \ 1812 octave_idx_type row = m.ridx (k); \
1813 if (w[row] < i + 1) \ 1813 if (w[row] < i + 1) \
1814 { \ 1814 { \
1815 w[row] = i + 1; \ 1815 w[row] = i + 1; \
1816 Xcol[row] = tmpval * m.data (k); \ 1816 Xcol[row] = tmpval * m.data (k); \
1817 } \ 1817 } \
1818 else \ 1818 else \
1819 Xcol[row] += tmpval * m.data (k); \ 1819 Xcol[row] += tmpval * m.data (k); \
1820 } \ 1820 } \
1821 } \ 1821 } \
1822 for (octave_idx_type k = 0; k < nr; k++) \ 1822 for (octave_idx_type k = 0; k < nr; k++) \
1823 if (w[k] == i + 1) \ 1823 if (w[k] == i + 1) \
1824 { \ 1824 { \
1825 retval.xdata (ii) = Xcol[k]; \ 1825 retval.xdata (ii) = Xcol[k]; \
1826 retval.xridx (ii++) = k; \ 1826 retval.xridx (ii++) = k; \
1827 } \ 1827 } \
1828 } \ 1828 } \
1829 else \ 1829 else \
1830 { \ 1830 { \
1831 for (octave_idx_type j = a.cidx (i); j < a.cidx (i+1); j++) \ 1831 for (octave_idx_type j = a.cidx (i); j < a.cidx (i+1); j++) \
1832 { \ 1832 { \
1833 octave_idx_type col = a.ridx (j); \ 1833 octave_idx_type col = a.ridx (j); \
1834 EL_TYPE tmpval = a.data (j); \ 1834 EL_TYPE tmpval = a.data (j); \
1835 for (octave_idx_type k = m.cidx (col) ; \ 1835 for (octave_idx_type k = m.cidx (col) ; \
1836 k < m.cidx (col+1); k++) \ 1836 k < m.cidx (col+1); k++) \
1837 { \ 1837 { \
1838 octave_quit (); \ 1838 octave_quit (); \
1839 octave_idx_type row = m.ridx (k); \ 1839 octave_idx_type row = m.ridx (k); \
1840 if (w[row] < i + 1) \ 1840 if (w[row] < i + 1) \
1841 { \ 1841 { \
1842 w[row] = i + 1; \ 1842 w[row] = i + 1; \
1843 retval.xridx (ii++) = row;\ 1843 retval.xridx (ii++) = row; \
1844 Xcol[row] = tmpval * m.data (k); \ 1844 Xcol[row] = tmpval * m.data (k); \
1845 } \ 1845 } \
1846 else \ 1846 else \
1847 Xcol[row] += tmpval * m.data (k); \ 1847 Xcol[row] += tmpval * m.data (k); \
1848 } \ 1848 } \
1849 } \ 1849 } \
1850 sort.sort (ri + retval.xcidx (i), ii - retval.xcidx (i)); \ 1850 sort.sort (ri + retval.xcidx (i), ii - retval.xcidx (i)); \
1851 for (octave_idx_type k = retval.xcidx (i); k < ii; k++) \ 1851 for (octave_idx_type k = retval.xcidx (i); k < ii; k++) \
1852 retval.xdata (k) = Xcol[retval.xridx (k)]; \ 1852 retval.xdata (k) = Xcol[retval.xridx (k)]; \
1853 } \ 1853 } \
1854 } \ 1854 } \
1855 retval.maybe_compress (true);\ 1855 retval.maybe_compress (true); \
1856 return retval; \ 1856 return retval; \
1857 } \ 1857 } \
1858 } 1858 }
1859 1859
1860 #define SPARSE_FULL_MUL(RET_TYPE, EL_TYPE, ZERO) \ 1860 #define SPARSE_FULL_MUL(RET_TYPE, EL_TYPE, ZERO) \
1861 octave_idx_type nr = m.rows (); \ 1861 octave_idx_type nr = m.rows (); \
1862 octave_idx_type nc = m.cols (); \ 1862 octave_idx_type nc = m.cols (); \
1863 \ 1863 \
1864 octave_idx_type a_nr = a.rows (); \ 1864 octave_idx_type a_nr = a.rows (); \
1865 octave_idx_type a_nc = a.cols (); \ 1865 octave_idx_type a_nc = a.cols (); \
1866 \ 1866 \
1867 if (nr == 1 && nc == 1) \ 1867 if (nr == 1 && nc == 1) \
1868 { \ 1868 { \
1869 RET_TYPE retval = m.elem (0,0) * a; \ 1869 RET_TYPE retval = m.elem (0,0) * a; \
1870 return retval; \ 1870 return retval; \
1871 } \ 1871 } \
1872 else if (nc != a_nr) \ 1872 else if (nc != a_nr) \
1873 err_nonconformant ("operator *", nr, nc, a_nr, a_nc); \ 1873 err_nonconformant ("operator *", nr, nc, a_nr, a_nc); \
1874 else \ 1874 else \
1875 { \ 1875 { \
1876 RET_TYPE retval (nr, a_nc, ZERO); \ 1876 RET_TYPE retval (nr, a_nc, ZERO); \
1877 \ 1877 \
1878 for (octave_idx_type i = 0; i < a_nc ; i++) \ 1878 for (octave_idx_type i = 0; i < a_nc ; i++) \
1879 { \ 1879 { \
1880 for (octave_idx_type j = 0; j < a_nr; j++) \ 1880 for (octave_idx_type j = 0; j < a_nr; j++) \
1881 { \ 1881 { \
1882 octave_quit (); \ 1882 octave_quit (); \
1883 \ 1883 \
1884 EL_TYPE tmpval = a.elem (j,i); \ 1884 EL_TYPE tmpval = a.elem (j,i); \
1885 for (octave_idx_type k = m.cidx (j) ; k < m.cidx (j+1); k++) \ 1885 for (octave_idx_type k = m.cidx (j) ; k < m.cidx (j+1); k++) \
1886 retval.elem (m.ridx (k),i) += tmpval * m.data (k); \ 1886 retval.elem (m.ridx (k),i) += tmpval * m.data (k); \
1887 } \ 1887 } \
1888 } \ 1888 } \
1889 return retval; \ 1889 return retval; \
1890 } 1890 }
1891 1891
1892 #define SPARSE_FULL_TRANS_MUL(RET_TYPE, EL_TYPE, ZERO, CONJ_OP) \ 1892 #define SPARSE_FULL_TRANS_MUL(RET_TYPE, EL_TYPE, ZERO, CONJ_OP) \
1893 octave_idx_type nr = m.rows (); \ 1893 octave_idx_type nr = m.rows (); \
1894 octave_idx_type nc = m.cols (); \ 1894 octave_idx_type nc = m.cols (); \
1895 \ 1895 \
1896 octave_idx_type a_nr = a.rows (); \ 1896 octave_idx_type a_nr = a.rows (); \
1897 octave_idx_type a_nc = a.cols (); \ 1897 octave_idx_type a_nc = a.cols (); \
1898 \ 1898 \
1899 if (nr == 1 && nc == 1) \ 1899 if (nr == 1 && nc == 1) \
1900 { \ 1900 { \
1901 RET_TYPE retval = CONJ_OP (m.elem (0,0)) * a; \ 1901 RET_TYPE retval = CONJ_OP (m.elem (0,0)) * a; \
1902 return retval; \ 1902 return retval; \
1903 } \ 1903 } \
1904 else if (nr != a_nr) \ 1904 else if (nr != a_nr) \
1905 err_nonconformant ("operator *", nc, nr, a_nr, a_nc); \ 1905 err_nonconformant ("operator *", nc, nr, a_nr, a_nc); \
1906 else \ 1906 else \
1907 { \ 1907 { \
1908 RET_TYPE retval (nc, a_nc); \ 1908 RET_TYPE retval (nc, a_nc); \
1909 \ 1909 \
1910 for (octave_idx_type i = 0; i < a_nc ; i++) \ 1910 for (octave_idx_type i = 0; i < a_nc ; i++) \
1911 { \ 1911 { \
1912 for (octave_idx_type j = 0; j < nc; j++) \ 1912 for (octave_idx_type j = 0; j < nc; j++) \
1913 { \ 1913 { \
1914 octave_quit (); \ 1914 octave_quit (); \
1915 \ 1915 \
1916 EL_TYPE acc = ZERO; \ 1916 EL_TYPE acc = ZERO; \
1917 for (octave_idx_type k = m.cidx (j) ; k < m.cidx (j+1); k++) \ 1917 for (octave_idx_type k = m.cidx (j) ; k < m.cidx (j+1); k++) \
1918 acc += a.elem (m.ridx (k),i) * CONJ_OP (m.data (k)); \ 1918 acc += a.elem (m.ridx (k),i) * CONJ_OP (m.data (k)); \
1919 retval.xelem (j,i) = acc; \ 1919 retval.xelem (j,i) = acc; \
1920 } \ 1920 } \
1921 } \ 1921 } \
1922 return retval; \ 1922 return retval; \
1923 } 1923 }
1924 1924
1925 #define FULL_SPARSE_MUL(RET_TYPE, EL_TYPE, ZERO) \ 1925 #define FULL_SPARSE_MUL(RET_TYPE, EL_TYPE, ZERO) \
1926 octave_idx_type nr = m.rows (); \ 1926 octave_idx_type nr = m.rows (); \
1927 octave_idx_type nc = m.cols (); \ 1927 octave_idx_type nc = m.cols (); \
1928 \ 1928 \
1929 octave_idx_type a_nr = a.rows (); \ 1929 octave_idx_type a_nr = a.rows (); \
1930 octave_idx_type a_nc = a.cols (); \ 1930 octave_idx_type a_nc = a.cols (); \
1931 \ 1931 \
1932 if (a_nr == 1 && a_nc == 1) \ 1932 if (a_nr == 1 && a_nc == 1) \
1933 { \ 1933 { \
1934 RET_TYPE retval = m * a.elem (0,0); \ 1934 RET_TYPE retval = m * a.elem (0,0); \
1935 return retval; \ 1935 return retval; \
1936 } \ 1936 } \
1937 else if (nc != a_nr) \ 1937 else if (nc != a_nr) \
1938 err_nonconformant ("operator *", nr, nc, a_nr, a_nc); \ 1938 err_nonconformant ("operator *", nr, nc, a_nr, a_nc); \
1939 else \ 1939 else \
1940 { \ 1940 { \
1941 RET_TYPE retval (nr, a_nc, ZERO); \ 1941 RET_TYPE retval (nr, a_nc, ZERO); \
1942 \ 1942 \
1943 for (octave_idx_type i = 0; i < a_nc ; i++) \ 1943 for (octave_idx_type i = 0; i < a_nc ; i++) \
1944 { \ 1944 { \
1945 octave_quit (); \ 1945 octave_quit (); \
1946 for (octave_idx_type j = a.cidx (i); j < a.cidx (i+1); j++) \ 1946 for (octave_idx_type j = a.cidx (i); j < a.cidx (i+1); j++) \
1947 { \ 1947 { \
1948 octave_idx_type col = a.ridx (j); \ 1948 octave_idx_type col = a.ridx (j); \
1949 EL_TYPE tmpval = a.data (j); \ 1949 EL_TYPE tmpval = a.data (j); \
1950 \ 1950 \
1951 for (octave_idx_type k = 0 ; k < nr; k++) \ 1951 for (octave_idx_type k = 0 ; k < nr; k++) \
1952 retval.xelem (k,i) += tmpval * m.elem (k,col); \ 1952 retval.xelem (k,i) += tmpval * m.elem (k,col); \
1953 } \ 1953 } \
1954 } \ 1954 } \
1955 return retval; \ 1955 return retval; \
1956 } 1956 }
1957 1957
1958 #define FULL_SPARSE_MUL_TRANS(RET_TYPE, EL_TYPE, ZERO, CONJ_OP) \ 1958 #define FULL_SPARSE_MUL_TRANS(RET_TYPE, EL_TYPE, ZERO, CONJ_OP) \
1959 octave_idx_type nr = m.rows (); \ 1959 octave_idx_type nr = m.rows (); \
1960 octave_idx_type nc = m.cols (); \ 1960 octave_idx_type nc = m.cols (); \
1961 \ 1961 \
1962 octave_idx_type a_nr = a.rows (); \ 1962 octave_idx_type a_nr = a.rows (); \
1963 octave_idx_type a_nc = a.cols (); \ 1963 octave_idx_type a_nc = a.cols (); \
1964 \ 1964 \
1965 if (a_nr == 1 && a_nc == 1) \ 1965 if (a_nr == 1 && a_nc == 1) \
1966 { \ 1966 { \
1967 RET_TYPE retval = m * CONJ_OP (a.elem (0,0)); \ 1967 RET_TYPE retval = m * CONJ_OP (a.elem (0,0)); \
1968 return retval; \ 1968 return retval; \
1969 } \ 1969 } \
1970 else if (nc != a_nc) \ 1970 else if (nc != a_nc) \
1971 err_nonconformant ("operator *", nr, nc, a_nc, a_nr); \ 1971 err_nonconformant ("operator *", nr, nc, a_nc, a_nr); \
1972 else \ 1972 else \
1973 { \ 1973 { \
1974 RET_TYPE retval (nr, a_nr, ZERO); \ 1974 RET_TYPE retval (nr, a_nr, ZERO); \
1975 \ 1975 \
1976 for (octave_idx_type i = 0; i < a_nc ; i++) \ 1976 for (octave_idx_type i = 0; i < a_nc ; i++) \
1977 { \ 1977 { \
1978 octave_quit (); \ 1978 octave_quit (); \
1979 for (octave_idx_type j = a.cidx (i); j < a.cidx (i+1); j++) \ 1979 for (octave_idx_type j = a.cidx (i); j < a.cidx (i+1); j++) \
1980 { \ 1980 { \
1981 octave_idx_type col = a.ridx (j); \ 1981 octave_idx_type col = a.ridx (j); \
1982 EL_TYPE tmpval = CONJ_OP (a.data (j)); \ 1982 EL_TYPE tmpval = CONJ_OP (a.data (j)); \
1983 for (octave_idx_type k = 0 ; k < nr; k++) \ 1983 for (octave_idx_type k = 0 ; k < nr; k++) \
1984 retval.xelem (k,col) += tmpval * m.elem (k,i); \ 1984 retval.xelem (k,col) += tmpval * m.elem (k,i); \
1985 } \ 1985 } \
1986 } \ 1986 } \
1987 return retval; \ 1987 return retval; \
1988 } 1988 }
1989 1989
1990 #endif 1990 #endif