1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2009-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 #  include "config.h"
28 #endif
29 
30 #include "mx-cm-s.h"
31 #include "mx-s-cm.h"
32 
33 #include "mx-dm-cs.h"
34 #include "mx-cs-dm.h"
35 
36 #include "mx-m-cs.h"
37 #include "mx-cs-m.h"
38 
39 #include "ovl.h"
40 #include "ov.h"
41 #include "ov-typeinfo.h"
42 #include "ops.h"
43 
44 #include "ov-re-diag.h"
45 #include "ov-cx-diag.h"
46 #include "ov-re-sparse.h"
47 #include "ov-cx-sparse.h"
48 
49 #include "sparse-xdiv.h"
50 
51 // diagonal matrix by sparse matrix ops
52 
DEFBINOP(mul_dm_scm,diag_matrix,sparse_complex_matrix)53 DEFBINOP (mul_dm_scm, diag_matrix, sparse_complex_matrix)
54 {
55   const octave_diag_matrix& v1 = dynamic_cast<const octave_diag_matrix&> (a1);
56   const octave_sparse_complex_matrix& v2
57     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
58 
59   if (v2.rows () == 1 && v2.columns () == 1)
60     // If v2 is a scalar in disguise, return a diagonal matrix rather than
61     // a sparse matrix.
62     {
63       std::complex<double> d = v2.complex_value ();
64 
65       return octave_value (v1.diag_matrix_value () * d);
66     }
67   else
68     {
69       MatrixType typ = v2.matrix_type ();
70       SparseComplexMatrix ret = v1.diag_matrix_value () *
71                                 v2.sparse_complex_matrix_value ();
72       octave_value out = octave_value (ret);
73       typ.mark_as_unsymmetric ();
74       out.matrix_type (typ);
75       return out;
76     }
77 }
78 
DEFBINOP(mul_cdm_sm,complex_diag_matrix,sparse_matrix)79 DEFBINOP (mul_cdm_sm, complex_diag_matrix, sparse_matrix)
80 {
81   const octave_complex_diag_matrix& v1
82     = dynamic_cast<const octave_complex_diag_matrix&> (a1);
83   const octave_sparse_matrix& v2
84     = dynamic_cast<const octave_sparse_matrix&> (a2);
85 
86   if (v2.rows () == 1 && v2.columns () == 1)
87     // If v2 is a scalar in disguise, return a diagonal matrix rather than
88     // a sparse matrix.
89     {
90       std::complex<double> d = v2.scalar_value ();
91 
92       return octave_value (v1.complex_diag_matrix_value () * d);
93     }
94   else
95     {
96       MatrixType typ = v2.matrix_type ();
97       SparseComplexMatrix ret = v1.complex_diag_matrix_value () *
98                                 v2.sparse_matrix_value ();
99       octave_value out = octave_value (ret);
100       typ.mark_as_unsymmetric ();
101       out.matrix_type (typ);
102       return out;
103     }
104 }
105 
DEFBINOP(mul_cdm_scm,complex_diag_matrix,sparse_complex_matrix)106 DEFBINOP (mul_cdm_scm, complex_diag_matrix, sparse_complex_matrix)
107 {
108   const octave_complex_diag_matrix& v1
109     = dynamic_cast<const octave_complex_diag_matrix&> (a1);
110   const octave_sparse_complex_matrix& v2
111     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
112 
113   if (v2.rows () == 1 && v2.columns () == 1)
114     // If v2 is a scalar in disguise, return a diagonal matrix rather than
115     // a sparse matrix.
116     {
117       std::complex<double> d = v2.complex_value ();
118 
119       return octave_value (v1.complex_diag_matrix_value () * d);
120     }
121   else
122     {
123       MatrixType typ = v2.matrix_type ();
124       SparseComplexMatrix ret = v1.complex_diag_matrix_value () *
125                                 v2.sparse_complex_matrix_value ();
126       octave_value out = octave_value (ret);
127       typ.mark_as_unsymmetric ();
128       out.matrix_type (typ);
129       return out;
130     }
131 }
132 
DEFBINOP(ldiv_dm_scm,diag_matrix,sparse_complex_matrix)133 DEFBINOP (ldiv_dm_scm, diag_matrix, sparse_complex_matrix)
134 {
135   const octave_diag_matrix& v1 = dynamic_cast<const octave_diag_matrix&> (a1);
136   const octave_sparse_complex_matrix& v2
137     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
138 
139   MatrixType typ = v2.matrix_type ();
140   return xleftdiv (v1.diag_matrix_value (), v2.sparse_complex_matrix_value (),
141                    typ);
142 }
143 
DEFBINOP(ldiv_cdm_sm,complex_diag_matrix,sparse_matrix)144 DEFBINOP (ldiv_cdm_sm, complex_diag_matrix, sparse_matrix)
145 {
146   const octave_complex_diag_matrix& v1
147     = dynamic_cast<const octave_complex_diag_matrix&> (a1);
148   const octave_sparse_matrix& v2
149     = dynamic_cast<const octave_sparse_matrix&> (a2);
150 
151   MatrixType typ = v2.matrix_type ();
152   return xleftdiv (v1.complex_diag_matrix_value (), v2.sparse_matrix_value (),
153                    typ);
154 }
155 
DEFBINOP(ldiv_cdm_scm,complex_diag_matrix,sparse_complex_matrix)156 DEFBINOP (ldiv_cdm_scm, complex_diag_matrix, sparse_complex_matrix)
157 {
158   const octave_complex_diag_matrix& v1
159     = dynamic_cast<const octave_complex_diag_matrix&> (a1);
160   const octave_sparse_complex_matrix& v2
161     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
162 
163   MatrixType typ = v2.matrix_type ();
164   return xleftdiv (v1.complex_diag_matrix_value (),
165                    v2.sparse_complex_matrix_value (),
166                    typ);
167 }
168 
DEFBINOP(add_dm_scm,diag_matrix,sparse_complex_matrix)169 DEFBINOP (add_dm_scm, diag_matrix, sparse_complex_matrix)
170 {
171   const octave_diag_matrix& v1 = dynamic_cast<const octave_diag_matrix&> (a1);
172   const octave_sparse_complex_matrix& v2
173     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
174 
175   if (v2.rows () == 1 && v2.columns () == 1)
176     // If v2 is a scalar in disguise, return a diagonal matrix rather than
177     // a sparse matrix.
178     {
179       std::complex<double> d = v2.complex_value ();
180 
181       return octave_value (v1.matrix_value () + d);
182     }
183   else
184     return v1.diag_matrix_value () + v2.sparse_complex_matrix_value ();
185 }
186 
DEFBINOP(add_cdm_sm,complex_diag_matrix,sparse_matrix)187 DEFBINOP (add_cdm_sm, complex_diag_matrix, sparse_matrix)
188 {
189   const octave_complex_diag_matrix& v1
190     = dynamic_cast<const octave_complex_diag_matrix&> (a1);
191   const octave_sparse_matrix& v2
192     = dynamic_cast<const octave_sparse_matrix&> (a2);
193 
194   if (v2.rows () == 1 && v2.columns () == 1)
195     // If v2 is a scalar in disguise, return a diagonal matrix rather than
196     // a sparse matrix.
197     {
198       double d = v2.scalar_value ();
199 
200       return octave_value (v1.complex_matrix_value () + d);
201     }
202   else
203     return v1.complex_diag_matrix_value () + v2.sparse_matrix_value ();
204 }
205 
DEFBINOP(add_cdm_scm,complex_diag_matrix,sparse_complex_matrix)206 DEFBINOP (add_cdm_scm, complex_diag_matrix, sparse_complex_matrix)
207 {
208   const octave_complex_diag_matrix& v1
209     = dynamic_cast<const octave_complex_diag_matrix&> (a1);
210   const octave_sparse_complex_matrix& v2
211     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
212 
213   if (v2.rows () == 1 && v2.columns () == 1)
214     // If v2 is a scalar in disguise, return a diagonal matrix rather than
215     // a sparse matrix.
216     {
217       std::complex<double> d = v2.complex_value ();
218 
219       return octave_value (v1.complex_matrix_value () + d);
220     }
221   else
222     return v1.complex_diag_matrix_value () + v2.sparse_complex_matrix_value ();
223 }
224 
DEFBINOP(sub_dm_scm,diag_matrix,sparse_complex_matrix)225 DEFBINOP (sub_dm_scm, diag_matrix, sparse_complex_matrix)
226 {
227   const octave_diag_matrix& v1 = dynamic_cast<const octave_diag_matrix&> (a1);
228   const octave_sparse_complex_matrix& v2
229     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
230 
231   if (v2.rows () == 1 && v2.columns () == 1)
232     // If v2 is a scalar in disguise, return a diagonal matrix rather than
233     // a sparse matrix.
234     {
235       std::complex<double> d = v2.complex_value ();
236 
237       return octave_value (v1.matrix_value () + (-d));
238     }
239   else
240     return v1.diag_matrix_value () - v2.sparse_complex_matrix_value ();
241 }
242 
DEFBINOP(sub_cdm_sm,complex_diag_matrix,sparse_matrix)243 DEFBINOP (sub_cdm_sm, complex_diag_matrix, sparse_matrix)
244 {
245   const octave_complex_diag_matrix& v1
246     = dynamic_cast<const octave_complex_diag_matrix&> (a1);
247   const octave_sparse_matrix& v2
248     = dynamic_cast<const octave_sparse_matrix&> (a2);
249 
250   if (v2.rows () == 1 && v2.columns () == 1)
251     // If v2 is a scalar in disguise, return a diagonal matrix rather than
252     // a sparse matrix.
253     {
254       double d = v2.scalar_value ();
255 
256       return octave_value (v1.complex_matrix_value () + (-d));
257     }
258   else
259     return v1.complex_diag_matrix_value () - v2.sparse_matrix_value ();
260 }
261 
DEFBINOP(sub_cdm_scm,complex_diag_matrix,sparse_complex_matrix)262 DEFBINOP (sub_cdm_scm, complex_diag_matrix, sparse_complex_matrix)
263 {
264   const octave_complex_diag_matrix& v1
265     = dynamic_cast<const octave_complex_diag_matrix&> (a1);
266   const octave_sparse_complex_matrix& v2
267     = dynamic_cast<const octave_sparse_complex_matrix&> (a2);
268 
269   if (v2.rows () == 1 && v2.columns () == 1)
270     // If v2 is a scalar in disguise, return a diagonal matrix rather than
271     // a sparse matrix.
272     {
273       std::complex<double> d = v2.complex_value ();
274 
275       return octave_value (v1.complex_matrix_value () + (-d));
276     }
277   else
278     return v1.complex_diag_matrix_value () - v2.sparse_complex_matrix_value ();
279 }
280 
281 // sparse matrix by diagonal matrix ops
282 
DEFBINOP(mul_scm_dm,sparse_complex_matrix,diag_matrix)283 DEFBINOP (mul_scm_dm, sparse_complex_matrix, diag_matrix)
284 {
285   const octave_sparse_complex_matrix& v1
286     = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
287   const octave_diag_matrix& v2 = dynamic_cast<const octave_diag_matrix&> (a2);
288 
289   if (v1.rows () == 1 && v1.columns () == 1)
290     // If v1 is a scalar in disguise, return a diagonal matrix rather than
291     // a sparse matrix.
292     {
293       std::complex<double> d = v1.complex_value ();
294 
295       return octave_value (d * v2.diag_matrix_value ());
296     }
297   else
298     {
299       MatrixType typ = v1.matrix_type ();
300       SparseComplexMatrix ret = v1.sparse_complex_matrix_value () *
301                                 v2.diag_matrix_value ();
302       octave_value out = octave_value (ret);
303       typ.mark_as_unsymmetric ();
304       out.matrix_type (typ);
305       return out;
306     }
307 }
308 
DEFBINOP(mul_sm_cdm,sparse_matrix,complex_diag_matrix)309 DEFBINOP (mul_sm_cdm, sparse_matrix, complex_diag_matrix)
310 {
311   const octave_sparse_matrix& v1
312     = dynamic_cast<const octave_sparse_matrix&> (a1);
313   const octave_complex_diag_matrix& v2
314     = dynamic_cast<const octave_complex_diag_matrix&> (a2);
315 
316   if (v1.rows () == 1 && v1.columns () == 1)
317     // If v1 is a scalar in disguise, return a diagonal matrix rather than
318     // a sparse matrix.
319     {
320       std::complex<double> d = v1.complex_value ();
321 
322       return octave_value (d * v2.complex_diag_matrix_value ());
323     }
324   else
325     {
326       MatrixType typ = v1.matrix_type ();
327       SparseComplexMatrix ret = v1.sparse_matrix_value () *
328                                 v2.complex_diag_matrix_value ();
329       octave_value out = octave_value (ret);
330       typ.mark_as_unsymmetric ();
331       out.matrix_type (typ);
332       return out;
333     }
334 }
335 
DEFBINOP(mul_scm_cdm,sparse_complex_matrix,complex_diag_matrix)336 DEFBINOP (mul_scm_cdm, sparse_complex_matrix, complex_diag_matrix)
337 {
338   const octave_sparse_complex_matrix& v1
339     = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
340   const octave_complex_diag_matrix& v2
341     = dynamic_cast<const octave_complex_diag_matrix&> (a2);
342 
343   if (v1.rows () == 1 && v1.columns () == 1)
344     // If v1 is a scalar in disguise, return a diagonal matrix rather than
345     // a sparse matrix.
346     {
347       std::complex<double> d = v1.complex_value ();
348 
349       return octave_value (d * v2.complex_diag_matrix_value ());
350     }
351   else if (v2.rows () == 1 && v2.columns () == 1)
352     // If v2 is a scalar in disguise, don't bother with further dispatching.
353     {
354       std::complex<double> d = v2.complex_value ();
355 
356       return octave_value (v1.sparse_complex_matrix_value () * d);
357     }
358   else
359     {
360       MatrixType typ = v1.matrix_type ();
361       SparseComplexMatrix ret = v1.sparse_complex_matrix_value () *
362                                 v2.complex_diag_matrix_value ();
363       octave_value out = octave_value (ret);
364       typ.mark_as_unsymmetric ();
365       out.matrix_type (typ);
366       return out;
367     }
368 }
369 
DEFBINOP(div_scm_dm,sparse_complex_matrix,diag_matrix)370 DEFBINOP (div_scm_dm, sparse_complex_matrix, diag_matrix)
371 {
372   const octave_sparse_complex_matrix& v1
373     = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
374   const octave_diag_matrix& v2 = dynamic_cast<const octave_diag_matrix&> (a2);
375 
376   if (v2.rows () == 1 && v2.columns () == 1)
377     return octave_value (v1.sparse_complex_matrix_value () / v2.scalar_value ());
378   else
379     {
380       MatrixType typ = v2.matrix_type ();
381       return xdiv (v1.sparse_complex_matrix_value (),
382                    v2.diag_matrix_value (), typ);
383     }
384 }
385 
DEFBINOP(div_sm_cdm,sparse_matrix,complex_diag_matrix)386 DEFBINOP (div_sm_cdm, sparse_matrix, complex_diag_matrix)
387 {
388   const octave_sparse_matrix& v1
389     = dynamic_cast<const octave_sparse_matrix&> (a1);
390   const octave_complex_diag_matrix& v2
391     = dynamic_cast<const octave_complex_diag_matrix&> (a2);
392 
393   if (v2.rows () == 1 && v2.columns () == 1)
394     return octave_value (v1.sparse_matrix_value () / v2.complex_value ());
395   else
396     {
397       MatrixType typ = v2.matrix_type ();
398       return xdiv (v1.sparse_matrix_value (),
399                    v2.complex_diag_matrix_value (), typ);
400     }
401 }
402 
DEFBINOP(div_scm_cdm,sparse_complex_matrix,complex_diag_matrix)403 DEFBINOP (div_scm_cdm, sparse_complex_matrix, complex_diag_matrix)
404 {
405   const octave_sparse_complex_matrix& v1
406     = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
407   const octave_complex_diag_matrix& v2
408     = dynamic_cast<const octave_complex_diag_matrix&> (a2);
409 
410   if (v2.rows () == 1 && v2.columns () == 1)
411     return octave_value (v1.sparse_complex_matrix_value () / v2.complex_value ());
412   else
413     {
414       MatrixType typ = v2.matrix_type ();
415       return xdiv (v1.sparse_complex_matrix_value (),
416                    v2.complex_diag_matrix_value (), typ);
417     }
418 }
419 
DEFBINOP(add_sm_cdm,sparse_matrix,complex_diag_matrix)420 DEFBINOP (add_sm_cdm, sparse_matrix, complex_diag_matrix)
421 {
422   const octave_sparse_matrix& v1
423     = dynamic_cast<const octave_sparse_matrix&> (a1);
424   const octave_complex_diag_matrix& v2
425     = dynamic_cast<const octave_complex_diag_matrix&> (a2);
426 
427   if (v2.rows () == 1 && v2.columns () == 1)
428     // If v2 is a scalar in disguise, return a diagonal matrix rather than
429     // a sparse matrix.
430     {
431       std::complex<double> d = v2.complex_value ();
432 
433       return octave_value (v1.sparse_matrix_value () + d);
434     }
435   else
436     return v1.sparse_matrix_value () + v2.complex_diag_matrix_value ();
437 }
438 
DEFBINOP(add_scm_dm,sparse_complex_matrix,diag_matrix)439 DEFBINOP (add_scm_dm, sparse_complex_matrix, diag_matrix)
440 {
441   const octave_sparse_complex_matrix& v1
442     = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
443   const octave_diag_matrix& v2 = dynamic_cast<const octave_diag_matrix&> (a2);
444 
445   if (v2.rows () == 1 && v2.columns () == 1)
446     // If v2 is a scalar in disguise, return a diagonal matrix rather than
447     // a sparse matrix.
448     {
449       double d = v2.scalar_value ();
450 
451       return octave_value (v1.sparse_complex_matrix_value () + d);
452     }
453   else
454     return v1.sparse_complex_matrix_value () + v2.diag_matrix_value ();
455 }
456 
DEFBINOP(add_scm_cdm,sparse_complex_matrix,complex_diag_matrix)457 DEFBINOP (add_scm_cdm, sparse_complex_matrix, complex_diag_matrix)
458 {
459   const octave_sparse_complex_matrix& v1
460     = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
461   const octave_complex_diag_matrix& v2
462     = dynamic_cast<const octave_complex_diag_matrix&> (a2);
463 
464   if (v2.rows () == 1 && v2.columns () == 1)
465     // If v2 is a scalar in disguise, return a diagonal matrix rather than
466     // a sparse matrix.
467     {
468       std::complex<double> d = v2.complex_value ();
469 
470       return octave_value (v1.sparse_complex_matrix_value () + d);
471     }
472   else
473     return v1.sparse_complex_matrix_value () + v2.complex_diag_matrix_value ();
474 }
475 
DEFBINOP(sub_sm_cdm,sparse_matrix,complex_diag_matrix)476 DEFBINOP (sub_sm_cdm, sparse_matrix, complex_diag_matrix)
477 {
478   const octave_sparse_matrix& v1
479     = dynamic_cast<const octave_sparse_matrix&> (a1);
480   const octave_complex_diag_matrix& v2
481     = dynamic_cast<const octave_complex_diag_matrix&> (a2);
482 
483   if (v2.rows () == 1 && v2.columns () == 1)
484     // If v2 is a scalar in disguise, return a diagonal matrix rather than
485     // a sparse matrix.
486     {
487       std::complex<double> d = v2.complex_value ();
488 
489       return octave_value (v1.sparse_matrix_value () + (-d));
490     }
491   else
492     return v1.sparse_matrix_value () - v2.complex_diag_matrix_value ();
493 }
494 
DEFBINOP(sub_scm_dm,sparse_complex_matrix,diag_matrix)495 DEFBINOP (sub_scm_dm, sparse_complex_matrix, diag_matrix)
496 {
497   const octave_sparse_complex_matrix& v1
498     = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
499   const octave_diag_matrix& v2 = dynamic_cast<const octave_diag_matrix&> (a2);
500 
501   if (v2.rows () == 1 && v2.columns () == 1)
502     // If v2 is a scalar in disguise, return a diagonal matrix rather than
503     // a sparse matrix.
504     {
505       double d = v2.scalar_value ();
506 
507       return octave_value (v1.sparse_complex_matrix_value () + (-d));
508     }
509   else
510     return v1.sparse_complex_matrix_value () - v2.diag_matrix_value ();
511 }
512 
DEFBINOP(sub_scm_cdm,sparse_complex_matrix,complex_diag_matrix)513 DEFBINOP (sub_scm_cdm, sparse_complex_matrix, complex_diag_matrix)
514 {
515   const octave_sparse_complex_matrix& v1
516     = dynamic_cast<const octave_sparse_complex_matrix&> (a1);
517   const octave_complex_diag_matrix& v2
518     = dynamic_cast<const octave_complex_diag_matrix&> (a2);
519 
520   if (v2.rows () == 1 && v2.columns () == 1)
521     // If v2 is a scalar in disguise, return a diagonal matrix rather than
522     // a sparse matrix.
523     {
524       std::complex<double> d = v2.complex_value ();
525 
526       return octave_value (v1.sparse_complex_matrix_value () + (-d));
527     }
528   else
529     return v1.sparse_complex_matrix_value () - v2.complex_diag_matrix_value ();
530 }
531 
532 void
install_dm_scm_ops(octave::type_info & ti)533 install_dm_scm_ops (octave::type_info& ti)
534 {
535   INSTALL_BINOP_TI (ti, op_mul, octave_diag_matrix, octave_sparse_complex_matrix,
536                     mul_dm_scm);
537   INSTALL_BINOP_TI (ti, op_mul, octave_complex_diag_matrix, octave_sparse_matrix,
538                     mul_cdm_sm);
539   INSTALL_BINOP_TI (ti, op_mul, octave_complex_diag_matrix,
540                     octave_sparse_complex_matrix, mul_cdm_scm);
541   INSTALL_BINOP_TI (ti, op_ldiv, octave_diag_matrix, octave_sparse_complex_matrix,
542                     ldiv_dm_scm);
543   INSTALL_BINOP_TI (ti, op_ldiv, octave_complex_diag_matrix, octave_sparse_matrix,
544                     ldiv_cdm_sm);
545   INSTALL_BINOP_TI (ti, op_ldiv, octave_complex_diag_matrix,
546                     octave_sparse_complex_matrix, ldiv_cdm_scm);
547 
548   INSTALL_BINOP_TI (ti, op_add, octave_diag_matrix, octave_sparse_complex_matrix,
549                     add_dm_scm);
550   INSTALL_BINOP_TI (ti, op_add, octave_complex_diag_matrix, octave_sparse_matrix,
551                     add_cdm_sm);
552   INSTALL_BINOP_TI (ti, op_add, octave_complex_diag_matrix,
553                     octave_sparse_complex_matrix, add_cdm_scm);
554   INSTALL_BINOP_TI (ti, op_sub, octave_diag_matrix, octave_sparse_complex_matrix,
555                     sub_dm_scm);
556   INSTALL_BINOP_TI (ti, op_sub, octave_complex_diag_matrix, octave_sparse_matrix,
557                     sub_cdm_sm);
558   INSTALL_BINOP_TI (ti, op_sub, octave_complex_diag_matrix,
559                     octave_sparse_complex_matrix, sub_cdm_scm);
560 
561   INSTALL_BINOP_TI (ti, op_mul, octave_sparse_complex_matrix, octave_diag_matrix,
562                     mul_scm_dm);
563   INSTALL_BINOP_TI (ti, op_mul, octave_sparse_matrix, octave_complex_diag_matrix,
564                     mul_sm_cdm);
565   INSTALL_BINOP_TI (ti, op_mul, octave_sparse_complex_matrix,
566                     octave_complex_diag_matrix, mul_scm_cdm);
567 
568   INSTALL_BINOP_TI (ti, op_div, octave_sparse_complex_matrix, octave_diag_matrix,
569                     div_scm_dm);
570   INSTALL_BINOP_TI (ti, op_div, octave_sparse_matrix, octave_complex_diag_matrix,
571                     div_sm_cdm);
572   INSTALL_BINOP_TI (ti, op_div, octave_sparse_complex_matrix,
573                     octave_complex_diag_matrix, div_scm_cdm);
574 
575   INSTALL_BINOP_TI (ti, op_add, octave_sparse_complex_matrix, octave_diag_matrix,
576                     add_scm_dm);
577   INSTALL_BINOP_TI (ti, op_add, octave_sparse_matrix, octave_complex_diag_matrix,
578                     add_sm_cdm);
579   INSTALL_BINOP_TI (ti, op_add, octave_sparse_complex_matrix,
580                     octave_complex_diag_matrix, add_scm_cdm);
581   INSTALL_BINOP_TI (ti, op_sub, octave_sparse_complex_matrix, octave_diag_matrix,
582                     sub_scm_dm);
583   INSTALL_BINOP_TI (ti, op_sub, octave_sparse_matrix, octave_complex_diag_matrix,
584                     sub_sm_cdm);
585   INSTALL_BINOP_TI (ti, op_sub, octave_sparse_complex_matrix,
586                     octave_complex_diag_matrix, sub_scm_cdm);
587 }
588