complex_matrices.cc
Go to the documentation of this file.
1// LIC// ====================================================================
2// LIC// This file forms part of oomph-lib, the object-oriented,
3// LIC// multi-physics finite-element library, available
4// LIC// at http://www.oomph-lib.org.
5// LIC//
6// LIC// Copyright (C) 2006-2025 Matthias Heil and Andrew Hazel
7// LIC//
8// LIC// This library is free software; you can redistribute it and/or
9// LIC// modify it under the terms of the GNU Lesser General Public
10// LIC// License as published by the Free Software Foundation; either
11// LIC// version 2.1 of the License, or (at your option) any later version.
12// LIC//
13// LIC// This library is distributed in the hope that it will be useful,
14// LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// LIC// Lesser General Public License for more details.
17// LIC//
18// LIC// You should have received a copy of the GNU Lesser General Public
19// LIC// License along with this library; if not, write to the Free Software
20// LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21// LIC// 02110-1301 USA.
22// LIC//
23// LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24// LIC//
25// LIC//====================================================================
26#include "complex_matrices.h"
27#include <set>
28
29namespace oomph
30{
31 //============================================================================
32 /// Complete LU solve (overwrites RHS with solution). This is the
33 /// generic version which should not need to be over-written.
34 //============================================================================
35 void ComplexMatrixBase::solve(Vector<std::complex<double>>& rhs)
36 {
37#ifdef PARANOID
38 // Check Matrix is square
39 if (nrow() != ncol())
40 {
41 throw OomphLibError(
42 "This matrix is not square, the matrix MUST be square!",
45 }
46 // Check that size of rhs = nrow()
47 if (rhs.size() != nrow())
48 {
49 std::ostringstream error_message_stream;
50 error_message_stream << "The rhs vector is not the right size. It is "
51 << rhs.size() << ", it should be " << nrow()
52 << std::endl;
53
57 }
58#endif
59
60 // Call the LU decomposition
62
63 // Call the back substitution
64 lubksub(rhs);
65 }
66
67
68 //============================================================================
69 /// Complete LU solve (Nothing gets overwritten!). This generic
70 /// version should never need to be overwritten
71 //============================================================================
72 void ComplexMatrixBase::solve(const Vector<std::complex<double>>& rhs,
73 Vector<std::complex<double>>& soln)
74 {
75 // Set the solution vector equal to the rhs
76 // N.B. This won't work if we change to another vector format
77 soln = rhs;
78
79 // Overwrite the solution vector (rhs is unchanged)
80 solve(soln);
81 }
82
83
84 //=======================================================================
85 /// Delete the storage that has been allocated for the LU factors, if
86 /// the matrix data is not itself being overwritten.
87 //======================================================================
89 {
90 // Clean up the LU factor storage, if it has been allocated
91 // and it's not the same as the matrix storage
92 if ((!Overwrite_matrix_storage) && (LU_factors != 0))
93 {
94 // Delete the pointer to the LU factors
95 delete[] LU_factors;
96 // Null out the vector
97 LU_factors = 0;
98 }
99 }
100
101
102 //=======================================================================
103 /// Destructor clean up the LU factors that have been allocated
104 //======================================================================
106 {
107 // Delete the storage for the index vector
108 delete Index;
109
110 // Delete the pointer to the LU factors
111 delete[] LU_factors;
112
113 // Null out the vector
114 LU_factors = 0;
115 }
116
117 //============================================================================
118 /// LU decompose a matrix, over-writing it and recording the pivots
119 /// numbers in the Index vector.
120 /// Returns the sign of the determinant.
121 //============================================================================
123 {
124#ifdef PARANOID
125 // Check Matrix is square
126 if (N != M)
127 {
128 throw OomphLibError(
129 "This matrix is not square, the matrix MUST be square!",
132 }
133#endif
134
135 // Small constant
136 const double small_number = 1.0e-20;
137
138 // If the Index vector has not already been allocated,
139 // allocated storage for the index of permutations
140 if (Index == 0)
141 {
142 Index = new Vector<long>;
143 }
144
145 // Resize the index vector to the correct length
146 Index->resize(N);
147
148 // Vector scaling stores the implicit scaling of each row
149 Vector<double> scaling(N);
150
151 // Integer to store the sign that must multiply the determinant as
152 // a consequence of the row/column interchanges
153 int signature = 1;
154
155 // Loop over rows to get implicit scaling information
156 for (unsigned long i = 0; i < N; i++)
157 {
158 double big = 0.0;
159 for (unsigned long j = 0; j < M; j++)
160 {
161 double tmp = std::abs((*this)(i, j));
162 if (tmp > big) big = tmp;
163 }
164 if (big == 0.0)
165 {
166 throw OomphLibError(
168 }
169 // Save the scaling
170 scaling[i] = 1.0 / big;
171 }
172
173 // Firsly, we shall delete any previous LU storage.
174 // If the user calls this function twice without changing the matrix
175 // then it is their own inefficiency, not ours (this time).
177
178 // Now if we're saving the LU factors separately (the default).
180 {
181 // Allocate storage for the LU factors
182 // Assign space for the n rows
183 LU_factors = new std::complex<double>[N * M];
184
185 // Now we know that memory has been allocated, copy over
186 // the matrix values
187 for (unsigned long i = 0; i < (N * M); i++)
188 {
190 }
191 }
192 // Otherwise the pointer to the LU_factors is the same as the
193 // matrix data
194 else
195 {
197 }
198
199 // Loop over columns
200 for (unsigned long j = 0; j < M; j++)
201 {
202 // Initialise imax
203 unsigned long imax = 0;
204
205 for (unsigned long i = 0; i < j; i++)
206 {
207 std::complex<double> sum = LU_factors[M * i + j];
208 for (unsigned long k = 0; k < i; k++)
209 {
210 sum -= LU_factors[M * i + k] * LU_factors[M * k + j];
211 }
212 LU_factors[M * i + j] = sum;
213 }
214
215 // Initialise search for largest pivot element
216 double largest_entry = 0.0;
217 for (unsigned long i = j; i < N; i++)
218 {
219 std::complex<double> sum = LU_factors[M * i + j];
220 for (unsigned long k = 0; k < j; k++)
221 {
222 sum -= LU_factors[M * i + k] * LU_factors[M * k + j];
223 }
224 LU_factors[M * i + j] = sum;
225 // Set temporary
226 double tmp = scaling[i] * std::abs(sum);
227 if (tmp >= largest_entry)
228 {
230 imax = i;
231 }
232 }
233
234 // Test to see if we need to interchange rows
235 if (j != imax)
236 {
237 for (unsigned long k = 0; k < N; k++)
238 {
239 std::complex<double> tmp = LU_factors[M * imax + k];
240 LU_factors[M * imax + k] = LU_factors[M * j + k];
241 LU_factors[M * j + k] = tmp;
242 }
243 // Change the parity of signature
245 // Interchange scale factor
246 scaling[imax] = scaling[j];
247 }
248
249 // Set the index
250 (*Index)[j] = imax;
251 if (LU_factors[M * j + j] == 0.0)
252 {
253 LU_factors[M * j + j] = small_number;
254 }
255 // Divide by pivot element
256 if (j != N - 1)
257 {
258 std::complex<double> tmp = 1.0 / LU_factors[M * j + j];
259 for (unsigned long i = j + 1; i < N; i++)
260 {
261 LU_factors[M * i + j] *= tmp;
262 }
263 }
264
265 } // End of loop over columns
266
267
268 // Now multiply all the diagonal terms together to get the determinant
269 // Note that we need to use the mantissa, exponent formulation to
270 // avoid underflow errors. This is way more tedious in complex arithmetic.
271 std::complex<double> determinant_mantissa(1.0, 0.0);
272 std::complex<int> determinant_exponent(0, 0);
273 for (unsigned i = 0; i < N; i++)
274 {
275 // Get the next entry in mantissa exponent form
276 std::complex<double> entry;
277 int iexp_real = 0, iexp_imag = 0;
278 entry =
279 std::complex<double>(frexp(LU_factors[M * i + i].real(), &iexp_real),
280 frexp(LU_factors[M * i + i].imag(), &iexp_imag));
281
282 // Now calculate the four terms that contribute to the real
283 // and imaginary parts
284 // i.e. A + Bi * C + Di = AC - BD + i(AD + BC)
285 double temp_mantissa[4];
286 int temp_exp[4];
287
288 // Get the first contribution to the real part, AC
289 temp_mantissa[0] = determinant_mantissa.real() * entry.real();
291 // Get the second contribution to the real part, DB
292 temp_mantissa[1] = determinant_mantissa.imag() * entry.imag();
294
295 // Get the first contribution to the imaginary part, AD
296 temp_mantissa[2] = determinant_mantissa.real() * entry.imag();
298 // Get the second contribution to the imaginary part, BC
299 temp_mantissa[3] = determinant_mantissa.imag() * entry.real();
301
302 // Align the exponents in the two terms for each sum (real or imaginary)
303 // We always align up to the larger exponent
304 for (unsigned i = 0; i < 3; i += 2)
305 {
306 // If the first exponent is smaller, move it up
307 if (temp_exp[i] < temp_exp[i + 1])
308 {
309 // The smaller term
310 int lower = temp_exp[i];
311 // Loop over the difference in the exponents,
312 // scaling down the mantissa each time
313 int upper = temp_exp[i + 1];
314 for (int index = lower; index < upper; ++index)
315 {
316 temp_mantissa[i] /= 2.0;
317 ++temp_exp[i];
318 }
319 }
320 // Otherwise the second exponent is smaller
321 else
322 {
323 // The smaller term is the other
324 int lower = temp_exp[i + 1];
325 // Loop over the difference in the exponents,
326 // scaling down the mantissa each time
327 int upper = temp_exp[i];
328 for (int index = lower; index < upper; ++index)
329 {
330 temp_mantissa[i + 1] /= 2.0;
331 ++temp_exp[i + 1];
332 }
333 }
334 }
335
336 // Now combine the terms AC - BD
337 // and Combine the terms AD + BC
339 std::complex<double>(temp_mantissa[0] - temp_mantissa[1],
341 // The exponents will be the same, so pick one
342 determinant_exponent = std::complex<int>(temp_exp[0], temp_exp[2]);
343
344 // Finally normalise the result
346 std::complex<double>(frexp(determinant_mantissa.real(), &iexp_real),
348
351
352 determinant_exponent = std::complex<int>(temp_real, temp_imag);
353 }
354
355 // Integer to store the sign of the determinant
356 int sign = 0;
357 // Find the sign of the determinant (left or right half-plane)
358 if (std::abs(determinant_mantissa) > 0.0)
359 {
360 sign = 1;
361 }
362 if (std::abs(determinant_mantissa) < 0.0)
363 {
364 sign = -1;
365 }
366
367 // Multiply the sign by the signature
368 sign *= signature;
369
370 // Return the sign of the determinant
371 return sign;
372 }
373
374 //============================================================================
375 /// Back substitute an LU decomposed matrix.
376 //============================================================================
377 void DenseComplexMatrix::lubksub(Vector<std::complex<double>>& rhs)
378 {
379#ifdef PARANOID
380 // Check Matrix is square
381 if (N != M)
382 {
383 throw OomphLibError(
384 "This matrix is not square, the matrix MUST be square!",
387 }
388 // Check that size of rhs=nrow() and index=nrow() are correct!
389 if (rhs.size() != N)
390 {
391 std::ostringstream error_message_stream;
392 error_message_stream << "The rhs vector is not the right size. It is "
393 << rhs.size() << ", it should be " << N << std::endl;
394
398 }
399 if (Index == 0)
400 {
401 throw OomphLibError(
402 "Index vector has not been allocated. Have you called ludecompse()\n",
405 }
406 if (Index->size() != N)
407 {
408 std::ostringstream error_message_stream;
409 error_message_stream << "The Index vector is not the right size. It is "
410 << Index->size() << ", it should be " << N
411 << std::endl;
412
416 }
417#endif
418
419 unsigned long ii = 0;
420 for (unsigned i = 0; i < N; i++)
421 {
422 unsigned long ip = (*Index)[i];
423 std::complex<double> sum = rhs[ip];
424 rhs[ip] = rhs[i];
425
426 if (ii != 0)
427 {
428 for (unsigned long j = ii - 1; j < i; j++)
429 {
430 sum -= LU_factors[M * i + j] * rhs[j];
431 }
432 }
433 else if (sum != 0.0)
434 {
435 ii = i + 1;
436 }
437 rhs[i] = sum;
438 }
439
440 // Now do the back substitution
441 for (long i = long(N) - 1; i >= 0; i--)
442 {
443 std::complex<double> sum = rhs[i];
444 for (long j = i + 1; j < long(N); j++)
445 sum -= LU_factors[M * i + j] * rhs[j];
446 rhs[i] = sum / LU_factors[M * i + i];
447 }
448 }
449
450 //============================================================================
451 /// Find the residual of Ax=b, i.e. r=b-Ax
452 //============================================================================
453 void DenseComplexMatrix::residual(const Vector<std::complex<double>>& x,
454 const Vector<std::complex<double>>& rhs,
455 Vector<std::complex<double>>& residual)
456 {
457#ifdef PARANOID
458 // Check Matrix is square
459 if (N != M)
460 {
461 throw OomphLibError(
462 "This matrix is not square, the matrix MUST be square!",
465 }
466 // Check that size of rhs = nrow()
467 if (rhs.size() != N)
468 {
469 std::ostringstream error_message_stream;
470 error_message_stream << "The rhs vector is not the right size. It is "
471 << rhs.size() << ", it should be " << N << std::endl;
472
476 }
477 // Check that the size of x is correct
478 if (x.size() != N)
479 {
480 std::ostringstream error_message_stream;
481 error_message_stream << "The x vector is not the right size. It is "
482 << x.size() << ", it should be " << N << std::endl;
483
487 }
488#endif
489 // If size of residual is wrong, correct it!
490 if (residual.size() != N)
491 {
492 residual.resize(N);
493 }
494
495 // Multiply the matrix by the vector x in residual vector
496 for (unsigned long i = 0; i < N; i++)
497 {
498 residual[i] = rhs[i];
499 for (unsigned long j = 0; j < M; j++)
500 {
501 residual[i] -= Matrixdata[M * i + j] * x[j];
502 }
503 }
504 }
505
506
507 //============================================================================
508 /// Multiply the matrix by the vector x: soln=Ax
509 //============================================================================
510 void DenseComplexMatrix::multiply(const Vector<std::complex<double>>& x,
511 Vector<std::complex<double>>& soln)
512 {
513#ifdef PARANOID
514 // Check to see if x.size() = ncol().
515 if (x.size() != M)
516 {
517 std::ostringstream error_message_stream;
518 error_message_stream << "The x vector is not the right size. It is "
519 << x.size() << ", it should be " << M << std::endl;
520
524 }
525#endif
526
527 if (soln.size() != N)
528 {
529 // Resize and initialize the solution vector
530 soln.resize(N);
531 }
532
533 // Multiply the matrix A, by the vector x
534 for (unsigned long i = 0; i < N; i++)
535 {
536 soln[i] = 0.0;
537 for (unsigned long j = 0; j < M; j++)
538 {
539 soln[i] += Matrixdata[M * i + j] * x[j];
540 }
541 }
542 }
543
544 //===========================================================================
545 /// Function to multiply this matrix by the CRComplexMatrix matrix_in.
546 /// In a serial matrix, there are 3 methods available:
547 /// Method 1: First runs through this matrix and matrix_in to find the storage
548 /// requirements for result - arrays of the correct size are
549 /// then allocated before performing the calculation.
550 /// Minimises memory requirements but more costly.
551 /// Method 2: Grows storage for values and column indices of result 'on the
552 /// fly' using an array of maps. Faster but more memory
553 /// intensive.
554 /// Method 3: Grows storage for values and column indices of result 'on the
555 /// fly' using a vector of vectors. Not particularly impressive
556 /// on the platforms we tried...
557 /// Method 2 is employed by default. See also CRDoubleMatrix::multiply(...)
558 //=============================================================================
560 CRComplexMatrix& result) const
561 {
562 // NB n is number of rows!
563 const unsigned long n = this->nrow();
564 const unsigned long m = matrix_in.ncol();
565 unsigned long local_nnz = 0;
566
567 // pointers to arrays which store result
568 int* row_start = 0;
569 std::complex<double>* value = 0;
570 int* column_index = 0;
571
572 // get pointers to matrix_in
573 const int* matrix_in_row_start = matrix_in.row_start();
574 const int* matrix_in_column_index = matrix_in.column_index();
575 const std::complex<double>* matrix_in_value = matrix_in.value();
576
577 // get pointers to this matrix
578 const std::complex<double>* i_value = this->value();
579 const int* i_row_start = this->row_start();
580 const int* i_column_index = this->column_index();
581
582 // clock_t clock1 = clock();
583
584 // METHOD 1
585 // --------
588 {
589 // allocate storage for row starts
590 row_start = new int[n + 1];
591 row_start[0] = 0;
592
593 // a set to store number of non-zero columns in each row of result
594 std::set<unsigned> columns;
595
596 // run through rows of this matrix and matrix_in to find number of
597 // non-zero entries in each row of result
598 for (unsigned long i_row = 0; i_row < n; i_row++)
599 {
600 // run through non-zeros in i_row of this matrix
601 int i_row_end = i_row_start[i_row + 1];
603 i_non_zero++)
604 {
605 // find column index for non-zero
607
608 // run through corresponding row in matrix_in
613 {
614 // find column index for non-zero in matrix_in and store in
615 // columns
617 }
618 }
619 // update row_start
621
622 // wipe values in columns
623 columns.clear();
624 }
625
626 // set local_nnz
628
629 // allocate arrays for result
630 value = new std::complex<double>[local_nnz];
631 column_index = new int[local_nnz];
632
633 // set all values of column_index to -1
634 for (unsigned long i = 0; i < local_nnz; i++)
635 {
636 column_index[i] = -1;
637 }
638
639 // Calculate values for result - first run through rows of this matrix
640 for (unsigned long i_row = 0; i_row < n; i_row++)
641 {
642 // run through non-zeros in i_row
643 int i_row_end = i_row_start[i_row + 1];
645 i_non_zero++)
646 {
647 // find value of non-zero
648 std::complex<double> i_val = i_value[i_non_zero];
649
650 // find column associated with non-zero
652
653 // run through corresponding row in matrix_in
658 {
659 // find column index for non-zero in matrix_in
661
662 // find position in result to insert value
663 int row_end = row_start[i_row + 1];
664 for (int insert_position = row_start[i_row];
667 {
669 {
670 // error - have passed end of row without finding
671 // correct column
672 std::ostringstream error_message;
673 error_message << "Error inserting value in result";
674
675 throw OomphLibError(error_message.str(),
678 }
679 else if (column_index[insert_position] == -1)
680 {
681 // first entry for this column index
685 break;
686 }
687 else if (column_index[insert_position] == col)
688 {
689 // column index already exists - add value
692 break;
693 }
694 }
695 }
696 }
697 }
698 }
699 // METHOD 2
700 // --------
703 {
704 // generate array of maps to store values for result
705 std::map<int, std::complex<double>>* result_maps =
706 new std::map<int, std::complex<double>>[n];
707
708 // run through rows of this matrix
709 for (unsigned long i_row = 0; i_row < n; i_row++)
710 {
711 // run through non-zeros in i_row
712 int i_row_end = i_row_start[i_row + 1];
714 i_non_zero++)
715 {
716 // find value of non-zero
717 std::complex<double> i_val = i_value[i_non_zero];
718
719 // find column index associated with non-zero
721
722 // run through corresponding row in matrix_in
727 {
728 // find column index for non-zero in matrix_in
729 int col = matrix_in_column_index[matrix_in_index]; // This is the
730 // offending line
731 // insert value
733 }
734 }
735 }
736
737 // allocate row_start
738 row_start = new int[n + 1];
739
740 // copy across row starts
741 row_start[0] = 0;
742 for (unsigned long row = 0; row < n; row++)
743 {
744 int size = result_maps[row].size();
745 row_start[row + 1] = row_start[row] + size;
746 }
747
748 // set local_nnz
750
751 // allocate other arrays
752 value = new std::complex<double>[local_nnz];
753 column_index = new int[local_nnz];
754
755 // copy values and column indices
756 for (unsigned long row = 0; row < n; row++)
757 {
758 unsigned insert_position = row_start[row];
759 for (std::map<int, std::complex<double>>::iterator i =
761 i != result_maps[row].end();
762 i++)
763 {
765 value[insert_position] = i->second;
767 }
768 }
769 // tidy up memory
770 delete[] result_maps;
771 }
772 // METHOD 3
773 // --------
776 {
777 // vectors of vectors to store results
778 std::vector<std::vector<int>> result_cols(n);
779 std::vector<std::vector<std::complex<double>>> result_vals(n);
780
781 // run through the rows of this matrix
782 for (unsigned long i_row = 0; i_row < n; i_row++)
783 {
784 // run through non-zeros in i_row
785 int i_row_end = i_row_start[i_row + 1];
787 i_non_zero++)
788 {
789 // find value of non-zero
790 std::complex<double> i_val = i_value[i_non_zero];
791
792 // find column index associated with non-zero
794
795 // run through corresponding row in matrix_in
800 {
801 // find column index for non-zero in matrix_in
803
804 // insert value
805 int size = result_cols[i_row].size();
806 for (int i = 0; i <= size; i++)
807 {
808 if (i == size)
809 {
810 // first entry for this column
811 result_cols[i_row].push_back(col);
812 result_vals[i_row].push_back(i_val *
814 }
815 else if (col == result_cols[i_row][i])
816 {
817 // column already exists
818 result_vals[i_row][i] +=
820 break;
821 }
822 }
823 }
824 }
825 }
826
827 // allocate row_start
828 row_start = new int[n + 1];
829
830 // copy across row starts
831 row_start[0] = 0;
832 for (unsigned long row = 0; row < n; row++)
833 {
834 int size = result_cols[row].size();
835 row_start[row + 1] = row_start[row] + size;
836 }
837
838 // set local_nnz
840
841 // allocate other arrays
842 value = new std::complex<double>[local_nnz];
843 column_index = new int[local_nnz];
844
845 // copy across values and column indices
846 for (unsigned long row = 0; row < n; row++)
847 {
848 unsigned insert_position = row_start[row];
849 unsigned nnn = result_cols[row].size();
850 for (unsigned i = 0; i < nnn; i++)
851 {
855 }
856 }
857 }
858
859 // build
860 const unsigned long n_nz = this->nnz();
862 }
863
864 //=============================================================================
865 /// Element-wise addition of this matrix with matrix_in.
866 //=============================================================================
869 {
870#ifdef PARANOID
871 // Check if the dimensions of this matrix and matrix_in are the same.
872 const unsigned long i_nrow = this->nrow();
873 const unsigned long matrix_in_nrow = matrix_in.nrow();
874 if (i_nrow != matrix_in_nrow)
875 {
876 std::ostringstream error_message;
877 error_message << "matrix_in has a different number of rows than\n"
878 << "this matrix.\n";
879 throw OomphLibError(
881 }
882
883 const unsigned long i_ncol = this->ncol();
884 const unsigned long matrix_in_ncol = matrix_in.ncol();
885 if (i_ncol != matrix_in_ncol)
886 {
887 std::ostringstream error_message;
888 error_message << "matrix_in has a different number of columns than\n"
889 << "this matrix.\n";
890 throw OomphLibError(
892 }
893#endif
894
895 // To add the elements of two CRComplexMatrices, we need to know the union
896 // of the sparsity patterns. This is determined by the column indices. We
897 // add the column indices and values (entries) as a key-value pair in a map
898 // (per row). We then read these out into two column indices and values
899 // vector for the result matrix.
900
901 unsigned nrow_local = this->nrow();
905 res_row_start.reserve(nrow_local + 1);
906
907 // The row_start and column_indices
908 const int* i_column_indices = this->column_index();
909 const int* i_row_start = this->row_start();
910 const int* in_column_indices = matrix_in.column_index();
911 const int* in_row_start = matrix_in.row_start();
912
913 // Values from this matrix and matrix_in.
914 const std::complex<double>* i_values = this->value();
915 const std::complex<double>* in_values = matrix_in.value();
916
917 // The first entry in row_start is always zero.
918 res_row_start.push_back(0);
919
920 // Loop through the rows of both matrices and insert the column indices and
921 // values as a key-value pair.
922 for (unsigned row_i = 0; row_i < nrow_local; row_i++)
923 {
924 // Create the map for this row.
925 std::map<int, std::complex<double>> res_row_map;
926
927 // Insert the column and value pair for this matrix.
928 int i_row_end = i_row_start[row_i + 1];
929 for (int i = i_row_start[row_i]; i < i_row_end; i++)
930 {
932 }
933
934 // Insert the column and value pair for in matrix.
935 int in_row_end = in_row_start[row_i + 1];
936 for (int i = in_row_start[row_i]; i < in_row_end; i++)
937 {
939 }
940
941 // Fill in the row start
942 res_row_start.push_back(res_row_start.back() + res_row_map.size());
943
944 // Now insert the key into res_column_indices and value into res_values
945 for (std::map<int, std::complex<double>>::iterator it =
946 res_row_map.begin();
947 it != res_row_map.end();
948 ++it)
949 {
950 res_column_indices.push_back(it->first);
951 res_values.push_back(it->second);
952 }
953 }
954
955 // Finally build the result_matrix.
956 // Use the existing distribution.
960 this->ncol(),
961 this->nrow());
962 }
963
964 //=============================================================================
965 /// Element-wise addition of this matrix with matrix_in.
966 //=============================================================================
969 {
970#ifdef PARANOID
971 // Check if matrix_in is built.
972 if (!matrix_in.built())
973 {
974 std::ostringstream error_message;
975 error_message << "The matrix matrix_in is not built.\n"
976 << "Please build the matrix!\n";
977 throw OomphLibError(
979 }
980
981 // Check if the dimensions of this matrix and matrix_in are the same.
982 const unsigned long n_row = this->nrow();
983 const unsigned long matrix_in_nrow = matrix_in.nrow();
984 if (n_row != matrix_in_nrow)
985 {
986 std::ostringstream error_message;
987 error_message << "matrix_in has a different number of rows than\n"
988 << "this matrix.\n";
989 throw OomphLibError(
991 }
992
993 const unsigned long i_ncol = this->ncol();
994 const unsigned long matrix_in_ncol = matrix_in.ncol();
995 if (i_ncol != matrix_in_ncol)
996 {
997 std::ostringstream error_message;
998 error_message << "matrix_in has a different number of columns than\n"
999 << "this matrix.\n";
1000 throw OomphLibError(
1001 error_message.str(), OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
1002 }
1003#endif
1004
1005 // To add the elements of two CRMatrices, we need to know the union of
1006 // the sparsity patterns. This is determined by the column indices.
1007 // We add the column indices and values (entries) as a key-value pair in
1008 // a map (per row). We then read these out into two column indices and
1009 // values vector for the result matrix.
1010
1011 unsigned nrow_local = this->nrow();
1015 res_row_start.reserve(nrow_local + 1);
1016
1017 // The row_start and column_indices
1018 const int* i_column_indices = this->column_index();
1019 const int* i_row_start = this->row_start();
1020 const int* in_column_indices = matrix_in.column_index();
1021 const int* in_row_start = matrix_in.row_start();
1022
1023 // Values from this matrix and matrix_in.
1024 const std::complex<double>* i_values = this->value();
1025 const double* in_values = matrix_in.value();
1026
1027 // The first entry in row_start is always zero.
1028 res_row_start.push_back(0);
1029
1030 // Loop through the rows of both matrices and insert the column indices and
1031 // values as a key-value pair.
1032 for (unsigned row_i = 0; row_i < nrow_local; row_i++)
1033 {
1034 // Create the map for this row.
1035 std::map<int, std::complex<double>> res_row_map;
1036
1037 // Insert the column and value pair for this matrix.
1038 int i_row_end = i_row_start[row_i + 1];
1039 for (int i = i_row_start[row_i]; i < i_row_end; i++)
1040 {
1042 }
1043
1044 // Insert the column and value pair for in matrix.
1045 int in_row_end = in_row_start[row_i + 1];
1046 for (int i = in_row_start[row_i]; i < in_row_end; i++)
1047 {
1049 }
1050
1051 // Fill in the row start
1052 res_row_start.push_back(res_row_start.back() + res_row_map.size());
1053
1054 // Now insert the key into res_column_indices and value into res_values
1055 for (std::map<int, std::complex<double>>::iterator it =
1056 res_row_map.begin();
1057 it != res_row_map.end();
1058 ++it)
1059 {
1060 res_column_indices.push_back(it->first);
1061 res_values.push_back(it->second);
1062 }
1063 }
1064
1065 // Finally build the result_matrix.
1066 // Use the existing distribution.
1070 this->ncol(),
1071 this->nrow());
1072 }
1073
1074
1075 //=================================================================
1076 /// Multiply the transposed matrix by the vector x: soln=A^T x
1077 //=================================================================
1079 const Vector<std::complex<double>>& x, Vector<std::complex<double>>& soln)
1080 {
1081#ifdef PARANOID
1082 // Check to see x.size() = nrow()
1083 if (x.size() != N)
1084 {
1085 std::ostringstream error_message_stream;
1086 error_message_stream << "The x vector is not the right size. It is "
1087 << x.size() << ", it should be " << N << std::endl;
1088
1092 }
1093#endif
1094
1095 if (soln.size() != M)
1096 {
1097 // Resize and initialize the solution vector
1098 soln.resize(M);
1099 }
1100
1101 // Initialise the solution
1102 for (unsigned long i = 0; i < M; i++)
1103 {
1104 soln[i] = 0.0;
1105 }
1106
1107
1108 // Matrix vector product
1109 for (unsigned long i = 0; i < N; i++)
1110 {
1111 for (unsigned long j = 0; j < M; j++)
1112 {
1113 soln[j] += Matrixdata[N * i + j] * x[i];
1114 }
1115 }
1116 }
1117
1118 ////////////////////////////////////////////////////////////////////////
1119 ////////////////////////////////////////////////////////////////////////
1120 ////////////////////////////////////////////////////////////////////////
1121
1122
1123 //===================================================================
1124 // Interface to SuperLU wrapper
1125 //===================================================================
1126 extern "C"
1127 {
1129 int*,
1130 int*,
1131 int*,
1132 std::complex<double>*,
1133 int*,
1134 int*,
1135 std::complex<double>*,
1136 int*,
1137 int*,
1138 int*,
1139 void*,
1140 int*);
1141 }
1142
1143
1144 //===================================================================
1145 /// Perform LU decomposition. Return the sign of the determinant
1146 //===================================================================
1148 {
1149#ifdef PARANOID
1150 if (N != M)
1151 {
1152 std::ostringstream error_message_stream;
1153 error_message_stream << "Can only solve for quadratic matrices\n"
1154 << "N, M " << N << " " << M << std::endl;
1155
1159 }
1160#endif
1161
1162 // SuperLU expects compressed column format: Set flag for
1163 // transpose (0/1) = (false/true)
1164 int transpose = 0;
1165
1166 // Doc (0/1) = (false/true)
1167 int doc = 0;
1168 if (Doc_stats_during_solve) doc = 1;
1169
1170 // Cast to integers for stupid SuperLU
1171 int n_aux = (int)N;
1172 int nnz_aux = (int)Nnz;
1173
1174 // Integer to hold the sign of the determinant
1175 int sign = 0;
1176
1177 // Just do the lu decompose phase (i=1)
1178 int i = 1;
1180 &n_aux,
1181 &nnz_aux,
1182 0,
1183 Value,
1184 Row_index,
1186 0,
1187 &n_aux,
1188 &transpose,
1189 &doc,
1190 &F_factors,
1191 &Info);
1192
1193 // Return the sign of the determinant
1194 return sign;
1195 }
1196
1197
1198 //===================================================================
1199 /// Do the backsubstitution
1200 //===================================================================
1201 void CCComplexMatrix::lubksub(Vector<std::complex<double>>& rhs)
1202 {
1203#ifdef PARANOID
1204 if (N != rhs.size())
1205 {
1206 std::ostringstream error_message_stream;
1207 error_message_stream << "Size of RHS doesn't match matrix size\n"
1208 << "N, rhs.size() " << N << " " << rhs.size()
1209 << std::endl;
1210
1214 }
1215 if (N != M)
1216 {
1217 std::ostringstream error_message_stream;
1218 error_message_stream << "Can only solve for quadratic matrices\n"
1219 << "N, M " << N << " " << M << std::endl;
1220
1224 }
1225#endif
1226
1227 /// RHS vector
1228 std::complex<double>* b = new std::complex<double>[N];
1229
1230 // Copy across
1231 for (unsigned long i = 0; i < N; i++)
1232 {
1233 b[i] = rhs[i];
1234 }
1235
1236 // SuperLU expects compressed column format: Set flag for
1237 // transpose (0/1) = (false/true)
1238 int transpose = 0;
1239
1240 // Doc (0/1) = (false/true)
1241 int doc = 0;
1242 if (Doc_stats_during_solve) doc = 1;
1243
1244 // Number of RHSs
1245 int nrhs = 1;
1246
1247
1248 // Cast to integers for stupid SuperLU
1249 int n_aux = (int)N;
1250 int nnz_aux = (int)Nnz;
1251
1252 // SuperLU in three steps (lu decompose, back subst, cleanup)
1253 // Do the solve phase
1254 int i = 2;
1256 &n_aux,
1257 &nnz_aux,
1258 &nrhs,
1259 Value,
1260 Row_index,
1262 b,
1263 &n_aux,
1264 &transpose,
1265 &doc,
1266 &F_factors,
1267 &Info);
1268
1269 // Copy b into rhs vector
1270 for (unsigned long i = 0; i < N; i++)
1271 {
1272 rhs[i] = b[i];
1273 }
1274
1275 // Cleanup
1276 delete[] b;
1277 }
1278
1279
1280 //===================================================================
1281 /// Cleanup storage
1282 //===================================================================
1284 {
1285 // Only bother if we've done an LU solve
1286 if (F_factors != 0)
1287 {
1288 // SuperLU expects compressed column format: Set flag for
1289 // transpose (0/1) = (false/true)
1290 int transpose = 0;
1291
1292 // Doc (0/1) = (false/true)
1293 int doc = 0;
1294 if (Doc_stats_during_solve) doc = 1;
1295
1296
1297 // Cast to integers for stupid SuperLU
1298 int n_aux = (int)N;
1299 int nnz_aux = (int)Nnz;
1300
1301 // SuperLU in three steps (lu decompose, back subst, cleanup)
1302 // Flag to indicate which solve step to do (1, 2 or 3)
1303 int i = 3;
1305 &n_aux,
1306 &nnz_aux,
1307 0,
1308 Value,
1309 Row_index,
1311 0,
1312 &n_aux,
1313 &transpose,
1314 &doc,
1315 &F_factors,
1316 &Info);
1317 }
1318 }
1319
1320
1321 //===================================================================
1322 /// Work out residual vector r = b-Ax for candidate solution x
1323 //===================================================================
1324 void CCComplexMatrix::residual(const Vector<std::complex<double>>& x,
1325 const Vector<std::complex<double>>& rhs,
1326 Vector<std::complex<double>>& residual)
1327 {
1328#ifdef PARANOID
1329 // Check Matrix is square
1330 if (N != M)
1331 {
1332 throw OomphLibError(
1333 "This matrix is not square, the matrix MUST be square!",
1336 }
1337 // Check that size of rhs = nrow()
1338 if (rhs.size() != N)
1339 {
1340 std::ostringstream error_message_stream;
1341 error_message_stream << "The rhs vector is not the right size. It is "
1342 << rhs.size() << ", it should be " << N << std::endl;
1343
1347 }
1348 // Check that the size of x is correct
1349 if (x.size() != N)
1350 {
1351 std::ostringstream error_message_stream;
1352 error_message_stream << "The x vector is not the right size. It is "
1353 << x.size() << ", it should be " << N << std::endl;
1354
1358 }
1359#endif
1360
1361 const unsigned long r_n = residual.size();
1362 if (r_n != N)
1363 {
1364 residual.resize(N);
1365 }
1366
1367 // Need to do this in loop over rows
1368 for (unsigned i = 0; i < N; i++)
1369 {
1370 residual[i] = rhs[i];
1371 }
1372 // Now loop over columns
1373 for (unsigned long j = 0; j < N; j++)
1374 {
1375 int column_end = Column_start[j + 1];
1376 for (long k = Column_start[j]; k < column_end; k++)
1377 {
1378 unsigned long i = Row_index[k];
1379 std::complex<double> a_ij = Value[k];
1380 residual[i] -= a_ij * x[j];
1381 }
1382 }
1383 }
1384
1385 //===================================================================
1386 /// Multiply the matrix by the vector x
1387 //===================================================================
1388 void CCComplexMatrix::multiply(const Vector<std::complex<double>>& x,
1389 Vector<std::complex<double>>& soln)
1390 {
1391#ifdef PARANOID
1392 // Check to see if x.size() = ncol()
1393 if (x.size() != M)
1394 {
1395 std::ostringstream error_message_stream;
1396 error_message_stream << "The x vector is not the right size. It is "
1397 << x.size() << ", it should be " << M << std::endl;
1398
1402 }
1403#endif
1404
1405 if (soln.size() != N)
1406 {
1407 // Resize and initialize the solution vector
1408 soln.resize(N);
1409 }
1410 for (unsigned i = 0; i < N; i++)
1411 {
1412 soln[i] = 0.0;
1413 }
1414
1415 for (unsigned long j = 0; j < N; j++)
1416 {
1417 int column_end = Column_start[j + 1];
1418 for (long k = Column_start[j]; k < column_end; k++)
1419 {
1420 unsigned long i = Row_index[k];
1421 std::complex<double> a_ij = Value[k];
1422 soln[i] += a_ij * x[j];
1423 }
1424 }
1425 }
1426
1427
1428 //=================================================================
1429 /// Multiply the transposed matrix by the vector x: soln=A^T x
1430 //=================================================================
1432 const Vector<std::complex<double>>& x, Vector<std::complex<double>>& soln)
1433 {
1434#ifdef PARANOID
1435 // Check to see x.size() = nrow()
1436 if (x.size() != N)
1437 {
1438 std::ostringstream error_message_stream;
1439 error_message_stream << "The x vector is not the right size. It is "
1440 << x.size() << ", it should be " << N << std::endl;
1441
1445 }
1446#endif
1447
1448 if (soln.size() != M)
1449 {
1450 // Resize and initialize the solution vector
1451 soln.resize(M);
1452 }
1453
1454 // Initialise the solution
1455 for (unsigned long i = 0; i < M; i++)
1456 {
1457 soln[i] = 0.0;
1458 }
1459
1460 // Matrix vector product
1461 for (unsigned long i = 0; i < N; i++)
1462 {
1463 int column_end = Column_start[i + 1];
1464 for (long k = Column_start[i]; k < column_end; k++)
1465 {
1466 unsigned long j = Row_index[k];
1467 std::complex<double> a_ij = Value[k];
1468 soln[j] += a_ij * x[i];
1469 }
1470 }
1471 }
1472
1473
1474 ////////////////////////////////////////////////////////////////////////
1475 ////////////////////////////////////////////////////////////////////////
1476 ////////////////////////////////////////////////////////////////////////
1477
1478
1479 //===================================================================
1480 /// Do LU decomposition and return sign of determinant
1481 //===================================================================
1483 {
1484#ifdef PARANOID
1485 if (N != M)
1486 {
1487 std::ostringstream error_message_stream;
1488 error_message_stream << "Can only solve for quadratic matrices\n"
1489 << "N, M " << N << " " << M << std::endl;
1490
1494 }
1495#endif
1496
1497 // SuperLU expects compressed column format: Set flag for
1498 // transpose (0/1) = (false/true)
1499 int transpose = 1;
1500
1501 // Doc (0/1) = (false/true)
1502 int doc = 0;
1503 if (Doc_stats_during_solve) doc = 1;
1504
1505 // Copies so that const-ness is maintained
1506 int n_aux = int(N);
1507 int nnz_aux = int(Nnz);
1508
1509 // Integer to hold the sign of the determinant
1510 int sign = 0;
1511
1512 // Just do the lu decompose phase (i=1)
1513 int i = 1;
1515 &n_aux,
1516 &nnz_aux,
1517 0,
1518 Value,
1520 Row_start,
1521 0,
1522 &n_aux,
1523 &transpose,
1524 &doc,
1525 &F_factors,
1526 &Info);
1527 // Return sign of determinant
1528 return sign;
1529 }
1530
1531
1532 //===================================================================
1533 /// Do back-substitution
1534 //===================================================================
1535 void CRComplexMatrix::lubksub(Vector<std::complex<double>>& rhs)
1536 {
1537#ifdef PARANOID
1538 if (N != rhs.size())
1539 {
1540 std::ostringstream error_message_stream;
1541 error_message_stream << "Size of RHS doesn't match matrix size\n"
1542 << "N, rhs.size() " << N << " " << rhs.size()
1543 << std::endl;
1544
1548 }
1549 if (N != M)
1550 {
1551 std::ostringstream error_message_stream;
1552 error_message_stream << "Can only solve for quadratic matrices\n"
1553 << "N, M " << N << " " << M << std::endl;
1554
1558 }
1559#endif
1560
1561 /// RHS vector
1562 std::complex<double>* b = new std::complex<double>[N];
1563
1564 // Copy across
1565 for (unsigned long i = 0; i < N; i++)
1566 {
1567 b[i] = rhs[i];
1568 }
1569
1570 // SuperLU expects compressed column format: Set flag for
1571 // transpose (0/1) = (false/true)
1572 int transpose = 1;
1573
1574 // Doc (0/1) = (false/true)
1575 int doc = 0;
1576 if (Doc_stats_during_solve) doc = 1;
1577
1578 // Number of RHSs
1579 int nrhs = 1;
1580
1581 // Copies so that const-ness is maintained
1582 int n_aux = int(N);
1583 int nnz_aux = int(Nnz);
1584
1585 // SuperLU in three steps (lu decompose, back subst, cleanup)
1586 // Do the solve phase
1587 int i = 2;
1589 &n_aux,
1590 &nnz_aux,
1591 &nrhs,
1592 Value,
1594 Row_start,
1595 b,
1596 &n_aux,
1597 &transpose,
1598 &doc,
1599 &F_factors,
1600 &Info);
1601
1602 // Copy b into rhs vector
1603 for (unsigned long i = 0; i < N; i++)
1604 {
1605 rhs[i] = b[i];
1606 }
1607
1608 // Cleanup
1609 delete[] b;
1610 }
1611
1612
1613 //===================================================================
1614 /// Cleanup memory
1615 //===================================================================
1617 {
1618 // Only bother if we've done an LU solve
1619 if (F_factors != 0)
1620 {
1621 // SuperLU expects compressed column format: Set flag for
1622 // transpose (0/1) = (false/true)
1623 int transpose = 1;
1624
1625 // Doc (0/1) = (false/true)
1626 int doc = 0;
1627 if (Doc_stats_during_solve) doc = 1;
1628
1629 // Copies so that const-ness is maintained
1630 int n_aux = int(N);
1631 int nnz_aux = int(Nnz);
1632
1633 // SuperLU in three steps (lu decompose, back subst, cleanup)
1634 // Flag to indicate which solve step to do (1, 2 or 3)
1635 int i = 3;
1637 &n_aux,
1638 &nnz_aux,
1639 0,
1640 Value,
1642 Row_start,
1643 0,
1644 &n_aux,
1645 &transpose,
1646 &doc,
1647 &F_factors,
1648 &Info);
1649 }
1650 }
1651
1652
1653 //=================================================================
1654 /// Find the residulal to x of Ax=b, ie r=b-Ax
1655 //=================================================================
1656 void CRComplexMatrix::residual(const Vector<std::complex<double>>& x,
1657 const Vector<std::complex<double>>& rhs,
1658 Vector<std::complex<double>>& residual)
1659 {
1660#ifdef PARANOID
1661 // Check that size of rhs = nrow()
1662 if (rhs.size() != N)
1663 {
1664 std::ostringstream error_message_stream;
1665 error_message_stream << "The rhs vector is not the right size. It is "
1666 << rhs.size() << ", it should be " << N << std::endl;
1667
1671 }
1672 // Check that the size of x is correct
1673 if (x.size() != M)
1674 {
1675 std::ostringstream error_message_stream;
1676 error_message_stream << "The x vector is not the right size. It is "
1677 << x.size() << ", it should be " << M << std::endl;
1678
1682 }
1683#endif
1684
1685 if (residual.size() != N)
1686 {
1687 residual.resize(N);
1688 }
1689
1690 for (unsigned long i = 0; i < N; i++)
1691 {
1692 residual[i] = rhs[i];
1693 int row_end = Row_start[i + 1];
1694 for (long k = Row_start[i]; k < row_end; k++)
1695 {
1696 unsigned long j = Column_index[k];
1697 std::complex<double> a_ij = Value[k];
1698 residual[i] -= a_ij * x[j];
1699 }
1700 }
1701 }
1702
1703 //=================================================================
1704 /// Multiply the matrix by the vector x
1705 //=================================================================
1706 void CRComplexMatrix::multiply(const Vector<std::complex<double>>& x,
1707 Vector<std::complex<double>>& soln)
1708 {
1709#ifdef PARANOID
1710 // Check to see x.size() = ncol()
1711 if (x.size() != M)
1712 {
1713 std::ostringstream error_message_stream;
1714 error_message_stream << "The x vector is not the right size. It is "
1715 << x.size() << ", it should be " << M << std::endl;
1716
1720 }
1721#endif
1722
1723 if (soln.size() != N)
1724 {
1725 // Resize and initialize the solution vector
1726 soln.resize(N);
1727 }
1728 for (unsigned long i = 0; i < N; i++)
1729 {
1730 soln[i] = 0.0;
1731 int row_end = Row_start[i + 1];
1732 for (long k = Row_start[i]; k < row_end; k++)
1733 {
1734 unsigned long j = Column_index[k];
1735 std::complex<double> a_ij = Value[k];
1736 soln[i] += a_ij * x[j];
1737 }
1738 }
1739 }
1740
1741
1742 //=================================================================
1743 /// Multiply the transposed matrix by the vector x: soln=A^T x
1744 //=================================================================
1746 const Vector<std::complex<double>>& x, Vector<std::complex<double>>& soln)
1747 {
1748#ifdef PARANOID
1749 // Check to see x.size() = nrow()
1750 if (x.size() != N)
1751 {
1752 std::ostringstream error_message_stream;
1753 error_message_stream << "The x vector is not the right size. It is "
1754 << x.size() << ", it should be " << N << std::endl;
1755
1759 }
1760#endif
1761
1762 if (soln.size() != M)
1763 {
1764 // Resize and initialize the solution vector
1765 soln.resize(M);
1766 }
1767
1768 // Initialise the solution
1769 for (unsigned long i = 0; i < M; i++)
1770 {
1771 soln[i] = 0.0;
1772 }
1773
1774 // Matrix vector product
1775 for (unsigned long i = 0; i < N; i++)
1776 {
1777 int row_end = Row_start[i + 1];
1778 for (long k = Row_start[i]; k < row_end; k++)
1779 {
1780 unsigned long j = Column_index[k];
1781 std::complex<double> a_ij = Value[k];
1782 soln[j] += a_ij * x[i];
1783 }
1784 }
1785 }
1786} // namespace oomph
cstr elem_len * i
Definition cfortran.h:603
int Info
Info flag for the SuperLU solver.
void multiply(const Vector< std::complex< double > > &x, Vector< std::complex< double > > &soln)
Multiply the matrix by the vector x: soln=Ax.
int ludecompose()
LU decomposition using SuperLU.
void multiply_transpose(const Vector< std::complex< double > > &x, Vector< std::complex< double > > &soln)
Multiply the transposed matrix by the vector x: soln=A^T x.
void clean_up_memory()
LU clean up (perhaps this should happen in the destructor)
bool Doc_stats_during_solve
Flag to indicate if stats are to be displayed during solution of linear system with SuperLU.
void * F_factors
Storage for the LU factors as required by SuperLU.
void lubksub(Vector< std::complex< double > > &rhs)
LU back solve for given RHS.
void residual(const Vector< std::complex< double > > &x, const Vector< std::complex< double > > &b, Vector< std::complex< double > > &residual)
Find the residulal to x of Ax=b, ie r=b-Ax.
int * Column_start
Start index for column.
Definition matrices.h:2779
A class for compressed row matrices.
unsigned long nrow() const
Return the number of rows of the matrix.
void * F_factors
Storage for the LU factors as required by SuperLU.
unsigned long ncol() const
Return the number of columns of the matrix.
bool Doc_stats_during_solve
Flag to indicate if stats are to be displayed during solution of linear system with SuperLU.
SerialMatrixMultiplyMethod Serial_matrix_matrix_multiply_method
A switch variable for selecting the matrix multiply method for serial (non-parallel) runs....
void multiply_transpose(const Vector< std::complex< double > > &x, Vector< std::complex< double > > &soln)
Multiply the transposed matrix by the vector x: soln=A^T x.
void multiply(const Vector< std::complex< double > > &x, Vector< std::complex< double > > &soln)
Multiply the matrix by the vector x: soln=Ax.
void add(const CRDoubleMatrix &matrix_in, CRComplexMatrix &result_matrix) const
Element-wise addition of this matrix with matrix_in.
int ludecompose()
LU decomposition using SuperLU.
void lubksub(Vector< std::complex< double > > &rhs)
LU back solve for given RHS.
int Info
Info flag for the SuperLU solver.
void residual(const Vector< std::complex< double > > &x, const Vector< std::complex< double > > &b, Vector< std::complex< double > > &residual)
Find the residual to x of Ax=b, i.e. r=b-Ax.
void clean_up_memory()
LU clean up (perhaps this should happen in the destructor)
A class for compressed row matrices. This is a distributable object.
Definition matrices.h:888
int * column_index()
Access to C-style column index array.
Definition matrices.h:797
int * Row_start
Start index for row.
Definition matrices.h:873
int * row_start()
Access to C-style row_start array.
Definition matrices.h:785
void build_without_copy(T *value, int *column_index, int *row_start, const unsigned long &nnz, const unsigned long &n, const unsigned long &m)
Function to build matrix from pointers to arrays which hold the row starts, column indices and non-ze...
Definition matrices.h:3354
virtual int ludecompose()
LU decomposition of the matrix using the appropriate linear solver. Return the sign of the determinan...
virtual void solve(Vector< std::complex< double > > &rhs)
Complete LU solve (replaces matrix by its LU decomposition and overwrites RHS with solution)....
virtual unsigned long ncol() const =0
Return the number of columns of the matrix.
virtual void lubksub(Vector< std::complex< double > > &rhs)
LU backsubstitue a previously LU-decomposed matrix; The passed rhs will be over-written with the solu...
virtual unsigned long nrow() const =0
Return the number of rows of the matrix.
bool Overwrite_matrix_storage
Boolean flag used to decided whether the LU decomposition is stored separately, or not.
virtual ~DenseComplexMatrix()
Destructor, delete the storage for Index vector and LU storage (if any)
Vector< long > * Index
Pointer to storage for the index of permutations in the LU solve.
void residual(const Vector< std::complex< double > > &x, const Vector< std::complex< double > > &rhs, Vector< std::complex< double > > &residual)
Find the residual of Ax=b, ie r=b-Ax for the "solution" x.
int ludecompose()
Overload the LU decomposition. For this storage scheme the matrix storage will be over-writeen by its...
void multiply_transpose(const Vector< std::complex< double > > &x, Vector< std::complex< double > > &soln)
Multiply the transposed matrix by the vector x: soln=A^T x.
void delete_lu_factors()
Function that deletes the storage for the LU_factors, if it is not the same as the matrix storage.
void lubksub(Vector< std::complex< double > > &rhs)
Overload the LU back substitution. Note that the rhs will be overwritten with the solution vector.
std::complex< double > * LU_factors
Pointer to storage for the LU decomposition.
void multiply(const Vector< std::complex< double > > &x, Vector< std::complex< double > > &soln)
Multiply the matrix by the vector x: soln=Ax.
unsigned long N
Number of rows.
Definition matrices.h:392
std::complex< double > & entry(const unsigned long &i, const unsigned long &j)
The access function that will be called by the read-write round-bracket operator.
Definition matrices.h:447
std::complex< double > * Matrixdata
Internal representation of matrix as a pointer to data.
Definition matrices.h:389
unsigned long M
Number of columns.
Definition matrices.h:395
double size() const
Calculate the size of the element (length, area, volume,...) in Eulerian computational coordinates....
Definition elements.cc:4320
An OomphLibError object which should be thrown when an run-time error is encountered....
unsigned long Nnz
Number of non-zero values (i.e. size of Value array)
Definition matrices.h:574
T * Value
Internal representation of the matrix values, a pointer.
Definition matrices.h:565
T * value()
Access to C-style value array.
Definition matrices.h:616
unsigned long nnz() const
Return the number of nonzero entries.
Definition matrices.h:640
unsigned long N
Number of rows.
Definition matrices.h:568
unsigned long M
Number of columns.
Definition matrices.h:571
TAdvectionDiffusionReactionElement<NREAGENT,DIM,NNODE_1D> elements are isoparametric triangular DIM-d...
A slight extension to the standard template vector class so that we can include "graceful" array rang...
Definition Vector.h:58
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
std::string lower(const std::string &text)
Definition fpdiff.cc:123
int superlu_complex(int *, int *, int *, int *, std::complex< double > *, int *, int *, std::complex< double > *, int *, int *, int *, void *, int *)