GNU Octave 11.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
sparse-xdiv.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1998-2026 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 "Array-util.h"
31#include "lo-array-errwarn.h"
32#include "oct-cmplx.h"
33#include "quit.h"
34#include "error.h"
35#include "lo-ieee.h"
36
37#include "dSparse.h"
38#include "dDiagMatrix.h"
39#include "CSparse.h"
40#include "CDiagMatrix.h"
41#include "oct-spparms.h"
42#include "sparse-xdiv.h"
43
45
46static void
47solve_singularity_warning (double rcond)
48{
49 octave::warn_singular_matrix (rcond);
50}
51
52template <typename T1, typename T2>
53bool
54mx_leftdiv_conform (const T1& a, const T2& b)
55{
56 octave_idx_type a_nr = a.rows ();
57 octave_idx_type b_nr = b.rows ();
58
59 if (a_nr != b_nr)
60 {
61 octave_idx_type a_nc = a.cols ();
62 octave_idx_type b_nc = b.cols ();
63
64 octave::err_nonconformant (R"(operator \)", a_nr, a_nc, b_nr, b_nc);
65 }
66
67 return true;
68}
69
70#define INSTANTIATE_MX_LEFTDIV_CONFORM(T1, T2) \
71 template bool mx_leftdiv_conform (const T1&, const T2&)
72
85
86template <typename T1, typename T2>
87bool
88mx_div_conform (const T1& a, const T2& b)
89{
90 octave_idx_type a_nc = a.cols ();
91 octave_idx_type b_nc = b.cols ();
92
93 if (a_nc != b_nc)
94 {
95 octave_idx_type a_nr = a.rows ();
96 octave_idx_type b_nr = b.rows ();
97
98 octave::err_nonconformant ("operator /", a_nr, a_nc, b_nr, b_nc);
99 }
100
101 return true;
102}
103
104#define INSTANTIATE_MX_DIV_CONFORM(T1, T2) \
105 template bool mx_div_conform (const T1&, const T2&)
106
119
120// Right division functions. X / Y = X * inv (Y) = (inv (Y') * X')'
121//
122// Y / X: m cm sm scm
123// +-- +---+----+----+----+
124// sparse matrix | 1 | 3 | 5 | 7 |
125// +---+----+----+----+
126// sparse complex_matrix | 2 | 4 | 6 | 8 |
127// +---+----+----+----+
128// diagonal matrix | 9 | 11 |
129// +----+----+
130// complex diag. matrix | 10 | 12 |
131// +----+----+
132
133// -*- 1 -*-
134Matrix
135xdiv (const Matrix& a, const SparseMatrix& b, MatrixType& typ)
136{
137 if (! mx_div_conform (a, b))
138 return Matrix ();
139
140 Matrix atmp = a.transpose ();
141 SparseMatrix btmp = b.transpose ();
142 MatrixType btyp = typ.transpose ();
143
144 octave_idx_type info;
145 double rcond = 0.0;
146 Matrix result = btmp.solve (btyp, atmp, info, rcond,
147 solve_singularity_warning);
148
149 typ = btyp.transpose ();
150 return result.transpose ();
151}
152
153// -*- 2 -*-
155xdiv (const Matrix& a, const SparseComplexMatrix& b, MatrixType& typ)
156{
157 if (! mx_div_conform (a, b))
158 return ComplexMatrix ();
159
160 Matrix atmp = a.transpose ();
161 SparseComplexMatrix btmp = b.hermitian ();
162 MatrixType btyp = typ.transpose ();
163
164 octave_idx_type info;
165 double rcond = 0.0;
166 ComplexMatrix result
167 = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning);
168
169 typ = btyp.transpose ();
170 return result.hermitian ();
171}
172
173// -*- 3 -*-
175xdiv (const ComplexMatrix& a, const SparseMatrix& b, MatrixType& typ)
176{
177 if (! mx_div_conform (a, b))
178 return ComplexMatrix ();
179
180 ComplexMatrix atmp = a.hermitian ();
181 SparseMatrix btmp = b.transpose ();
182 MatrixType btyp = typ.transpose ();
183
184 octave_idx_type info;
185 double rcond = 0.0;
186 ComplexMatrix result
187 = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning);
188
189 typ = btyp.transpose ();
190 return result.hermitian ();
191}
192
193// -*- 4 -*-
196{
197 if (! mx_div_conform (a, b))
198 return ComplexMatrix ();
199
200 ComplexMatrix atmp = a.hermitian ();
201 SparseComplexMatrix btmp = b.hermitian ();
202 MatrixType btyp = typ.transpose ();
203
204 octave_idx_type info;
205 double rcond = 0.0;
206 ComplexMatrix result
207 = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning);
208
209 typ = btyp.transpose ();
210 return result.hermitian ();
211}
212
213// -*- 5 -*-
215xdiv (const SparseMatrix& a, const SparseMatrix& b, MatrixType& typ)
216{
217 if (! mx_div_conform (a, b))
218 return SparseMatrix ();
219
220 SparseMatrix atmp = a.transpose ();
221 SparseMatrix btmp = b.transpose ();
222 MatrixType btyp = typ.transpose ();
223
224 octave_idx_type info;
225 double rcond = 0.0;
226 SparseMatrix result = btmp.solve (btyp, atmp, info, rcond,
227 solve_singularity_warning);
228
229 typ = btyp.transpose ();
230 return result.transpose ();
231}
232
233// -*- 6 -*-
236{
237 if (! mx_div_conform (a, b))
238 return SparseComplexMatrix ();
239
240 SparseMatrix atmp = a.transpose ();
241 SparseComplexMatrix btmp = b.hermitian ();
242 MatrixType btyp = typ.transpose ();
243
244 octave_idx_type info;
245 double rcond = 0.0;
247 = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning);
248
249 typ = btyp.transpose ();
250 return result.hermitian ();
251}
252
253// -*- 7 -*-
256{
257 if (! mx_div_conform (a, b))
258 return SparseComplexMatrix ();
259
260 SparseComplexMatrix atmp = a.hermitian ();
261 SparseMatrix btmp = b.transpose ();
262 MatrixType btyp = typ.transpose ();
263
264 octave_idx_type info;
265 double rcond = 0.0;
267 = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning);
268
269 typ = btyp.transpose ();
270 return result.hermitian ();
271}
272
273// -*- 8 -*-
276 MatrixType& typ)
277{
278 if (! mx_div_conform (a, b))
279 return SparseComplexMatrix ();
280
281 SparseComplexMatrix atmp = a.hermitian ();
282 SparseComplexMatrix btmp = b.hermitian ();
283 MatrixType btyp = typ.transpose ();
284
285 octave_idx_type info;
286 double rcond = 0.0;
288 = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning);
289
290 typ = btyp.transpose ();
291 return result.hermitian ();
292}
293
294template <typename RT, typename SM, typename DM>
295RT
296do_rightdiv_sm_dm (const SM& a, const DM& d)
297{
298 const octave_idx_type d_nr = d.rows ();
299
300 const octave_idx_type a_nr = a.rows ();
301 const octave_idx_type a_nc = a.cols ();
302
303 using std::min;
304 const octave_idx_type nc = min (d_nr, a_nc);
305
306 if (! mx_div_conform (a, d))
307 return RT ();
308
309 const octave_idx_type nz = a.nnz ();
310 RT r (a_nr, nc, nz);
311
312 typedef typename DM::element_type DM_elt_type;
313 const DM_elt_type zero = DM_elt_type ();
314
315 octave_idx_type k_result = 0;
316 for (octave_idx_type j = 0; j < nc; ++j)
317 {
318 octave_quit ();
319 const DM_elt_type s = d.dgelem (j);
320 const octave_idx_type colend = a.cidx (j+1);
321 r.xcidx (j) = k_result;
322 if (s != zero)
323 for (octave_idx_type k = a.cidx (j); k < colend; ++k)
324 {
325 r.xdata (k_result) = a.data (k) / s;
326 r.xridx (k_result) = a.ridx (k);
327 ++k_result;
328 }
329 }
330 r.xcidx (nc) = k_result;
331
332 r.maybe_compress (true);
333 return r;
334}
335
336// -*- 9 -*-
339{
340 return do_rightdiv_sm_dm<SparseMatrix> (a, b);
341}
342
343// -*- 10 -*-
346{
347 return do_rightdiv_sm_dm<SparseComplexMatrix> (a, b);
348}
349
350// -*- 11 -*-
353{
354 return do_rightdiv_sm_dm<SparseComplexMatrix> (a, b);
355}
356
357// -*- 12 -*-
360{
361 return do_rightdiv_sm_dm<SparseComplexMatrix> (a, b);
362}
363
364// Funny element by element division operations.
365//
366// op2 \ op1: s cs
367// +-- +---+----+
368// matrix | 1 | 3 |
369// +---+----+
370// complex_matrix | 2 | 4 |
371// +---+----+
372
373Matrix
374elem_xdiv (double a, const SparseMatrix& b)
375{
376 octave_idx_type nr = b.rows ();
377 octave_idx_type nc = b.cols ();
378
379 Matrix result;
380 if (octave::math::isnan (a))
381 {
382 result = Matrix (nr, nc, octave::numeric_limits<double>::NaN ());
383 return result;
384 }
385 if (a == 0.)
386 result = Matrix (nr, nc, octave::numeric_limits<double>::NaN ());
387 else if (a > 0.)
388 result = Matrix (nr, nc, octave::numeric_limits<double>::Inf ());
389 else
390 result = Matrix (nr, nc, -octave::numeric_limits<double>::Inf ());
391
392 for (octave_idx_type j = 0; j < nc; j++)
393 for (octave_idx_type i = b.cidx (j); i < b.cidx (j+1); i++)
394 {
395 octave_quit ();
396 result.elem (b.ridx (i), j) = a / b.data (i);
397 }
398
399 return result;
400}
401
403elem_xdiv (double a, const SparseComplexMatrix& b)
404{
405 octave_idx_type nr = b.rows ();
406 octave_idx_type nc = b.cols ();
407
408 ComplexMatrix result;
409 if (octave::math::isnan (a))
410 {
411 result = ComplexMatrix (nr, nc,
412 Complex (octave::numeric_limits<double>::NaN (),
413 octave::numeric_limits<double>::NaN ()));
414 return result;
415 }
416 if (a == 0.)
417 result = ComplexMatrix (nr, nc,
418 Complex (octave::numeric_limits<double>::NaN (),
419 octave::numeric_limits<double>::NaN ()));
420 else if (a > 0.)
421 result = ComplexMatrix (nr, nc,
422 Complex (octave::numeric_limits<double>::Inf (),
423 octave::numeric_limits<double>::Inf ()));
424 else
425 result = ComplexMatrix (nr, nc,
426 Complex (-octave::numeric_limits<double>::Inf (),
427 -octave::numeric_limits<double>::Inf ()));
428
429 for (octave_idx_type j = 0; j < nc; j++)
430 for (octave_idx_type i = b.cidx (j); i < b.cidx (j+1); i++)
431 {
432 octave_quit ();
433 result.elem (b.ridx (i), j) = a / b.data (i);
434 }
435
436 return result;
437}
438
440elem_xdiv (const Complex& a, const SparseMatrix& b)
441{
442 octave_idx_type nr = b.rows ();
443 octave_idx_type nc = b.cols ();
444
445 ComplexMatrix result (nr, nc, (a / 0.0));
446
447 for (octave_idx_type j = 0; j < nc; j++)
448 for (octave_idx_type i = b.cidx (j); i < b.cidx (j+1); i++)
449 {
450 octave_quit ();
451 result.elem (b.ridx (i), j) = a / b.data (i);
452 }
453
454 return result;
455}
456
459{
460 octave_idx_type nr = b.rows ();
461 octave_idx_type nc = b.cols ();
462
463 ComplexMatrix result (nr, nc, (a / 0.0));
464
465 for (octave_idx_type j = 0; j < nc; j++)
466 for (octave_idx_type i = b.cidx (j); i < b.cidx (j+1); i++)
467 {
468 octave_quit ();
469 result.elem (b.ridx (i), j) = a / b.data (i);
470 }
471
472 return result;
473}
474
475// Left division functions. X \ Y = inv (X) * Y
476//
477// Y \ X : sm scm dm dcm
478// +-- +---+----+
479// matrix | 1 | 5 |
480// +---+----+
481// complex_matrix | 2 | 6 |
482// +---+----+----+----+
483// sparse matrix | 3 | 7 | 9 | 11 |
484// +---+----+----+----+
485// sparse complex_matrix | 4 | 8 | 10 | 12 |
486// +---+----+----+----+
487
488// -*- 1 -*-
489Matrix
490xleftdiv (const SparseMatrix& a, const Matrix& b, MatrixType& typ)
491{
492 if (! mx_leftdiv_conform (a, b))
493 return Matrix ();
494
495 octave_idx_type info;
496 double rcond = 0.0;
497 return a.solve (typ, b, info, rcond, solve_singularity_warning);
498}
499
500// -*- 2 -*-
503{
504 if (! mx_leftdiv_conform (a, b))
505 return ComplexMatrix ();
506
507 octave_idx_type info;
508 double rcond = 0.0;
509 return a.solve (typ, b, info, rcond, solve_singularity_warning);
510}
511
512// -*- 3 -*-
515{
516 if (! mx_leftdiv_conform (a, b))
517 return SparseMatrix ();
518
519 octave_idx_type info;
520 double rcond = 0.0;
521 return a.solve (typ, b, info, rcond, solve_singularity_warning);
522}
523
524// -*- 4 -*-
527{
528 if (! mx_leftdiv_conform (a, b))
529 return SparseComplexMatrix ();
530
531 octave_idx_type info;
532 double rcond = 0.0;
533 return a.solve (typ, b, info, rcond, solve_singularity_warning);
534}
535
536// -*- 5 -*-
539{
540 if (! mx_leftdiv_conform (a, b))
541 return ComplexMatrix ();
542
543 octave_idx_type info;
544 double rcond = 0.0;
545 return a.solve (typ, b, info, rcond, solve_singularity_warning);
546}
547
548// -*- 6 -*-
551{
552 if (! mx_leftdiv_conform (a, b))
553 return ComplexMatrix ();
554
555 octave_idx_type info;
556 double rcond = 0.0;
557 return a.solve (typ, b, info, rcond, solve_singularity_warning);
558}
559
560// -*- 7 -*-
563{
564 if (! mx_leftdiv_conform (a, b))
565 return SparseComplexMatrix ();
566
567 octave_idx_type info;
568 double rcond = 0.0;
569 return a.solve (typ, b, info, rcond, solve_singularity_warning);
570}
571
572// -*- 8 -*-
575 MatrixType& typ)
576{
577 if (! mx_leftdiv_conform (a, b))
578 return SparseComplexMatrix ();
579
580 octave_idx_type info;
581 double rcond = 0.0;
582 return a.solve (typ, b, info, rcond, solve_singularity_warning);
583}
584
585template <typename RT, typename DM, typename SM>
586RT
587do_leftdiv_dm_sm (const DM& d, const SM& a)
588{
589 const octave_idx_type a_nr = a.rows ();
590 const octave_idx_type a_nc = a.cols ();
591
592 const octave_idx_type d_nc = d.cols ();
593
594 using std::min;
595 const octave_idx_type nr = min (d_nc, a_nr);
596
597 if (! mx_leftdiv_conform (d, a))
598 return RT ();
599
600 const octave_idx_type nz = a.nnz ();
601 RT r (nr, a_nc, nz);
602
603 typedef typename DM::element_type DM_elt_type;
604 const DM_elt_type zero = DM_elt_type ();
605
606 octave_idx_type k_result = 0;
607 for (octave_idx_type j = 0; j < a_nc; ++j)
608 {
609 octave_quit ();
610 const octave_idx_type colend = a.cidx (j+1);
611 r.xcidx (j) = k_result;
612 for (octave_idx_type k = a.cidx (j); k < colend; ++k)
613 {
614 const octave_idx_type i = a.ridx (k);
615 if (i < nr)
616 {
617 const DM_elt_type s = d.dgelem (i);
618 if (s != zero)
619 {
620 r.xdata (k_result) = a.data (k) / s;
621 r.xridx (k_result) = i;
622 ++k_result;
623 }
624 }
625 }
626 }
627 r.xcidx (a_nc) = k_result;
628
629 r.maybe_compress (true);
630 return r;
631}
632
633// -*- 9 -*-
636{
637 return do_leftdiv_dm_sm<SparseMatrix> (d, a);
638}
639
640// -*- 10 -*-
643{
644 return do_leftdiv_dm_sm<SparseComplexMatrix> (d, a);
645}
646
647// -*- 11 -*-
650{
651 return do_leftdiv_dm_sm<SparseComplexMatrix> (d, a);
652}
653
654// -*- 12 -*-
657 MatrixType&)
658{
659 return do_leftdiv_dm_sm<SparseComplexMatrix> (d, a);
660}
661
662OCTAVE_END_NAMESPACE(octave)
charNDArray min(char d, const charNDArray &m)
Definition chNDArray.cc:207
T & elem(octave_idx_type n)
Size of the specified dimension.
Definition Array-base.h:585
ComplexMatrix hermitian() const
Definition CMatrix.h:168
MatrixType transpose() const
Matrix transpose() const
Definition dMatrix.h:138
SparseComplexMatrix hermitian() const
Definition CSparse.cc:853
ComplexMatrix solve(MatrixType &mattype, const Matrix &b) const
Definition CSparse.cc:6936
SparseMatrix transpose() const
Definition dSparse.h:131
Matrix solve(MatrixType &typ, const Matrix &b) const
Definition dSparse.cc:6888
octave_idx_type cols() const
Definition Sparse.h:351
octave_idx_type * cidx()
Definition Sparse.h:595
T * data()
Definition Sparse.h:573
octave_idx_type * ridx()
Definition Sparse.h:582
octave_idx_type rows() const
Definition Sparse.h:350
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
std::complex< double > Complex
Definition oct-cmplx.h:33
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
Matrix elem_xdiv(double a, const SparseMatrix &b)
Matrix xdiv(const Matrix &a, const SparseMatrix &b, MatrixType &typ)
bool mx_leftdiv_conform(const T1 &a, const T2 &b)
bool mx_div_conform(const T1 &a, const T2 &b)
RT do_rightdiv_sm_dm(const SM &a, const DM &d)
#define INSTANTIATE_MX_LEFTDIV_CONFORM(T1, T2)
#define INSTANTIATE_MX_DIV_CONFORM(T1, T2)
Matrix xleftdiv(const SparseMatrix &a, const Matrix &b, MatrixType &typ)
RT do_leftdiv_dm_sm(const DM &d, const SM &a)