Macaulay2 Engine
Loading...
Searching...
No Matches
lapack.cpp
Go to the documentation of this file.
1#include "coeffrings.hpp"
2#include "lapack.hpp"
3#include <M2/config.h>
4#include <iostream>
5
6#include "mat-arith.hpp"
7
8// lapack arrays are all arrays of doubles, and are
9// placed in column-major order, as that is what lapack uses.
10// Lapack arrays of complex numbers are done in the same way, except
11// they have twice the length, and 2 contiguous doubles are used to
12// represent a complex value.
13
14using LapackDoubles = double*;
15
17// same for RR/CC
19
20std::vector<double> make_lapack_array(const DMatRR& mat)
21{
22 size_t len = mat.numRows() * mat.numColumns();
23 std::vector<double> doubles(len);
24 size_t i = 0;
25 for (size_t c = 0; c < mat.numColumns(); ++c)
26 for (size_t r = 0; r < mat.numRows(); ++r)
27 doubles[i++] = mat.entry(r, c);
28 return doubles;
29}
30
31std::vector<double> make_lapack_array(const DMatCC& mat)
32{
33 size_t len = 2 * mat.numRows() * mat.numColumns();
34 std::vector<double> doubles(len);
35 size_t i = 0;
36 for (size_t c = 0; c < mat.numColumns(); ++c)
37 for (size_t r = 0; r < mat.numRows(); ++r)
38 {
39 doubles[i++] = mat.entry(r, c).re;
40 doubles[i++] = mat.entry(r, c).im;
41 }
42 return doubles;
43}
44
45void fill_from_lapack_array(const std::vector <double> & doubles, DMatRR& mat)
46{
47 size_t len = mat.numRows() * mat.numColumns();
48 if (len > doubles.size())
49 {
50 throw exc::engine_error("Internal error: a size in lapack code was set too small");
51 }
52 size_t i = 0;
53 for (size_t c = 0; c < mat.numColumns(); ++c)
54 for (size_t r = 0; r < mat.numRows(); ++r)
55 mat.entry(r, c) = doubles[i++];
56}
57
58void fill_from_lapack_array(const std::vector <double> & doubles, DMatCC& mat)
59{
60 size_t len = 2 * mat.numRows() * mat.numColumns();
61 if (len > doubles.size())
62 {
63 throw exc::engine_error("Internal error: a size in lapack CC code was set too small");
64 }
65 size_t i = 0;
66 for (size_t c = 0; c < mat.numColumns(); ++c)
67 for (size_t r = 0; r < mat.numRows(); ++r)
68 {
69 mat.entry(r, c).re = doubles[i++];
70 mat.entry(r, c).im = doubles[i++];
71 }
72}
73
74void fill_from_lapack_upper(const std::vector<double>& lapack_numbers, // column-major order
75 int numrows,
76 int numcols,
77 DMatRR &upper)
78// original matrix has size nrows x ncols
79// lapack_numbers is an array of this size
80// result: upper: size min(nrows, ncols) x ncols
81//
82// lapack_numbers is in column major form
83// upper is in row major form
84{
85 (void) numcols;
86 // At this point, upper should be a zero matrix of size (min(numrows, numcols) x numcols)
87 assert(upper.numRows() == std::min(numrows, numcols));
88 assert(upper.numColumns() == numcols);
89 assert(MatrixOps::isZero(upper));
90
91 const double* U = lapack_numbers.data();
92 for (size_t c = 0; c < upper.numColumns(); c++, U += numrows)
93 for (size_t r = 0; r <= c; ++r)
94 {
95 if (r >= upper.numRows()) break;
96 upper.entry(r, c) = U[r];
97 }
98}
99
100void fill_from_lapack_upper(const std::vector<double>& lapack_numbers, // column-major order
101 int numrows,
102 int numcols,
103 DMatCC &upper)
104// original matrix has size nrows x ncols
105// lapack_numbers is an array of this size
106// result: upper: size min(nrows, ncols) x ncols
107//
108// lapack_numbers is in column major form
109// upper is in row major form
110{
111 (void) numcols;
112 // At this point, upper should be a zero matrix of size (min(numrows, numcols) x numcols)
113 assert(upper.numRows() == std::min(numrows, numcols));
114 assert(upper.numColumns() == numcols);
115 assert(MatrixOps::isZero(upper));
116
117 const double* U = lapack_numbers.data();
118 for (size_t c = 0; c < upper.numColumns(); c++, U += 2*numrows)
119 for (size_t r = 0; r <= c; ++r)
120 {
121 if (r >= upper.numRows()) break;
122 upper.ring().set_from_doubles(upper.entry(r, c), U[2*r], U[2*r+1]);
123 }
124}
125
126void fill_lower_and_upper(const std::vector<double>& lapack_numbers, // column-major order
127 DMatRR &lower,
128 DMatRR &upper)
129// original matrix has size nrows x ncols
130// lapack_numbers is an array of this size (in column major order)
131// result: lower: size: nrows x min(nrows, ncols)
132// result: upper: size min x ncols
133{
134 int nrows = static_cast<int>(lower.numRows());
135 int ncols = static_cast<int>(upper.numColumns());
136 int min = static_cast<int>(lower.numColumns());
137 assert(min == static_cast<int>(upper.numRows()));
138
139 // At this point, lower and upper should be zero matrices.
140 assert(MatrixOps::isZero(lower));
141 assert(MatrixOps::isZero(upper));
142
143 const double* U = lapack_numbers.data();
144 for (size_t c = 0; c < upper.numColumns(); c++)
145 {
146 for (size_t r = 0; r <= c and r <= min; r++)
147 upper.entry(r, c) = *U++;
148 lower.entry(c, c) = 1;
149 for (size_t r = c+1 ; r <= lower.numColumns(); ++r)
150 lower.entry(r,c) = *U++;
151 }
152}
153
154void fill_lower_and_upper(const std::vector<double>& lapack_numbers, // column-major order
155 DMatCC &lower,
156 DMatCC &upper)
157// original matrix has size nrows x ncols
158// lapack_numbers is an array of this size (in column major order)
159// result: lower: size: nrows x min(nrows, ncols)
160// result: upper: size min x ncols
161{
162 auto& ring = lower.ring();
163 int nrows = static_cast<int>(lower.numRows());
164 int ncols = static_cast<int>(upper.numColumns());
165 int min = static_cast<int>(lower.numColumns());
166 assert(min == static_cast<int>(upper.numRows()));
167
168 // At this point, lower and upper should be zero matrices.
169 assert(MatrixOps::isZero(lower));
170 assert(MatrixOps::isZero(upper));
171
172 const double* U = lapack_numbers.data();
173 for (size_t c = 0; c < upper.numColumns(); c++)
174 {
175 for (size_t r = 0; r <= c and r <= min; r++)
176 {
177 double re = *U++;
178 double im = *U++;
179 ring.set_from_doubles(upper.entry(r, c), re, im);
180 // upper.entry(r, c).re = *U++;
181 // upper.entry(r, c).im = *U++;
182 }
183 ring.set_from_long(lower.entry(c, c), 1);
184 for (size_t r = c+1 ; r <= lower.numColumns(); ++r)
185 {
186 double re = *U++;
187 double im = *U++;
188 ring.set_from_doubles(lower.entry(r, c), re, im);
189 // lower.entry(r,c).re = *U++;
190 // lower.entry(r,c).im = *U++;
191 }
192 }
193}
194
196{
197 int rows = static_cast<int>(A->numRows());
198 int cols = static_cast<int>(A->numColumns());
199 int info;
200 int min = (rows <= cols) ? rows : cols;
202
203 L->resize(rows, min);
204 U->resize(min, cols);
205
206 if (min == 0)
207 {
208 if (rows > 0)
209 for (int i = 0; i < rows; i++) result->array[i] = i;
210 return result;
211 }
212
213 int* perm = new int[min];
214 std::vector<double> copyA = make_lapack_array(*A);
215
216 dgetrf_(&rows, &cols, copyA.data(), &rows, perm, &info);
217
218 fill_lower_and_upper(copyA, *L, *U);
219
220 for (int i = 0; i < rows; i++) result->array[i] = i;
221 for (int i = 0; i < min; i++)
222 {
223 int thisloc = perm[i] - 1;
224 int tmp = result->array[thisloc];
225 result->array[thisloc] = result->array[i];
226 result->array[i] = tmp;
227 }
228
229 delete [] perm;
230
231 if (info < 0)
232 {
233 ERROR("argument passed to dgetrf had an illegal value");
234 return nullptr;
235 }
236
237 return result;
238}
239
240bool Lapack::solve(const DMatRR *A, /* read only */
241 const DMatRR *b, /* read only */
242 DMatRR *x) /* output value */
243{
244 int size = static_cast<int>(A->numRows());
245 int bsize = static_cast<int>(b->numColumns());
246 int info;
247
248 /* make sure matrix is square */
249 if (A->numRows() != A->numColumns())
250 {
251 ERROR("expected a square matrix");
252 return false;
253 }
254
255 /* make sure dimensions of b make sense for Ax=b */
256 if (b->numRows() != size)
257 {
258 ERROR("expected matrices to have same number of rows");
259 return false;
260 ;
261 }
262
263 if (size == 0)
264 {
265 x->resize(size, bsize);
266 return true;
267 }
268
269 int* perm = new int[size];
270 std::vector<double> copyA = make_lapack_array(*A);
271 std::vector<double> copyb = make_lapack_array(*b);
272
273 dgesv_(&size,
274 &bsize,
275 copyA.data(),
276 &size,
277 perm,
278 copyb.data(), // also the result
279 &size,
280 &info);
281
282 delete [] perm; // Do we need this for anything??
283
284 // Now set x
285 x->resize(size, bsize);
286 fill_from_lapack_array(copyb, *x);
287
288 if (info > 0)
289 {
290 ERROR("according to dgesv, matrix is singular");
291 return false;
292 }
293 else if (info < 0)
294 {
295 ERROR("argument passed to dgesv had an illegal value");
296 return false;
297 }
298
299 return true;
300}
301
302bool Lapack::eigenvalues(const DMatRR *A, DMatCC *eigvals)
303{
304 int size = static_cast<int>(A->numRows());
305 if (size != static_cast<int>(A->numColumns()))
306 {
307 ERROR("expected a square matrix");
308 return false;
309 }
310
311 if (size == 0)
312 {
313 eigvals->resize(0, 1);
314 return true;
315 }
316
317 bool ret = true;
318 char dont = 'N';
319 int wsize = 3 * size;
320 double* workspace = new double[2 * wsize];
321 int info;
322
323 std::vector<double> copyA = make_lapack_array(*A);
324 double *real = new double[size]; // real components of eigvals
325 double *imag = new double[size]; // imaginary components
326
327 dgeev_(&dont,
328 &dont,
329 &size,
330 copyA.data(),
331 &size,
332 real,
333 imag,
334 static_cast<double *>(nullptr),
335 &size, /* left eigenvectors */
336 static_cast<double *>(nullptr),
337 &size, /* right eigenvectors */
338 workspace,
339 &wsize,
340 &info);
341
342 if (info < 0)
343 {
344 ERROR("argument passed to dgeev had an illegal value");
345 ret = false;
346 }
347 else if (info > 0)
348 {
349 ERROR("the QR algorithm in dgeev failed to compute all eigvals");
350 ret = false;
351 }
352 else
353 {
354 eigvals->resize(size, 1);
355 for (int i = 0; i < size; i++)
356 eigvals->ring().set_from_doubles(eigvals->entry(i, 0), real[i], imag[i]);
357 }
358
359 delete [] real;
360 delete [] imag;
361
362 return ret;
363}
364
366 DMatCC *eigvals,
367 DMatCC *eigvecs)
368{
369 int size = static_cast<int>(A->numRows());
370 if (size != static_cast<int>(A->numColumns()))
371 {
372 ERROR("expected a square matrix");
373 return false;
374 }
375
376 if (size == 0)
377 {
378 eigvals->resize(0, 1); // TODO: is this 1 correct?
379 eigvecs->resize(0, 0);
380 return true;
381 }
382
383 bool ret = true;
384 char dont = 'N';
385 char doit = 'V';
386 int wsize = 4 * size;
387
388 double *workspace = new double[2*wsize];
389 int info;
390
391 std::vector<double> copyA = make_lapack_array(*A);
392 double *real = new double[size]; // real components of eigvals
393 double *imag = new double[size]; // imaginary components
394 double *eigen = new double[size * size]; // eigvecs
395
396 dgeev_(&dont, /* left e-vectors */
397 &doit, /* right e-vectors */
398 &size,
399 copyA.data(),
400 &size,
401 real,
402 imag,
403 static_cast<double *>(nullptr),
404 &size, /* left eigvecs */
405 eigen,
406 &size, /* right eigvecs */
407 workspace,
408 &wsize,
409 &info);
410
411 if (info < 0)
412 {
413 ERROR("argument passed to dgeev had an illegal value");
414 ret = false;
415 }
416 else if (info > 0)
417 {
418 ERROR("the QR algorithm in dgeev failed to compute all eigvals");
419 ret = false;
420 }
421 else
422 {
423 // Make the complex arrays of eigvals and eigvecs
424 eigvals->resize(size, 1);
425 eigvecs->resize(size, size);
426 // DMatCC::ElementType *elems = eigvals->rowMajorArray();
427 double* eigenLoc = eigen; // current row (eigenvector) in the eigen array
428 for (int j = 0; j < size; j++, eigenLoc += size)
429 {
430 eigvals->ring().set_from_doubles(eigvals->entry(j,0), real[j], imag[j]);
431
432 // now set j-th column of eigvecs
433 if (imag[j] == 0)
434 {
435 for (int i = 0; i < size; ++i)
436 {
437 eigvecs->entry(i,j).re = eigenLoc[i];
438 eigvecs->entry(i,j).im = 0;
439 }
440 }
441 else if (imag[j] > 0)
442 {
443 for (int i = 0; i < size; ++i)
444 {
445 eigvecs->ring().set_from_doubles(eigvecs->entry(i,j),
446 eigenLoc[i], eigenLoc[size + i]);
447 eigvecs->ring().set_from_doubles(eigvecs->entry(i,j+1),
448 eigenLoc[i], - eigenLoc[size + i]);
449 }
450 }
451 }
452 }
453
454 delete [] workspace;
455 delete [] real;
456 delete [] imag;
457 delete [] eigen;
458
459 return ret;
460}
461
463{
464 int size = static_cast<int>(A->numRows());
465 if (size != static_cast<int>(A->numColumns()))
466 {
467 ERROR("expected a square matrix");
468 return false;
469 }
470
471 if (size == 0)
472 {
473 eigvals->resize(0, 1);
474 return true;
475 }
476
477 bool ret = true;
478 char dont = 'N';
479 char triangle = 'U'; /* Upper triangular part makes symmetric matrix. */
480 int info;
481
482 int wsize = 3 * size - 1;
483 double * workspace = new double[wsize];
484
485 std::vector<double> copyA = make_lapack_array(*A);
486 std::vector<double> evals(size);
487
488 dsyev_(
489 &dont, &triangle, &size, copyA.data(), &size, evals.data(), workspace, &wsize, &info);
490
491 if (info < 0)
492 {
493 ERROR("argument passed to dsyev had an illegal value");
494 ret = false;
495 }
496 else if (info > 0)
497 {
498 ERROR("dsyev did not converge");
499 ret = false;
500 }
501 else
502 {
503 // Copy eigenvalues back to eigvals
504 eigvals->resize(size, 1);
505 fill_from_lapack_array(evals, *eigvals);
506 }
507
508 delete [] workspace;
509
510 return ret;
511}
512
514 DMatRR *eigvals,
515 DMatRR *eigvecs)
516{
517 int size = static_cast<int>(A->numRows());
518 if (size != static_cast<int>(A->numColumns()))
519 {
520 ERROR("expected a square matrix");
521 return false;
522 }
523
524 if (size == 0)
525 {
526 eigvals->resize(0, 1);
527 eigvecs->resize(0, 0);
528 return true;
529 }
530
531 bool ret = true;
532 char doit = 'V';
533 char triangle = 'U'; /* Upper triangular part makes symmetric matrix */
534
535 int wsize = 3 * size - 1;
536 double* workspace = new double[wsize];
537 int info;
538
539 std::vector<double> evecs = make_lapack_array(*A);
540 std::vector<double> evals(size);
541
542 dsyev_(
543 &doit, &triangle, &size, evecs.data(), &size, evals.data(), workspace, &wsize, &info);
544
545 if (info < 0)
546 {
547 ERROR("argument passed to dsyev had an illegal value");
548 ret = false;
549 }
550 else if (info > 0)
551 {
552 ERROR("dsyev did not converge");
553 ret = false;
554 }
555 else
556 {
557 // Copy results to eigvals, eigvecs
558 eigvecs->resize(size, size);
559 fill_from_lapack_array(evecs, *eigvecs);
560 eigvals->resize(size, 1);
561 fill_from_lapack_array(evals, *eigvals);
562 }
563
564 delete [] workspace;
565
566 return ret;
567}
568
569bool Lapack::SVD(const DMatRR *A,
570 DMatRR *Sigma,
571 DMatRR *U,
572 DMatRR *VT)
573{
574 bool ret = true;
575 char doit = 'A'; // other options are 'S' and 'O' for singular vectors only
576 int rows = static_cast<int>(A->numRows());
577 int cols = static_cast<int>(A->numColumns());
578 int info;
579 int min = (rows <= cols) ? rows : cols;
580
581 if (min == 0)
582 {
583 ERROR("expected a matrix with positive dimensions");
584 return false;
585 }
586
587 int max = (rows >= cols) ? rows : cols;
588 int wsize = (3 * min + max >= 5 * min) ? 3 * min + max : 5 * min;
589 double *workspace = new double[wsize];
590
591 std::vector<double> copyA = make_lapack_array(*A);
592 std::vector<double> u(rows * rows);
593 std::vector<double> vt(cols * cols);
594 std::vector<double> sigma(min);
595
596 dgesvd_(&doit,
597 &doit,
598 &rows,
599 &cols,
600 copyA.data(),
601 &rows,
602 sigma.data(),
603 u.data(),
604 &rows,
605 vt.data(),
606 &cols,
607 workspace,
608 &wsize,
609 &info);
610
611 if (info < 0)
612 {
613 ERROR("argument passed to dgesvd had an illegal value");
614 ret = false;
615 }
616 else if (info > 0)
617 {
618 ERROR("dgesvd did not converge");
619 ret = false;
620 }
621 else
622 {
623 U->resize(rows, rows);
624 VT->resize(cols, cols);
625 Sigma->resize(min, 1);
627 fill_from_lapack_array(vt, *VT);
628 fill_from_lapack_array(sigma, *Sigma);
629 }
630
631 delete [] workspace;
632
633 return ret;
634}
635
637 DMatRR *Sigma,
638 DMatRR *U,
639 DMatRR *VT)
640{
641 bool ret = true;
642 char doit = 'A'; // other options are 'S' and 'O' for singular vectors only
643 int rows = static_cast<int>(A->numRows());
644 int cols = static_cast<int>(A->numColumns());
645 int info;
646 int min = (rows <= cols) ? rows : cols;
647
648 if (min == 0)
649 {
650 ERROR("expected a matrix with positive dimensions");
651 return false;
652 }
653
654 int max = (rows >= cols) ? rows : cols;
655 int wsize = 4 * min * min + max + 9 * min;
656
657 double *workspace = new double[wsize];
658 int* iworkspace = new int[8 * min];
659
660 std::vector<double> copyA = make_lapack_array(*A);
661 std::vector<double> u(rows * rows);
662 std::vector<double> vt(cols * cols);
663 std::vector<double> sigma(min);
664
665 dgesdd_(&doit,
666 &rows,
667 &cols,
668 copyA.data(),
669 &rows,
670 sigma.data(),
671 u.data(),
672 &rows,
673 vt.data(),
674 &cols,
675 workspace,
676 &wsize,
677 iworkspace,
678 &info);
679
680 if (info < 0)
681 {
682 ERROR("argument passed to dgesdd had an illegal value");
683 ret = false;
684 }
685 else if (info > 0)
686 {
687 ERROR("dgesdd did not converge");
688 ret = false;
689 }
690 else
691 {
692 U->resize(rows, rows);
693 VT->resize(cols, cols);
694 Sigma->resize(min, 1);
696 fill_from_lapack_array(vt, *VT);
697 fill_from_lapack_array(sigma, *Sigma);
698 }
699
700 delete [] workspace;
701 delete [] iworkspace;
702
703 return ret;
704}
705
706// YYY working on this one!!
707bool Lapack::least_squares(const DMatRR *A, const DMatRR *b, DMatRR *x)
708{
709 bool ret = true;
710 char job = 'N';
711 int info;
712 int rows = static_cast<int>(A->numRows());
713 int cols = static_cast<int>(A->numColumns());
714 int brows = static_cast<int>(b->numRows());
715 int bcols = static_cast<int>(b->numColumns());
716 int min = (rows <= cols) ? rows : cols;
717 int max = (rows >= cols) ? rows : cols;
718 int wsize = min + ((bcols >= max) ? bcols : max);
719
720 if (brows != rows)
721 {
722 ERROR("expected compatible right hand side");
723 return false;
724 }
725
726 if (min == 0 || bcols == 0)
727 {
728 x->resize(cols, bcols);
729 return true;
730 }
731
732 std::vector<double> copyA = make_lapack_array(*A);
733 std::vector<double> copyb = make_lapack_array(*b);
734 double* workspace = new double[wsize];
735
736 if (rows < cols)
737 {
738 // Make 'b' (copyb) into a cols x bcols matrix, by adding a zero block at
739 // the bottom
740 std::vector<double> copyb2(cols * bcols);
741 for (auto&a : copyb2) a = 0;
742 int bloc = 0;
743 int copyloc = 0;
744 for (int j = 0; j < bcols; j++)
745 {
746 copyloc = j * cols;
747 for (int i = 0; i < brows; i++)
748 {
749 copyb2[copyloc++] = copyb[bloc++];
750 }
751 }
752 std::swap(copyb2, copyb);
753 }
754
755 dgels_(&job,
756 &rows,
757 &cols,
758 &bcols,
759 copyA.data(),
760 &rows,
761 copyb.data(),
762 &max,
763 workspace,
764 &wsize,
765 &info);
766
767 if (info != 0)
768 {
769 ERROR("argument passed to dgels had an illegal value");
770 ret = false;
771 }
772 else
773 {
774 x->resize(cols, bcols);
775 if (rows > cols)
776 {
777 // We only need the first 'cols' rows of copyb
778 int copyloc = 0;
779 for (int j = 0; j < bcols; j++)
780 {
781 copyloc = j * rows;
782 for (int i = 0; i < cols; i++)
783 {
784 x->entry(i,j) = copyb[copyloc++];
785 }
786 }
787 }
788 else
789 {
790 fill_from_lapack_array(copyb, *x);
791 }
792 }
793
794 delete [] workspace;
795
796 return ret;
797}
798
800 const DMatRR *b,
801 DMatRR *x)
802{
803 bool ret = true;
804 int rows = static_cast<int>(A->numRows());
805 int cols = static_cast<int>(A->numColumns());
806 int brows = static_cast<int>(b->numRows());
807 int bcols = static_cast<int>(b->numColumns());
808 double rcond = -1.0; // use machine precision
809 int rank, info;
810 int min = (rows < cols) ? rows : cols;
811 int max = (rows > cols) ? rows : cols;
812 int tempmax = ((2 * min > max) ? 2 * min : max);
813 int wsize = 3 * min + ((tempmax > bcols) ? tempmax : bcols);
814
815 if (brows != rows)
816 {
817 ERROR("expected compatible right hand side");
818 return false;
819 }
820
821 if (min == 0 || bcols == 0)
822 {
823 x->resize(cols, bcols);
824 return true;
825 }
826
827 std::vector<double> copyA = make_lapack_array(*A);
828 std::vector<double> copyb = make_lapack_array(*b);
829 double *workspace = new double[wsize];
830 double *sing = new double[min];
831
832 if (rows < cols)
833 {
834 // Make 'b' (copyb) into a cols x bcols matrix, by adding a zero block at
835 // the bottom
836 std::vector<double> copyb2(cols * bcols);
837 for (auto&a : copyb2) a = 0;
838 int bloc = 0;
839 int copyloc = 0;
840 for (int j = 0; j < bcols; j++)
841 {
842 copyloc = j * cols;
843 for (int i = 0; i < brows; i++)
844 {
845 copyb2[copyloc++] = copyb[bloc++];
846 }
847 }
848 std::swap(copyb2, copyb);
849 }
850
851 dgelss_(&rows,
852 &cols,
853 &bcols,
854 copyA.data(),
855 &rows,
856 copyb.data(),
857 &max,
858 sing,
859 &rcond,
860 &rank,
861 workspace,
862 &wsize,
863 &info);
864
865 if (info != 0)
866 {
867 ERROR("argument passed to dgelss had an illegal value");
868 ret = false;
869 }
870 else
871 {
872 x->resize(cols, bcols);
873 if (rows > cols)
874 {
875 // We only need the first 'cols' rows of copyb
876 int copyloc = 0;
877 for (int j = 0; j < bcols; j++)
878 {
879 copyloc = j * rows;
880 for (int i = 0; i < cols; i++)
881 {
882 x->entry(i,j) = copyb[copyloc++];
883 }
884 }
885 }
886 else
887 {
888 fill_from_lapack_array(copyb, *x);
889 }
890 }
891
892 delete [] workspace;
893 delete [] sing;
894
895 return ret;
896}
897
898bool Lapack::QR(const DMatRR *A, DMatRR *Q, DMatRR *R, bool return_QR)
899{
900 // sizes:
901 // input: A[m,n]
902 // output for returnQR==true:
903 // case m >= n: Q[m,n], R[n,n]
904 // case m < n: Q[m,m], R[m,n]
905 // output for returnQR==false:
906 // Q[m,n], R[1,min(m,n)]
907 bool ret = true;
908 int rows = static_cast<int>(A->numRows());
909 int cols = static_cast<int>(A->numColumns());
910 int info1 = 0, info2 = 0, info3 = 0, info4 = 0;
911 int min = (rows <= cols) ? rows : cols;
912
913 if (min == 0)
914 {
915 ERROR("expected a matrix with positive dimensions");
916 return false;
917 }
918
919 std::vector<double> copyA = make_lapack_array(*A);
920 std::vector<double> tau (min); // TODO: set to 0??
921 double workspace_size[1];
922 int work_size = -1;
923 // find optimal workspace
924 dgeqrf_(&rows, &cols, copyA.data(), &rows, tau.data(), workspace_size, &work_size, &info1);
925 work_size = static_cast<int>(workspace_size[0]);
926 // std::cout << "work size for QR: " << work_size << std::endl;
927 double *workspace = new double[work_size];
928
929 dgeqrf_(&rows, &cols, copyA.data(), &rows, tau.data(), workspace, &work_size, &info2);
930
931 if (info1 < 0 or info2 < 0)
932 {
933 ERROR("argument passed to dgeqrf had an illegal value");
934 ret = false;
935 }
936 if (info1 > 0 or info2 > 0)
937 {
938 ERROR("can this happen?");
939 ret = false;
940 }
941
942 if (ret)
943 {
944 if (return_QR)
945 {
946 Q->resize(rows, cols);
947 R->resize(cols, cols);
948 fill_from_lapack_upper(copyA, rows, cols, *R);
949
950 // Reset Q, R, with their values.
951 int orgqr_work_size = -1;
952 dorgqr_(&rows,
953 &cols,
954 &min,
955 copyA.data(),
956 &rows, // lda?
957 tau.data(),
958 workspace_size,
959 &orgqr_work_size,
960 &info3);
961 orgqr_work_size = static_cast<int>(workspace_size[0]);
962 if (orgqr_work_size > work_size)
963 {
964 delete[] workspace;
965 work_size = orgqr_work_size;
966 workspace = new double[work_size];
967 std::cout << "work size increased to: " << work_size << std::endl;
968 }
969 dorgqr_(&rows,
970 &cols,
971 &min,
972 copyA.data(),
973 &rows, // lda?
974 tau.data(),
975 workspace,
976 &work_size,
977 &info4);
978 if (info3 < 0 or info4 < 0)
979 {
980 ERROR("argument passed to dorgqr or dorgqr had an illegal value");
981 ret = false;
982 }
983 else if (info3 > 0 or info4 > 0)
984 {
985 ERROR("can this happen?");
986 ret = false;
987 }
988 else
989 {
990 fill_from_lapack_array(copyA, *Q);
991 }
992 }
993 else
994 {
995 // Return the raw values for QR: the "A" matrix encodes R and the
996 // Householders, and tau has the multipliers.
997 Q->resize(rows, cols);
998 R->resize(1, min);
999 fill_from_lapack_array(copyA, *Q);
1000 fill_from_lapack_array(tau, *R);
1001 }
1002 }
1003
1004 delete[] workspace;
1005
1006 return ret;
1007}
1008
1009bool Lapack::QR(const DMatCC *A, DMatCC *Q, DMatCC *R, bool return_QR)
1010{
1011 // sizes:
1012 // input: A[m,n]
1013 // output for returnQR==true:
1014 // case m >= n: Q[m,n], R[n,n]
1015 // case m < n: Q[m,m], R[m,n]
1016 // output for returnQR==false:
1017 // Q[m,n], R[1,min(m,n)]
1018 bool ret = true;
1019 int rows = static_cast<int>(A->numRows());
1020 int cols = static_cast<int>(A->numColumns());
1021 int info1 = 0, info2 = 0, info3 = 0, info4 = 0;
1022 int min = (rows <= cols) ? rows : cols;
1023
1024 if (min == 0)
1025 {
1026 ERROR("expected a matrix with positive dimensions");
1027 return false;
1028 }
1029
1030 std::vector<double> copyA = make_lapack_array(*A); // delete as well.
1031 std::vector<double> tau (10*min); // TODO: set to 0?
1032 double workspace_size[1];
1033 int work_size = -1;
1034 // find optimal workspace
1035 zgeqrf_(&rows, &cols, copyA.data(), &rows, tau.data(), workspace_size, &work_size, &info1);
1036 work_size = static_cast<int>(workspace_size[0]);
1037 double *workspace = new double[20 * work_size];
1038
1039 zgeqrf_(&rows, &cols, copyA.data(), &rows, tau.data(), workspace, &work_size, &info2);
1040
1041 if (info1 < 0 or info2 < 0)
1042 {
1043 ERROR("argument passed to zgeqrf had an illegal value");
1044 ret = false;
1045 }
1046 if (info1 > 0 or info2 > 0)
1047 {
1048 ERROR("can this happen?");
1049 ret = false;
1050 }
1051
1052 if (ret)
1053 {
1054 if (return_QR)
1055 {
1056 Q->resize(rows, cols);
1057 R->resize(cols, cols);
1058 fill_from_lapack_upper(copyA, rows, cols, *R);
1059
1060 // Reset Q, R, with their values.
1061 int orgqr_work_size = -1;
1062 zungqr_(&rows,
1063 &cols,
1064 &min,
1065 copyA.data(),
1066 &rows, // lda?
1067 tau.data(),
1068 workspace_size,
1069 &orgqr_work_size,
1070 &info3);
1071 orgqr_work_size = static_cast<int>(workspace_size[0]);
1072 if (orgqr_work_size > work_size)
1073 {
1074 delete[] workspace;
1075 work_size = orgqr_work_size;
1076 workspace = new double[2 * work_size];
1077 }
1078 zungqr_(&rows,
1079 &cols,
1080 &min,
1081 copyA.data(),
1082 &rows, // lda?
1083 tau.data(),
1084 workspace,
1085 &work_size,
1086 &info4);
1087 if (info3 < 0 or info4 < 0)
1088 {
1089 ERROR("argument passed to dorgqr or dorgqr had an illegal value");
1090 ret = false;
1091 }
1092 else if (info3 > 0 or info4 > 0)
1093 {
1094 ERROR("can this happen?");
1095 ret = false;
1096 }
1097 else
1098 {
1099 fill_from_lapack_array(copyA, *Q);
1100 }
1101 }
1102 else
1103 {
1104 // Return the raw values for QR: the "A" matrix encodes R and the
1105 // Householders, and tau has the multipliers.
1106 Q->resize(rows, cols);
1107 R->resize(1, min);
1108 fill_from_lapack_array(copyA, *Q);
1109 fill_from_lapack_array(tau, *R);
1110 }
1111 }
1112
1113 delete[] workspace;
1114 return ret;
1115}
1116
1118{
1119 int rows = static_cast<int>(A->numRows());
1120 int cols = static_cast<int>(A->numColumns());
1121 int info;
1122 int min = (rows <= cols) ? rows : cols;
1124
1125 L->resize(rows, min);
1126 U->resize(min, cols);
1127
1128 if (min == 0)
1129 {
1130 if (rows > 0)
1131 for (int i = 0; i < rows; i++) result->array[i] = i;
1132 return result;
1133 }
1134
1135 int* perm = new int[min];
1136 std::vector<double> copyA = make_lapack_array(*A);
1137
1138 zgetrf_(&rows, &cols, copyA.data(), &rows, perm, &info);
1139
1140 if (info < 0)
1141 {
1142 ERROR("argument passed to zgetrf had an illegal value");
1143 result = nullptr;
1144 }
1145 else
1146 {
1147 fill_lower_and_upper(copyA, *L, *U);
1148
1149 for (int i = 0; i < rows; i++) result->array[i] = i;
1150 for (int i = 0; i < min; i++)
1151 {
1152 int thisloc = perm[i] - 1;
1153 int tmp = result->array[thisloc];
1154 result->array[thisloc] = result->array[i];
1155 result->array[i] = tmp;
1156 }
1157
1158// TODO: What is this block? Remove it?
1159#if 0
1160 /* set the permutation array */
1161 for (int row=1; row<=min; row++) {
1162 int targ = row;
1163 for (int i=1; i<=min; i++) {
1164 if (i == targ)
1165 targ = perm[i-1];
1166 else if (perm[i-1] == targ)
1167 targ = i;
1168 }
1169 result->array[row-1] = targ-1;
1170 }
1171 for (int i=min; i<rows; i++)
1172 result->array[i] = i;
1173#endif
1174 }
1175
1176 delete[] perm;
1177 return result;
1178}
1179
1180bool Lapack::solve(const DMatCC *A, const DMatCC *b, DMatCC *x)
1181{
1182 bool ret = true;
1183 int size = static_cast<int>(A->numRows());
1184 int bsize = static_cast<int>(b->numColumns());
1185 int info;
1186
1187 /* make sure matrix is square */
1188 if (size != static_cast<int>(A->numColumns()))
1189 {
1190 ERROR("expected a square matrix");
1191 return false;
1192 }
1193
1194 /* make sure dimensions of b make sense for Ax=b */
1195 if (b->numRows() != size)
1196 {
1197 ERROR("expected matrices to have same number of rows");
1198 return false;
1199 }
1200
1201 if (size == 0)
1202 {
1203 x->resize(size, bsize);
1204 return true;
1205 }
1206
1207 int* permutation = new int[size]; // TODO: set to 0?
1208 std::vector<double> copyA = make_lapack_array(*A);
1209 std::vector<double> copyb = make_lapack_array(*b);
1210
1211 zgesv_(&size, &bsize, copyA.data(), &size, permutation, copyb.data(), &size, &info);
1212
1213 if (info > 0)
1214 {
1215 ERROR("according to zgesv, matrix is singular");
1216 ret = false;
1217 }
1218 else if (info < 0)
1219 {
1220 ERROR("argument passed to zgesv had an illegal value");
1221 ret = false;
1222 }
1223 else
1224 {
1225 x->resize(size, bsize);
1226 fill_from_lapack_array(copyb, *x);
1227 }
1228
1229 delete [] permutation;
1230 return ret;
1231}
1232
1233bool Lapack::eigenvalues(const DMatCC *A, DMatCC *eigvals)
1234{
1235 int size = static_cast<int>(A->numRows());
1236 if (size != static_cast<int>(A->numColumns()))
1237 {
1238 ERROR("expected a square matrix");
1239 return false;
1240 }
1241
1242 if (size == 0)
1243 {
1244 eigvals->resize(0, 1);
1245 return true;
1246 }
1247
1248 bool ret = true;
1249 char dont = 'N';
1250 int info;
1251 int wsize = 2 * size;
1252 int rsize = 2 * size;
1253 double *workspace = new double[2*wsize];
1254 double *rwork = new double[rsize];
1255
1256 std::vector<double> copyA = make_lapack_array(*A);
1257 std::vector<double> evals(2 * size); // TODO: set to 0?
1258
1259 zgeev_(&dont,
1260 &dont,
1261 &size,
1262 copyA.data(),
1263 &size,
1264 evals.data(),
1265 static_cast<double *>(nullptr),
1266 &size, /* left eigenvectors */
1267 static_cast<double *>(nullptr),
1268 &size, /* right eigenvectors */
1269 workspace,
1270 &wsize,
1271 rwork,
1272 &info);
1273
1274 if (info < 0)
1275 {
1276 ERROR("argument passed to zgeev had an illegal value");
1277 ret = false;
1278 }
1279 else if (info > 0)
1280 {
1281 ERROR("the QR algorithm in zgeev failed to compute all eigvals");
1282 ret = false;
1283 }
1284 else
1285 {
1286 eigvals->resize(size, 1);
1287 fill_from_lapack_array(evals, *eigvals);
1288 }
1289
1290 delete[] workspace;
1291 delete[] rwork;
1292
1293 return ret;
1294}
1295
1297 DMatCC *eigvals,
1298 DMatCC *eigvecs)
1299{
1300 int size = static_cast<int>(A->numRows());
1301 if (size != static_cast<int>(A->numColumns()))
1302 {
1303 ERROR("expected a square matrix");
1304 return false;
1305 }
1306
1307 if (size == 0)
1308 {
1309 eigvals->resize(0, 1);
1310 eigvecs->resize(0, 0);
1311 return true;
1312 }
1313
1314 bool ret = true;
1315 char dont = 'N';
1316 char doit = 'V';
1317 int wsize = 2 * size;
1318 int rsize = 2 * size;
1319 double *workspace = new double[2*wsize];
1320 double *rwork = new double[rsize];
1321 int info;
1322
1323 std::vector<double> copyA = make_lapack_array(*A);
1324 std::vector<double> evals(2 * size);
1325 std::vector<double> evecs(2 * size * size);
1326
1327 zgeev_(&dont,
1328 &doit,
1329 &size,
1330 copyA.data(),
1331 &size,
1332 evals.data(),
1333 static_cast<double *>(nullptr),
1334 &size, /* left eigvecs */
1335 evecs.data(),
1336 &size, /* right eigvecs */
1337 workspace,
1338 &wsize,
1339 rwork,
1340 &info);
1341
1342 if (info < 0)
1343 {
1344 ERROR("argument passed to zgeev had an illegal value");
1345 ret = false;
1346 }
1347 else if (info > 0)
1348 {
1349 ERROR("the QR algorithm in zgeev failed to compute all eigvals");
1350 ret = false;
1351 }
1352 else
1353 {
1354 eigvals->resize(size, 1);
1355 fill_from_lapack_array(evals, *eigvals);
1356 eigvecs->resize(size, size);
1357 fill_from_lapack_array(evecs, *eigvecs);
1358 }
1359
1360 delete[] workspace;
1361 delete[] rwork;
1362
1363 return ret;
1364}
1365
1367{
1368 int size = static_cast<int>(A->numRows());
1369 if (size != static_cast<int>(A->numColumns()))
1370 {
1371 ERROR("expected a square matrix");
1372 return false;
1373 }
1374
1375 if (size == 0)
1376 {
1377 eigvals->resize(0, 1);
1378 return true;
1379 }
1380
1381 bool ret = true;
1382 char dont = 'N';
1383 char triangle = 'U'; /* Upper triangular part makes symmetric matrix. */
1384
1385 int wsize = 2 * size - 1;
1386 double *workspace = new double[2*wsize];
1387 double *rwork = new double[3 * size - 2];
1388 int info;
1389
1390 std::vector<double> copyA = make_lapack_array(*A);
1391 std::vector<double> evals(size);
1392
1393 zheev_(&dont,
1394 &triangle,
1395 &size,
1396 copyA.data(),
1397 &size,
1398 evals.data(),
1399 workspace,
1400 &wsize,
1401 rwork,
1402 &info);
1403
1404 if (info < 0)
1405 {
1406 ERROR("argument passed to zheev had an illegal value");
1407 ret = false;
1408 }
1409 else if (info > 0)
1410 {
1411 ERROR("zheev did not converge");
1412 ret = false;
1413 }
1414 else
1415 {
1416 eigvals->resize(size, 1);
1417 fill_from_lapack_array(evals, *eigvals);
1418 }
1419
1420 delete[] workspace;
1421 delete[] rwork;
1422
1423 return ret;
1424}
1425
1427 DMatRR *eigvals,
1428 DMatCC *eigvecs)
1429{
1430 int size = static_cast<int>(A->numRows());
1431 if (size != static_cast<int>(A->numColumns()))
1432 {
1433 ERROR("expected a square matrix");
1434 return false;
1435 }
1436
1437 if (size == 0)
1438 {
1439 eigvals->resize(0, 1);
1440 eigvecs->resize(0, 0);
1441 return true;
1442 }
1443
1444 bool ret = true;
1445 char doit = 'V';
1446 char triangle = 'U'; /* Upper triangular part makes symmetric matrix */
1447
1448 int wsize = 2 * size - 1;
1449 double *workspace = new double[2*wsize];
1450 double *rwork = new double[3 * size - 2];
1451 int info;
1452
1453 std::vector<double> evecs = make_lapack_array(*A);
1454 std::vector<double> evals(size);
1455
1456 zheev_(&doit,
1457 &triangle,
1458 &size,
1459 evecs.data(),
1460 &size,
1461 evals.data(),
1462 workspace,
1463 &wsize,
1464 rwork,
1465 &info);
1466
1467 if (info < 0)
1468 {
1469 ERROR("argument passed to zheev had an illegal value");
1470 ret = false;
1471 }
1472 else if (info > 0)
1473 {
1474 ERROR("zheev did not converge");
1475 ret = false;
1476 }
1477 else
1478 {
1479 eigvals->resize(size, 1);
1480 fill_from_lapack_array(evals, *eigvals);
1481 eigvecs->resize(size, size);
1482 fill_from_lapack_array(evecs, *eigvecs);
1483 }
1484
1485 delete[] workspace;
1486 delete[] rwork;
1487
1488 return ret;
1489}
1490
1491bool Lapack::SVD(const DMatCC *A,
1492 DMatRR *Sigma,
1493 DMatCC *U,
1494 DMatCC *VT)
1495{
1496 bool ret = true;
1497 char doit = 'A'; // other options are 'S' and 'O' for singular vectors only
1498 int rows = static_cast<int>(A->numRows());
1499 int cols = static_cast<int>(A->numColumns());
1500 int info;
1501 int min = (rows <= cols) ? rows : cols;
1502
1503 if (min == 0)
1504 {
1505 ERROR("expected a matrix with positive dimensions");
1506 return false;
1507 }
1508
1509 int max = (rows >= cols) ? rows : cols;
1510 int wsize = 2 * min + max;
1511 double *workspace = new double[2 * wsize];
1512 double *rwork = new double[5 * min];
1513
1514 std::vector<double> copyA = make_lapack_array(*A);
1515 std::vector<double> u(2 * rows * rows);
1516 std::vector<double> vt(2 * cols * cols);
1517 std::vector<double> sigma(2 * min);
1518
1519 zgesvd_(&doit,
1520 &doit,
1521 &rows,
1522 &cols,
1523 copyA.data(),
1524 &rows,
1525 sigma.data(),
1526 u.data(),
1527 &rows,
1528 vt.data(),
1529 &cols,
1530 workspace,
1531 &wsize,
1532 rwork,
1533 &info);
1534
1535 if (info < 0)
1536 {
1537 ERROR("argument passed to zgesvd had an illegal value");
1538 ret = false;
1539 }
1540 else if (info > 0)
1541 {
1542 ERROR("zgesvd did not converge");
1543 ret = false;
1544 }
1545 else
1546 {
1547 U->resize(rows, rows);
1549 VT->resize(cols, cols);
1550 fill_from_lapack_array(vt, *VT);
1551 Sigma->resize(min, 1);
1552 fill_from_lapack_array(sigma, *Sigma);
1553 }
1554
1555 delete[] workspace;
1556 delete[] rwork;
1557
1558 return ret;
1559}
1560
1562 DMatRR *Sigma,
1563 DMatCC *U,
1564 DMatCC *VT)
1565{
1566 bool ret = true;
1567 char doit = 'A'; // other options are 'S' and 'O' for singular vectors only
1568 int rows = static_cast<int>(A->numRows());
1569 int cols = static_cast<int>(A->numColumns());
1570 int info;
1571 int min = (rows <= cols) ? rows : cols;
1572
1573 if (min == 0)
1574 {
1575 ERROR("expected a matrix with positive dimensions");
1576 return false;
1577 }
1578
1579 int max = (rows >= cols) ? rows : cols;
1580 int wsize = min * min + 2 * min + max;
1581
1582 double *workspace = new double[2 * wsize];
1583 int *iworkspace = new int[8 * min];
1584 double *rwork = new double[5 * min * min + 7 * min]; // documentation not clear
1585
1586 std::vector<double> copyA = make_lapack_array(*A);
1587 std::vector<double> u(2 * rows * rows);
1588 std::vector<double> vt(2 * cols * cols);
1589 std::vector<double> sigma(2 * min);
1590
1591 zgesdd_(&doit,
1592 &rows,
1593 &cols,
1594 copyA.data(),
1595 &rows,
1596 sigma.data(),
1597 u.data(),
1598 &rows,
1599 vt.data(),
1600 &cols,
1601 workspace,
1602 &wsize,
1603 rwork,
1604 iworkspace,
1605 &info);
1606
1607 if (info < 0)
1608 {
1609 ERROR("argument passed to zgesdd had an illegal value");
1610 ret = false;
1611 }
1612 else if (info > 0)
1613 {
1614 ERROR("zgesdd did not converge");
1615 ret = false;
1616 }
1617 else
1618 {
1619 U->resize(rows, rows);
1621 VT->resize(cols, cols);
1622 fill_from_lapack_array(vt, *VT);
1623 Sigma->resize(min, 1);
1624 fill_from_lapack_array(sigma, *Sigma);
1625 }
1626
1627 delete[] workspace;
1628 delete[] iworkspace;
1629 delete[] rwork;
1630
1631 return ret;
1632}
1633
1634bool Lapack::least_squares(const DMatCC *A, const DMatCC *b, DMatCC *x)
1635{
1636 bool ret = true;
1637 char job = 'N';
1638 int info;
1639 int rows = static_cast<int>(A->numRows());
1640 int cols = static_cast<int>(A->numColumns());
1641 int brows = static_cast<int>(b->numRows());
1642 int bcols = static_cast<int>(b->numColumns());
1643 int min = (rows <= cols) ? rows : cols;
1644 int max = (rows >= cols) ? rows : cols;
1645 int wsize = min + ((bcols >= max) ? bcols : max);
1646
1647 if (brows != rows)
1648 {
1649 ERROR("expected compatible right hand side");
1650 return false;
1651 }
1652
1653 if (min == 0 || bcols == 0)
1654 {
1655 x->resize(cols, bcols);
1656 return true;
1657 }
1658
1659 std::vector<double> copyA = make_lapack_array(*A);
1660 std::vector<double> copyb = make_lapack_array(*b);
1661 double *workspace = new double[2 * wsize];
1662
1663 if (rows < cols)
1664 {
1665 // Make 'b' (copyb) into a cols x bcols matrix, by adding a zero block at
1666 // the bottom
1667 std::vector<double> copyb2(2 * cols * bcols);
1668 for (auto& a : copyb2) a = 0;
1669 int bloc = 0;
1670 int copyloc = 0;
1671 for (int j = 0; j < bcols; j++)
1672 {
1673 copyloc = 2 * j * cols;
1674 for (int i = 0; i < 2 * brows; i++)
1675 {
1676 copyb2[copyloc++] = copyb[bloc++];
1677 }
1678 }
1679 std::swap(copyb, copyb2);
1680 }
1681
1682 zgels_(&job,
1683 &rows,
1684 &cols,
1685 &bcols,
1686 copyA.data(),
1687 &rows,
1688 copyb.data(),
1689 &max,
1690 workspace,
1691 &wsize,
1692 &info);
1693
1694 if (info != 0)
1695 {
1696 ERROR("argument passed to zgels had an illegal value");
1697 ret = false;
1698 }
1699 else
1700 {
1701 x->resize(cols, bcols);
1702 if (rows > cols)
1703 {
1704 // We only need the first 'cols' rows of copyb
1705 int copyloc = 0;
1706 for (int j = 0; j < bcols; j++)
1707 {
1708 copyloc = 2 * j * rows;
1709 for (int i = 0; i < cols; i++)
1710 {
1711 double re = copyb[copyloc++];
1712 double im = copyb[copyloc++];
1713 x->ring().set_from_doubles(x->entry(i,j), re, im);
1714 }
1715 }
1716 }
1717 else
1718 {
1719 fill_from_lapack_array(copyb, *x);
1720 }
1721 }
1722
1723 delete[] workspace;
1724
1725 return ret;
1726}
1727
1729 const DMatCC *b,
1730 DMatCC *x)
1731{
1732 bool ret = true;
1733 int rows = static_cast<int>(A->numRows());
1734 int cols = static_cast<int>(A->numColumns());
1735 int brows = static_cast<int>(b->numRows());
1736 int bcols = static_cast<int>(b->numColumns());
1737 double rcond = -1.0;
1738 int rank, info;
1739 int min = (rows < cols) ? rows : cols;
1740 int max = (rows > cols) ? rows : cols;
1741 int wsize = 2 * min + ((bcols > max) ? bcols : max);
1742
1743 if (brows != rows)
1744 {
1745 ERROR("expected compatible right hand side");
1746 return false;
1747 }
1748
1749 if (min == 0 || bcols == 0)
1750 {
1751 x->resize(cols, bcols);
1752 return true;
1753 }
1754
1755 std::vector<double> copyA = make_lapack_array(*A);
1756 std::vector<double> copyb = make_lapack_array(*b);
1757 double *workspace = new double[2 * wsize];
1758 double *sing = new double[min];
1759 double *rwork = new double[5 * min];
1760
1761 if (rows < cols)
1762 {
1763 // Make 'b' (copyb) into a cols x bcols matrix, by adding a zero block at
1764 // the bottom
1765 std::vector<double> copyb2(2 * cols * bcols);
1766 for (auto& a : copyb2) a = 0;
1767 int bloc = 0;
1768 int copyloc = 0;
1769 for (int j = 0; j < bcols; j++)
1770 {
1771 copyloc = 2 * j * cols;
1772 for (int i = 0; i < 2 * brows; i++)
1773 {
1774 copyb2[copyloc++] = copyb[bloc++];
1775 }
1776 }
1777 std::swap(copyb, copyb2);
1778 }
1779
1780 zgelss_(&rows,
1781 &cols,
1782 &bcols,
1783 copyA.data(),
1784 &rows,
1785 copyb.data(),
1786 &max,
1787 sing,
1788 &rcond,
1789 &rank,
1790 workspace,
1791 &wsize,
1792 rwork,
1793 &info);
1794
1795 if (info != 0)
1796 {
1797 ERROR("argument passed to zgelss had an illegal value");
1798 ret = false;
1799 }
1800 else
1801 {
1802 x->resize(cols, bcols);
1803 if (rows > cols)
1804 {
1805 // We only need the first 'cols' rows of copyb
1806 int copyloc = 0;
1807 for (int j = 0; j < bcols; j++)
1808 {
1809 copyloc = 2 * j * rows;
1810 for (int i = 0; i < cols; i++)
1811 {
1812 double re = copyb[copyloc++];
1813 double im = copyb[copyloc++];
1814 x->ring().set_from_doubles(x->entry(i,j), re, im);
1815 }
1816 }
1817 }
1818 else
1819 {
1820 fill_from_lapack_array(copyb, *x);
1821 }
1822 }
1823
1824 delete[] workspace;
1825 delete[] sing;
1826 delete[] rwork;
1827
1828 return ret;
1829}
1830
1831// Local Variables:
1832// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
1833// indent-tabs-mode: nil
1834// End:
size_t numRows() const
Definition dmat.hpp:144
ElementType & entry(size_t row, size_t column)
Definition dmat.hpp:148
void resize(size_t new_nrows, size_t new_ncols)
Definition dmat.hpp:157
const ACoeffRing & ring() const
Definition dmat.hpp:143
size_t numColumns() const
Definition dmat.hpp:145
static bool least_squares_deficient(const DMatRRR *A, const DMatRRR *b, DMatRRR *x)
DMat< M2::ARingRR > DMatRR
Definition lapack.hpp:556
static bool SVD_divide_conquer(const DMatRRR *A, DMatRRR *Sigma, DMatRRR *U, DMatRRR *VT)
static bool eigenvectors_symmetric(const DMatRRR *A, DMatRRR *eigenvals, DMatRRR *eigenvecs)
static bool eigenvalues_hermitian(const DMatCCC *A, DMatRRR *eigenvals)
static bool SVD(const DMatRRR *A, DMatRRR *Sigma, DMatRRR *U, DMatRRR *VT)
static bool QR(const DMatRR *A, DMatRR *Q, DMatRR *R, bool return_QR)
Definition lapack.cpp:898
static bool eigenvalues_symmetric(const DMatRRR *A, DMatRRR *eigenvals)
static bool solve(const DMatRRR *A, const DMatRRR *b, DMatRRR *x)
static M2_arrayintOrNull LU(const DMatRRR *A, DMatRRR *L, DMatRRR *U)
static bool eigenvectors_hermitian(const DMatCCC *A, DMatRRR *eigenvals, DMatCCC *eigenvecs)
static bool least_squares(const DMatRRR *A, const DMatRRR *b, DMatRRR *x)
static bool eigenvectors(const DMatRRR *A, DMatCCC *eigenvals, DMatCCC *eigenvecs)
DMat< M2::ARingCC > DMatCC
Definition lapack.hpp:557
static bool eigenvalues(const DMatRRR *A, DMatCCC *eigenvals)
void set_from_doubles(ElementType &result, double re, double im) const
Definition aring-CC.hpp:455
Two SimpleARing-style coefficient adapters: CoefficientRingZZp and CoefficientRingR.
std::vector< double > make_lapack_array(const DMatRR &mat)
Definition lapack.cpp:20
void fill_from_lapack_array(const std::vector< double > &doubles, DMatRR &mat)
Definition lapack.cpp:45
std::vector< double > make_lapack_array(const DMatRR &mat)
Definition lapack.cpp:20
void fill_from_lapack_upper(const std::vector< double > &lapack_numbers, int numrows, int numcols, DMatRR &upper)
Definition lapack.cpp:74
void fill_from_lapack_array(const std::vector< double > &doubles, DMatRR &mat)
Definition lapack.cpp:45
void fill_lower_and_upper(const std::vector< double > &lapack_numbers, DMatRR &lower, DMatRR &upper)
Definition lapack.cpp:126
double * LapackDoubles
Definition lapack.cpp:14
int zgelss_(int *rows, int *cols, int *nhrs, double *A, int *ldA, double *b, int *ldb, double *Sigma, double *rcond, int *rank, double *work, int *lwork, double *rwork, int *info)
int dgesdd_(char *jobU, int *rows, int *cols, double *A, int *ldA, double *Sigma, double *U, int *ldU, double *VT, int *ldVT, double *work, int *lwork, int *iwork, int *info)
int zgeqrf_(int *m, int *n, double *A, int *lda, double *tau, double *work, int *lwork, int *info)
int zgesdd_(char *jobU, int *rows, int *cols, double *A, int *ldA, double *Sigma, double *U, int *ldU, double *VT, int *ldVT, double *w, int *lwork, double *rwork, int *iwork, int *info)
int zgesvd_(char *jobU, char *jobV, int *rows, int *cols, double *A, int *ldA, double *Sigma, double *U, int *ldU, double *VT, int *ldVT, double *w, int *lwork, double *rwork, int *info)
int zheev_(char *n, char *n2, int *size, double *M, int *lda, double *eig, double *w, int *wsize, double *rwork, int *info)
int zgetrf_(int *rows, int *cols, double *M, int *ld, int *ipiv, int *info)
int zgesv_(int *n, int *nrhs, double *a, int *lda, int *ipiv, double *b, int *ldb, int *info)
int zgels_(char *job, int *rows, int *cols, int *nhrs, double *A, int *ldA, double *b, int *ldb, double *work, int *lwork, int *info)
int dgeqrf_(int *m, int *n, double *A, int *lda, double *tau, double *work, int *lwork, int *info)
int zungqr_(int *m, int *n, int *k, double *A, int *lda, double *tau, double *work, int *lwork, int *info)
int dorgqr_(int *m, int *n, int *k, double *A, int *lda, double *tau, double *work, int *lwork, int *info)
int dsyev_(char *n, char *n2, int *size, double *M, int *lda, double *eig, double *work, int *wsize, int *info)
int dgeev_(char *n, char *n2, int *size, double *M, int *size1, double *E, double *E2, double *, int *, double *, int *, double *, int *, int *)
DMat< M2::ARingCC > DMatCC
Definition lapack.hpp:53
int dgesvd_(char *jobU, char *jobV, int *rows, int *cols, double *A, int *ldA, double *Sigma, double *U, int *ldU, double *VT, int *ldVT, double *work, int *lwork, int *info)
int zgeev_(char *n, char *n2, int *size, double *M, int *size1, double *E, double *l, int *lsize, double *r, int *rsize, double *w, int *wsize, double *rwork, int *info)
int dgelss_(int *rows, int *cols, int *nhrs, double *A, int *ldA, double *b, int *ldb, double *Sigma, double *rcond, int *rank, double *work, int *lwork, int *info)
void dgetrf_(const int *rows, const int *cols, double *A, const int *ld, int *ipiv, int *info)
int dgesv_(int *n, int *nrhs, double *a, int *lda, int *ipiv, double *b, int *ldb, int *info)
int dgels_(char *job, int *rows, int *cols, int *nhrs, double *A, int *ldA, double *b, int *ldb, double *work, int *lwork, int *info)
DMat< M2::ARingRR > DMatRR
Definition lapack.hpp:52
Engine bridge into LAPACK for RR / CC dense linear algebra.
const int ERROR
Definition m2-mem.cpp:55
VALGRIND_MAKE_MEM_DEFINED & result(result)
M2_arrayint M2_makearrayint(int n)
Definition m2-types.cpp:6
M2_arrayint M2_arrayintOrNull
Definition m2-types.h:99
Templated matrix arithmetic for DMat<R> / SMat<R> plus the MatrixWindow / SubMatrix view types.
doubling_stash * doubles
Definition mem.cpp:14
bool isZero(const DMat< RT > &A)
void swap(mpfr::mpreal &x, mpfr::mpreal &y)
Definition mpreal.h:3244
volatile int x
#define max(a, b)
Definition polyroots.cpp:52