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// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 #include "complex_matrices.h"
31 
32 namespace oomph
33 {
34 
35 
36 //============================================================================
37 /// Complete LU solve (overwrites RHS with solution). This is the
38 /// generic version which should not need to be over-written.
39 //============================================================================
40  void ComplexMatrixBase::solve(Vector<std::complex<double> > &rhs)
41 {
42 #ifdef PARANOID
43  // Check Matrix is square
44  if (nrow()!=ncol())
45  {
46  throw OomphLibError(
47  "This matrix is not square, the matrix MUST be square!",
48  OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
49  }
50  // Check that size of rhs = nrow()
51  if (rhs.size()!=nrow())
52  {
53  std::ostringstream error_message_stream;
54  error_message_stream
55  << "The rhs vector is not the right size. It is " << rhs.size()
56  << ", it should be " << nrow() << std::endl;
57 
58  throw OomphLibError(error_message_stream.str(),
59 OOMPH_CURRENT_FUNCTION,
60  OOMPH_EXCEPTION_LOCATION);
61  }
62 #endif
63 
64  //Call the LU decomposition
65  ludecompose();
66 
67  //Call the back substitution
68  lubksub(rhs);
69 }
70 
71 
72 //============================================================================
73 /// Complete LU solve (Nothing gets overwritten!). This generic
74 /// version should never need to be overwritten
75 //============================================================================
76 void ComplexMatrixBase::solve(const Vector<std::complex<double> >&rhs,
77  Vector<std::complex<double> > &soln)
78 {
79  //Set the solution vector equal to the rhs
80  //N.B. This won't work if we change to another vector format
81  soln = rhs;
82 
83  //Overwrite the solution vector (rhs is unchanged)
84  solve(soln);
85 }
86 
87 std::complex<double> DiagonalComplexMatrix::operator()(const unsigned long &i,
88  const unsigned long &j) const
89 {
90  if (i==j)
91  {
92  return Matrixdata[i];
93  }
94  else
95  {
96  return std::complex<double>(0.0, 0.0);
97  }
98 }
99 
100 std::complex<double>& DiagonalComplexMatrix::operator()(const unsigned long &i,
101  const unsigned long &j)
102 {
103  if (i==j)
104  {
105  return Matrixdata[i];
106  }
107  else
108  {
109  throw OomphLibError(
110  "You can only write the diagonal components of a diagonal matrix",
111  OOMPH_CURRENT_FUNCTION,
112  OOMPH_EXCEPTION_LOCATION);
113  }
114 }
115 
116 void DiagonalComplexMatrix::resize(const unsigned& N, const unsigned& M)
117 {
118 #ifdef PARANOID
119  if (M != N)
120  {
121  throw OomphLibError("Diagonal matrices must be square",
122  OOMPH_CURRENT_FUNCTION,
123  OOMPH_EXCEPTION_LOCATION);
124  }
125 #endif
126  Matrixdata.resize(N);
127 }
128 
129 void DiagonalComplexMatrix::resize(const unsigned& N, const unsigned& M,
130  std::complex<double> z)
131 {
132 #ifdef PARANOID
133  if (M != N)
134  {
135  throw OomphLibError("Diagonal matrices must be square",
136  OOMPH_CURRENT_FUNCTION,
137  OOMPH_EXCEPTION_LOCATION);
138  }
139 #endif
140  Matrixdata.resize(N, z);
141 }
142 
143 
144 void DiagonalComplexMatrix::multiply(const Vector<std::complex<double> > &x,
145  Vector<std::complex<double> > &result)
146 {
147  const unsigned N = ncol();
148 #ifdef PARANOID
149  if (x.size() != N)
150  {
151  std::ostringstream error_message_stream;
152  error_message_stream
153  << "The x vector is not the right size. It is " << x.size()
154  << ", it should be " << N << std::endl;
155 
156  throw OomphLibError(error_message_stream.str(),
157  OOMPH_CURRENT_FUNCTION,
158  OOMPH_EXCEPTION_LOCATION);
159  }
160 #endif
161 
162  for (unsigned i=0; i<N; i++)
163  {
164  result[i] = Matrixdata[i]*x[i];
165  }
166 }
167 
168 //=======================================================================
169 /// Delete the storage that has been allocated for the LU factors, if
170 /// the matrix data is not itself being overwritten.
171 //======================================================================
173 {
174 
175  //Clean up the LU factor storage, if it has been allocated
176  //and it's not the same as the matrix storage
177  if((!Overwrite_matrix_storage) && (LU_factors!=0))
178  {
179  //Delete the pointer to the LU factors
180  delete[] LU_factors;
181  //Null out the vector
182  LU_factors = 0;
183  }
184 }
185 
186 
187 //=======================================================================
188 /// Destructor clean up the LU factors that have been allocated
189 //======================================================================
191 {
192  //Delete the storage for the index vector
193  delete Index;
194 
195  //Delete the pointer to the LU factors
196  delete[] LU_factors;
197 
198  //Null out the vector
199  LU_factors = 0;
200 
201 }
202 
203 //============================================================================
204 /// LU decompose a matrix, over-writing it and recording the pivots
205 /// numbers in the Index vector.
206 /// Returns the sign of the determinant.
207 //============================================================================
209 {
210 #ifdef PARANOID
211  // Check Matrix is square
212  if (N!=M)
213  {
214  throw OomphLibError(
215  "This matrix is not square, the matrix MUST be square!",
216  OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
217  }
218 #endif
219 
220  //Small constant
221  const double small_number=1.0e-20;
222 
223  //If the Index vector has not already been allocated,
224  //allocated storage for the index of permutations
225  if (Index == 0) { Index = new Vector<long>; }
226 
227  //Resize the index vector to the correct length
228  Index->resize(N);
229 
230  //Vector scaling stores the implicit scaling of each row
231  Vector<double> scaling(N);
232 
233  //Integer to store the sign that must multiply the determinant as
234  //a consequence of the row/column interchanges
235  int signature = 1;
236 
237  //Loop over rows to get implicit scaling information
238  for(unsigned long i=0;i<N;i++)
239  {
240  double big=0.0;
241  for(unsigned long j=0;j<M;j++)
242  {
243  double tmp = std::abs((*this)(i,j));
244  if(tmp > big) big = tmp;
245  }
246  if(big==0.0)
247  {
248  throw OomphLibError("Singular Matrix",
249  OOMPH_CURRENT_FUNCTION,
250  OOMPH_EXCEPTION_LOCATION);
251  }
252  //Save the scaling
253  scaling[i] = 1.0/big;
254  }
255 
256  //Firsly, we shall delete any previous LU storage.
257  //If the user calls this function twice without changing the matrix
258  //then it is their own inefficiency, not ours (this time).
259  delete_lu_factors();
260 
261  //Now if we're saving the LU factors separately (the default).
262  if(!Overwrite_matrix_storage)
263  {
264  //Allocate storage for the LU factors
265  //Assign space for the n rows
266  LU_factors = new std::complex<double>[N*M];
267 
268  //Now we know that memory has been allocated, copy over
269  //the matrix values
270  for(unsigned long i=0;i<(N*M);i++)
271  {
272  LU_factors[i] = Matrixdata[i];
273  }
274  }
275  //Otherwise the pointer to the LU_factors is the same as the
276  //matrix data
277  else
278  {
279  LU_factors = Matrixdata;
280  }
281 
282  //Loop over columns
283  for(unsigned long j=0;j<M;j++)
284  {
285  //Initialise imax
286  unsigned long imax=0;
287 
288  for(unsigned long i=0;i<j;i++)
289  {
290  std::complex<double> sum = LU_factors[M*i+j];
291  for(unsigned long k=0;k<i;k++)
292  {
293  sum -= LU_factors[M*i+k]*LU_factors[M*k+j];
294  }
295  LU_factors[M*i+j] = sum;
296  }
297 
298  //Initialise search for largest pivot element
299  double largest_entry=0.0;
300  for(unsigned long i=j;i<N;i++)
301  {
302  std::complex<double> sum = LU_factors[M*i+j];
303  for(unsigned long k=0;k<j;k++)
304  {
305  sum -= LU_factors[M*i+k]*LU_factors[M*k+j];
306  }
307  LU_factors[M*i+j] = sum;
308  //Set temporary
309  double tmp = scaling[i]*std::abs(sum);
310  if(tmp >= largest_entry)
311  {
312  largest_entry = tmp;
313  imax = i;
314  }
315  }
316 
317  //Test to see if we need to interchange rows
318  if(j != imax)
319  {
320  for(unsigned long k=0;k<N;k++)
321  {
322  std::complex<double> tmp = LU_factors[M*imax+k];
323  LU_factors[M*imax+k] = LU_factors[M*j+k];
324  LU_factors[M*j+k] = tmp;
325  }
326  //Change the parity of signature
327  signature = -signature;
328  //Interchange scale factor
329  scaling[imax] = scaling[j];
330  }
331 
332  //Set the index
333  (*Index)[j] = imax;
334  if(LU_factors[M*j+j] == 0.0)
335  {
336  LU_factors[M*j+j] = small_number;
337  }
338  //Divide by pivot element
339  if(j != N-1)
340  {
341  std::complex<double> tmp = 1.0/LU_factors[M*j+j];
342  for(unsigned long i=j+1;i<N;i++)
343  {
344  LU_factors[M*i+j] *= tmp;
345  }
346  }
347 
348  } //End of loop over columns
349 
350 
351  //Now multiply all the diagonal terms together to get the determinant
352  //Note that we need to use the mantissa, exponent formulation to
353  //avoid underflow errors. This is way more tedious in complex arithmetic.
354  std::complex<double> determinant_mantissa(1.0,0.0);
355  std::complex<int> determinant_exponent(0,0);
356  for(unsigned i=0; i<N; i++)
357  {
358  //Get the next entry in mantissa exponent form
359  std::complex<double> entry;
360  int iexp_real=0, iexp_imag=0;
361  entry = std::complex<double>(frexp(LU_factors[M*i+i].real(),&iexp_real),
362  frexp(LU_factors[M*i+i].imag(),&iexp_imag));
363 
364  //Now calculate the four terms that contribute to the real
365  //and imaginary parts
366  //i.e. A + Bi * C + Di = AC - BD + i(AD + BC)
367  double temp_mantissa[4]; int temp_exp[4];
368 
369  //Get the first contribution to the real part, AC
370  temp_mantissa[0] = determinant_mantissa.real()*entry.real();
371  temp_exp[0] = determinant_exponent.real() + iexp_real;
372  //Get the second contribution to the real part, DB
373  temp_mantissa[1] = determinant_mantissa.imag()*entry.imag();
374  temp_exp[1] = determinant_exponent.imag() + iexp_imag;
375 
376  //Get the first contribution to the imaginary part, AD
377  temp_mantissa[2] = determinant_mantissa.real()*entry.imag();
378  temp_exp[2] = determinant_exponent.real() + iexp_imag;
379  //Get the second contribution to the imaginary part, BC
380  temp_mantissa[3] = determinant_mantissa.imag()*entry.real();
381  temp_exp[3] = determinant_exponent.imag() + iexp_real;
382 
383  //Align the exponents in the two terms for each sum (real or imaginary)
384  //We always align up to the larger exponent
385  for(unsigned i=0;i<3;i+=2)
386  {
387  //If the first exponent is smaller, move it up
388  if(temp_exp[i] < temp_exp[i+1])
389  {
390  //The smaller term
391  int lower = temp_exp[i];
392  //Loop over the difference in the exponents,
393  //scaling down the mantissa each time
394  for(int index=lower;index<temp_exp[i+1];++index)
395  {
396  temp_mantissa[i] /= 2.0;
397  ++temp_exp[i];
398  }
399  }
400  //Otherwise the second exponent is smaller
401  else
402  {
403  //The smaller term is the other
404  int lower = temp_exp[i+1];
405  //Loop over the difference in the exponents,
406  //scaling down the mantissa each time
407  for(int index=lower;index<temp_exp[i];++index)
408  {
409  temp_mantissa[i+1] /= 2.0;
410  ++temp_exp[i+1];
411  }
412  }
413  }
414 
415  //Now combine the terms AC - BD
416  //and Combine the terms AD + BC
417  determinant_mantissa = std::complex<double>(
418  temp_mantissa[0] - temp_mantissa[1],
419  temp_mantissa[2] + temp_mantissa[3]);
420  //The exponents will be the same, so pick one
421  determinant_exponent= std::complex<int> (temp_exp[0],temp_exp[2]);
422 
423  //Finally normalise the result
424  determinant_mantissa = std::complex<double>(
425  frexp(determinant_mantissa.real(),&iexp_real),
426  frexp(determinant_mantissa.imag(),&iexp_imag));
427 
428  int temp_real = determinant_exponent.real() + iexp_real;
429  int temp_imag = determinant_exponent.imag() + iexp_imag;
430 
431  determinant_exponent = std::complex<int>(temp_real,temp_imag);
432  }
433 
434  //Integer to store the sign of the determinant
435  int sign = 0;
436  //Find the sign of the determinant (left or right half-plane)
437  if(std::abs(determinant_mantissa) > 0.0) {sign = 1;}
438  if(std::abs(determinant_mantissa) < 0.0) {sign = -1;}
439 
440  //Multiply the sign by the signature
441  sign *= signature;
442 
443  //Return the sign of the determinant
444  return sign;
445 }
446 
447 //============================================================================
448 /// Back substitute an LU decomposed matrix.
449 //============================================================================
450 void DenseComplexMatrix::lubksub(Vector<std::complex<double> > &rhs)
451 {
452 #ifdef PARANOID
453  // Check Matrix is square
454  if (N!=M)
455  {
456  throw OomphLibError(
457  "This matrix is not square, the matrix MUST be square!",
458  OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
459  }
460  // Check that size of rhs=nrow() and index=nrow() are correct!
461  if (rhs.size()!=N)
462  {
463  std::ostringstream error_message_stream;
464  error_message_stream
465  << "The rhs vector is not the right size. It is " << rhs.size()
466  << ", it should be " << N << std::endl;
467 
468  throw OomphLibError(error_message_stream.str(),
469 OOMPH_CURRENT_FUNCTION,
470  OOMPH_EXCEPTION_LOCATION);
471  }
472  if(Index == 0)
473  {
474  throw OomphLibError(
475  "Index vector has not been allocated. Have you called ludecompse()\n",
476 OOMPH_CURRENT_FUNCTION,
477  OOMPH_EXCEPTION_LOCATION);
478  }
479  if(Index->size()!=N)
480  {
481  std::ostringstream error_message_stream;
482  error_message_stream
483  << "The Index vector is not the right size. It is " << Index->size()
484  << ", it should be " << N << std::endl;
485 
486  throw OomphLibError(error_message_stream.str(),
487 OOMPH_CURRENT_FUNCTION,
488  OOMPH_EXCEPTION_LOCATION);
489  }
490 #endif
491 
492  unsigned long ii=0;
493  for(unsigned i=0;i<N;i++)
494  {
495  unsigned long ip = (*Index)[i];
496  std::complex<double> sum = rhs[ip];
497  rhs[ip] = rhs[i];
498 
499  if(ii != 0)
500  {
501  for(unsigned long j=ii-1;j<i;j++)
502  {
503  sum -= LU_factors[M*i+j]*rhs[j];
504  }
505  }
506  else if(sum != 0.0)
507  {
508  ii = i+1;
509  }
510  rhs[i] = sum;
511  }
512 
513  //Now do the back substitution
514  for (long i=long(N)-1;i>=0;i--)
515  {
516  std::complex<double> sum = rhs[i];
517  for(long j=i+1;j<long(N);j++) sum -= LU_factors[M*i+j]*rhs[j];
518  rhs[i] = sum/LU_factors[M*i+i];
519  }
520 
521 }
522 
523 //============================================================================
524 /// Find the residual of Ax=b, i.e. r=b-Ax
525 //============================================================================
526 void DenseComplexMatrix::residual(const Vector<std::complex<double> >&x,
527  const Vector<std::complex<double> > &rhs,
528  Vector<std::complex<double> > &residual)
529 {
530 #ifdef PARANOID
531  // Check Matrix is square
532  if (N!=M)
533  {
534  throw OomphLibError(
535  "This matrix is not square, the matrix MUST be square!",
536  OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
537  }
538  // Check that size of rhs = nrow()
539  if (rhs.size()!=N)
540  {
541  std::ostringstream error_message_stream;
542  error_message_stream
543  << "The rhs vector is not the right size. It is " << rhs.size()
544  << ", it should be " << N << std::endl;
545 
546  throw OomphLibError(error_message_stream.str(),
547  OOMPH_CURRENT_FUNCTION,
548  OOMPH_EXCEPTION_LOCATION);
549  }
550  // Check that the size of x is correct
551  if (x.size()!=N)
552  {
553  std::ostringstream error_message_stream;
554  error_message_stream
555  << "The x vector is not the right size. It is " << x.size()
556  << ", it should be " << N << std::endl;
557 
558  throw OomphLibError(error_message_stream.str(),
559  OOMPH_CURRENT_FUNCTION,
560  OOMPH_EXCEPTION_LOCATION);
561  }
562 #endif
563  // If size of residual is wrong, correct it!
564  if (residual.size()!=N)
565  {
566  residual.resize(N);
567  }
568 
569  // Multiply the matrix by the vector x in residual vector
570  for (unsigned long i=0;i<N;i++)
571  {
572  residual[i]=rhs[i];
573  for (unsigned long j=0;j<M;j++)
574  {
575  residual[i] -= Matrixdata[M*i+j]*x[j];
576  }
577  }
578 
579 }
580 
581 
582 
583 
584 //============================================================================
585 /// Multiply the matrix by the vector x: soln=Ax
586 //============================================================================
587 void DenseComplexMatrix::multiply(const Vector<std::complex<double> > &x,
588  Vector<std::complex<double> > &soln)
589 {
590 #ifdef PARANOID
591  // Check to see if x.size() = ncol().
592  if (x.size()!=M)
593  {
594  std::ostringstream error_message_stream;
595  error_message_stream
596  << "The x vector is not the right size. It is " << x.size()
597  << ", it should be " << M << std::endl;
598 
599  throw OomphLibError(error_message_stream.str(),
600  OOMPH_CURRENT_FUNCTION,
601  OOMPH_EXCEPTION_LOCATION);
602  }
603 #endif
604 
605  if (soln.size()!=N)
606  {
607  // Resize and initialize the solution vector
608  soln.resize(N);
609  }
610 
611  // Multiply the matrix A, by the vector x
612  for (unsigned long i=0;i<N;i++)
613  {
614  soln[i] = 0.0;
615  for (unsigned long j=0;j<M;j++)
616  {
617  soln[i] += Matrixdata[M*i+j]*x[j];
618  }
619  }
620 }
621 
622 
623 
624 
625 //=================================================================
626 /// Multiply the transposed matrix by the vector x: soln=A^T x
627 //=================================================================
629  const Vector<std::complex<double> > &x,
630  Vector<std::complex<double> > &soln)
631 {
632 
633 #ifdef PARANOID
634  // Check to see x.size() = nrow()
635  if (x.size()!=N)
636  {
637  std::ostringstream error_message_stream;
638  error_message_stream
639  << "The x vector is not the right size. It is " << x.size()
640  << ", it should be " << N << std::endl;
641 
642  throw OomphLibError(error_message_stream.str(),
643  OOMPH_CURRENT_FUNCTION,
644  OOMPH_EXCEPTION_LOCATION);
645  }
646 #endif
647 
648  if (soln.size() != M)
649  {
650  // Resize and initialize the solution vector
651  soln.resize(M);
652  }
653 
654  // Initialise the solution
655  for (unsigned long i=0;i<M;i++)
656  {
657  soln[i] = 0.0;
658  }
659 
660 
661  // Matrix vector product
662  for (unsigned long i=0;i<N;i++)
663  {
664  for (unsigned long j=0;j<M;j++)
665  {
666  soln[j] += Matrixdata[N*i+j]*x[i];
667  }
668  }
669 }
670 
671 
672 //=============================================================================
673 /// Function to multiply this matrix by the DenseComplexMatrix matrix_in.
674 //=============================================================================
676  DenseComplexMatrix& result)
677 {
678 #ifdef PARANOID
679  // check matrix dimensions are compatable
680  if ( this->ncol() != matrix_in.nrow() )
681  {
682  std::ostringstream error_message;
683  error_message
684  << "Matrix dimensions incompatable for matrix-matrix multiplication"
685  << "ncol() for first matrix:" << this->ncol()
686  << "nrow() for second matrix: " << matrix_in.nrow();
687 
688  throw OomphLibError(error_message.str(), OOMPH_CURRENT_FUNCTION,
689  OOMPH_EXCEPTION_LOCATION);
690  }
691 #endif
692 
693  // NB N is number of rows!
694  unsigned long n_row = this->nrow();
695  unsigned long m_col = matrix_in.ncol();
696 
697  // resize and intialize result
698  result.resize(n_row, m_col, 0.0);
699 
700  // clock_t clock1 = clock();
701 
702  // do calculation
703  unsigned long n_col=this->ncol();
704  for (unsigned long k=0; k<n_col; k++)
705  {
706  for (unsigned long i=0; i<n_row; i++)
707  {
708  for (unsigned long j=0; j<m_col; j++)
709  {
710  result(i,j) += Matrixdata[m_col*i+k] * matrix_in(k,j);
711  }
712  }
713  }
714 }
715 
716 //============================================================================
717 /// Scale the matrix by the real c
718 //============================================================================
719 void DenseComplexMatrix::scale(const double &c)
720 {
721  // Multiply the matrix A, by the real double c
722  for (unsigned long i=0;i<N;i++)
723  {
724  for (unsigned long j=0;j<M;j++)
725  {
726  Matrixdata[M*i+j] = Matrixdata[M*i+j]*c;
727  }
728  }
729 }
730 
731 //============================================================================
732 /// Scale the matrix by the complex number c
733 //============================================================================
734 void DenseComplexMatrix::scale(const std::complex<double> &c)
735 {
736  // Multiply the matrix A, by the real double c
737  for (unsigned long i=0;i<N;i++)
738  {
739  for (unsigned long j=0;j<M;j++)
740  {
741  Matrixdata[M*i+j] = Matrixdata[M*i+j]*c;
742  }
743  }
744 }
745 
746 ////////////////////////////////////////////////////////////////////////
747 ////////////////////////////////////////////////////////////////////////
748 ////////////////////////////////////////////////////////////////////////
749 
750 
751 
752 //===================================================================
753 // Interface to SuperLU wrapper
754 //===================================================================
755 extern "C"
756 {
757  int superlu_complex(int *, int *, int *, int *,
758  std::complex<double> *, int *, int *,
759  std::complex<double> *, int *, int *, int *,
760  void*, int *);
761 }
762 
763 
764 //===================================================================
765 /// Perform LU decomposition. Return the sign of the determinant
766 //===================================================================
768 {
769 #ifdef PARANOID
770  if (N!=M)
771  {
772  std::ostringstream error_message_stream;
773  error_message_stream << "Can only solve for quadratic matrices\n"
774  << "N, M " << N << " " << M << std::endl;
775 
776  throw OomphLibError(error_message_stream.str(),
777  OOMPH_CURRENT_FUNCTION,
778  OOMPH_EXCEPTION_LOCATION);
779  }
780 #endif
781 
782  // SuperLU expects compressed column format: Set flag for
783  // transpose (0/1) = (false/true)
784  int transpose=0;
785 
786  // Doc (0/1) = (false/true)
787  int doc=0;
788  if (Doc_stats_during_solve) doc=1;
789 
790  //Cast to integers for stupid SuperLU
791  int n_aux = (int)N;
792  int nnz_aux = (int)Nnz;
793 
794  //Integer to hold the sign of the determinant
795  int sign=0;
796 
797  //Just do the lu decompose phase (i=1)
798  int i=1;
799  sign = superlu_complex(&i, &n_aux, &nnz_aux, 0,
800  Value, Row_index, Column_start,
801  0, &n_aux, &transpose, &doc,
802  &F_factors, &Info);
803 
804  //Return the sign of the determinant
805  return sign;
806 }
807 
808 
809 
810 //===================================================================
811 /// Do the backsubstitution
812 //===================================================================
813 void CCComplexMatrix::lubksub(Vector<std::complex<double> > &rhs)
814 {
815 #ifdef PARANOID
816  if (N!=rhs.size())
817  {
818  std::ostringstream error_message_stream;
819  error_message_stream << "Size of RHS doesn't match matrix size\n"
820  << "N, rhs.size() " << N << " " << rhs.size()
821  << std::endl;
822 
823  throw OomphLibError(error_message_stream.str(),
824  OOMPH_CURRENT_FUNCTION,
825  OOMPH_EXCEPTION_LOCATION);
826  }
827  if (N!=M)
828  {
829  std::ostringstream error_message_stream;
830  error_message_stream << "Can only solve for quadratic matrices\n"
831  << "N, M " << N << " " << M << std::endl;
832 
833  throw OomphLibError(error_message_stream.str(),
834  OOMPH_CURRENT_FUNCTION,
835  OOMPH_EXCEPTION_LOCATION);
836  }
837 #endif
838 
839  /// RHS vector
840  std::complex<double>* b=new std::complex<double> [N];
841 
842  // Copy across
843  for (unsigned long i=0;i<N;i++) {b[i]=rhs[i];}
844 
845  // SuperLU expects compressed column format: Set flag for
846  // transpose (0/1) = (false/true)
847  int transpose=0;
848 
849  // Doc (0/1) = (false/true)
850  int doc=0;
851  if (Doc_stats_during_solve) doc=1;
852 
853  //Number of RHSs
854  int nrhs=1;
855 
856 
857  //Cast to integers for stupid SuperLU
858  int n_aux = (int)N;
859  int nnz_aux = (int)Nnz;
860 
861  // SuperLU in three steps (lu decompose, back subst, cleanup)
862  //Do the solve phase
863  int i=2;
864  superlu_complex(&i, &n_aux, &nnz_aux, &nrhs,
865  Value, Row_index, Column_start,
866  b, &n_aux, &transpose, &doc,
867  &F_factors, &Info);
868 
869  // Copy b into rhs vector
870  for (unsigned long i=0;i<N;i++)
871  {
872  rhs[i]=b[i];
873  }
874 
875  // Cleanup
876  delete[] b;
877 }
878 
879 
880 
881 
882 //===================================================================
883 /// Cleanup storage
884 //===================================================================
886 {
887  //Only bother if we've done an LU solve
888  if(F_factors != 0)
889  {
890  // SuperLU expects compressed column format: Set flag for
891  // transpose (0/1) = (false/true)
892  int transpose=0;
893 
894  // Doc (0/1) = (false/true)
895  int doc=0;
896  if (Doc_stats_during_solve) doc=1;
897 
898 
899  //Cast to integers for stupid SuperLU
900  int n_aux = (int)N;
901  int nnz_aux = (int)Nnz;
902 
903  // SuperLU in three steps (lu decompose, back subst, cleanup)
904  // Flag to indicate which solve step to do (1, 2 or 3)
905  int i=3;
906  superlu_complex(&i, &n_aux , &nnz_aux, 0,
907  Value, Row_index, Column_start,
908  0, &n_aux, &transpose, &doc,
909  &F_factors, &Info);
910  }
911 }
912 
913 
914 //===================================================================
915 /// Work out residual vector r = b-Ax for candidate solution x
916 //===================================================================
917 void CCComplexMatrix::residual(const Vector<std::complex<double> > &x,
918  const Vector<std::complex<double> >& rhs,
919  Vector<std::complex<double> >& residual)
920 {
921 
922 #ifdef PARANOID
923  // Check Matrix is square
924  if (N!=M)
925  {
926  throw OomphLibError(
927  "This matrix is not square, the matrix MUST be square!",
928  OOMPH_CURRENT_FUNCTION, OOMPH_EXCEPTION_LOCATION);
929  }
930  // Check that size of rhs = nrow()
931  if (rhs.size()!=N)
932  {
933  std::ostringstream error_message_stream;
934  error_message_stream
935  << "The rhs vector is not the right size. It is " << rhs.size()
936  << ", it should be " << N << std::endl;
937 
938  throw OomphLibError(error_message_stream.str(),
939 OOMPH_CURRENT_FUNCTION,
940  OOMPH_EXCEPTION_LOCATION);
941  }
942  // Check that the size of x is correct
943  if (x.size()!=N)
944  {
945  std::ostringstream error_message_stream;
946  error_message_stream
947  << "The x vector is not the right size. It is " << x.size()
948  << ", it should be " << N << std::endl;
949 
950  throw OomphLibError(error_message_stream.str(),
951 OOMPH_CURRENT_FUNCTION,
952  OOMPH_EXCEPTION_LOCATION);
953  }
954 #endif
955 
956  unsigned long r_n = residual.size();
957  if (r_n!=N)
958  {
959  residual.resize(N);
960  }
961 
962  // Need to do this in loop over rows
963  for (unsigned i=0;i<N;i++)
964  {
965  residual[i] = rhs[i];
966  }
967  // Now loop over columns
968  for (unsigned long j=0;j<N;j++)
969  {
970  for (long k=Column_start[j];k<Column_start[j+1];k++)
971  {
972  unsigned long i=Row_index[k];
973  std::complex<double> a_ij=Value[k];
974  residual[i]-=a_ij*x[j];
975  }
976  }
977 }
978 
979 //===================================================================
980 /// Multiply the matrix by the vector x
981 //===================================================================
982 void CCComplexMatrix::multiply(const Vector<std::complex<double> > &x,
983  Vector<std::complex<double> > &soln)
984 {
985 
986 #ifdef PARANOID
987  // Check to see if x.size() = ncol()
988  if (x.size()!=M)
989  {
990  std::ostringstream error_message_stream;
991  error_message_stream
992  << "The x vector is not the right size. It is " << x.size()
993  << ", it should be " << M << std::endl;
994 
995  throw OomphLibError(error_message_stream.str(),
996 OOMPH_CURRENT_FUNCTION,
997  OOMPH_EXCEPTION_LOCATION);
998  }
999 #endif
1000 
1001  if (soln.size() != N)
1002  {
1003  // Resize and initialize the solution vector
1004  soln.resize(N);
1005  }
1006  for (unsigned i=0;i<N;i++)
1007  {
1008  soln[i] = 0.0;
1009  }
1010 
1011  for (unsigned long j=0;j<N;j++)
1012  {
1013  for (long k=Column_start[j];k<Column_start[j+1];k++)
1014  {
1015  unsigned long i = Row_index[k];
1016  std::complex<double> a_ij = Value[k];
1017  soln[i] += a_ij*x[j];
1018  }
1019  }
1020 }
1021 
1022 
1023 
1024 
1025 //=================================================================
1026 /// Multiply the transposed matrix by the vector x: soln=A^T x
1027 //=================================================================
1029  const Vector<std::complex<double> > &x,
1030  Vector<std::complex<double> > &soln)
1031 {
1032 
1033 #ifdef PARANOID
1034  // Check to see x.size() = nrow()
1035  if (x.size()!=N)
1036  {
1037  std::ostringstream error_message_stream;
1038  error_message_stream
1039  << "The x vector is not the right size. It is " << x.size()
1040  << ", it should be " << N << std::endl;
1041 
1042  throw OomphLibError(error_message_stream.str(),
1043 OOMPH_CURRENT_FUNCTION,
1044  OOMPH_EXCEPTION_LOCATION);
1045  }
1046 #endif
1047 
1048  if (soln.size() != M)
1049  {
1050  // Resize and initialize the solution vector
1051  soln.resize(M);
1052  }
1053 
1054  // Initialise the solution
1055  for (unsigned long i=0;i<M;i++)
1056  {
1057  soln[i] = 0.0;
1058  }
1059 
1060  // Matrix vector product
1061  for (unsigned long i=0;i<N;i++)
1062  {
1063 
1064  for (long k=Column_start[i];k<Column_start[i+1];k++)
1065  {
1066  unsigned long j=Row_index[k];
1067  std::complex<double> a_ij=Value[k];
1068  soln[j]+=a_ij*x[i];
1069  }
1070  }
1071 
1072 }
1073 
1074 
1075 ////////////////////////////////////////////////////////////////////////
1076 ////////////////////////////////////////////////////////////////////////
1077 ////////////////////////////////////////////////////////////////////////
1078 
1079 
1080 
1081 //===================================================================
1082 /// Do LU decomposition and return sign of determinant
1083 //===================================================================
1085 {
1086 #ifdef PARANOID
1087  if (N!=M)
1088  {
1089  std::ostringstream error_message_stream;
1090  error_message_stream << "Can only solve for quadratic matrices\n"
1091  << "N, M " << N << " " << M << std::endl;
1092 
1093  throw OomphLibError(error_message_stream.str(),
1094 OOMPH_CURRENT_FUNCTION,
1095  OOMPH_EXCEPTION_LOCATION);
1096  }
1097 #endif
1098 
1099  // SuperLU expects compressed column format: Set flag for
1100  // transpose (0/1) = (false/true)
1101  int transpose=1;
1102 
1103  // Doc (0/1) = (false/true)
1104  int doc=0;
1105  if (Doc_stats_during_solve) doc=1;
1106 
1107  // Copies so that const-ness is maintained
1108  int n_aux=int(N);
1109  int nnz_aux=int(Nnz);
1110 
1111  //Integer to hold the sign of the determinant
1112  int sign = 0;
1113 
1114  //Just do the lu decompose phase (i=1)
1115  int i=1;
1116  sign = superlu_complex(&i, &n_aux, &nnz_aux, 0,
1117  Value, Column_index, Row_start,
1118  0, &n_aux, &transpose, &doc,
1119  &F_factors, &Info);
1120  //Return sign of determinant
1121  return sign;
1122 }
1123 
1124 
1125 
1126 
1127 //===================================================================
1128 /// Do back-substitution
1129 //===================================================================
1130 void CRComplexMatrix::lubksub(Vector<std::complex<double> > &rhs)
1131 {
1132 #ifdef PARANOID
1133  if (N!=rhs.size())
1134  {
1135  std::ostringstream error_message_stream;
1136  error_message_stream << "Size of RHS doesn't match matrix size\n"
1137  << "N, rhs.size() " << N << " " << rhs.size()
1138  << std::endl;
1139 
1140  throw OomphLibError(error_message_stream.str(),
1141 OOMPH_CURRENT_FUNCTION,
1142  OOMPH_EXCEPTION_LOCATION);
1143  }
1144  if (N!=M)
1145  {
1146  std::ostringstream error_message_stream;
1147  error_message_stream << "Can only solve for quadratic matrices\n"
1148  << "N, M " << N << " " << M << std::endl;
1149 
1150  throw OomphLibError(error_message_stream.str(),
1151 OOMPH_CURRENT_FUNCTION,
1152  OOMPH_EXCEPTION_LOCATION);
1153  }
1154 #endif
1155 
1156  /// RHS vector
1157  std::complex<double> * b=new std::complex<double> [N];
1158 
1159  // Copy across
1160  for (unsigned long i=0;i<N;i++) {b[i]=rhs[i];}
1161 
1162  // SuperLU expects compressed column format: Set flag for
1163  // transpose (0/1) = (false/true)
1164  int transpose=1;
1165 
1166  // Doc (0/1) = (false/true)
1167  int doc=0;
1168  if (Doc_stats_during_solve) doc=1;
1169 
1170  //Number of RHSs
1171  int nrhs=1;
1172 
1173  // Copies so that const-ness is maintained
1174  int n_aux=int(N);
1175  int nnz_aux=int(Nnz);
1176 
1177  // SuperLU in three steps (lu decompose, back subst, cleanup)
1178  //Do the solve phase
1179  int i=2;
1180  superlu_complex(&i, &n_aux, &nnz_aux, &nrhs,
1181  Value, Column_index, Row_start,
1182  b, &n_aux, &transpose, &doc,
1183  &F_factors, &Info);
1184 
1185  // Copy b into rhs vector
1186  for (unsigned long i=0;i<N;i++)
1187  {
1188  rhs[i]=b[i];
1189  }
1190 
1191  // Cleanup
1192  delete[] b;
1193 }
1194 
1195 
1196 
1197 //===================================================================
1198 /// Cleanup memory
1199 //===================================================================
1201 {
1202  //Only bother if we've done an LU solve
1203  if(F_factors!= 0)
1204  {
1205  // SuperLU expects compressed column format: Set flag for
1206  // transpose (0/1) = (false/true)
1207  int transpose=1;
1208 
1209  // Doc (0/1) = (false/true)
1210  int doc=0;
1211  if (Doc_stats_during_solve) doc=1;
1212 
1213  // Copies so that const-ness is maintained
1214  int n_aux=int(N);
1215  int nnz_aux=int(Nnz);
1216 
1217  // SuperLU in three steps (lu decompose, back subst, cleanup)
1218  // Flag to indicate which solve step to do (1, 2 or 3)
1219  int i=3;
1220  superlu_complex(&i, &n_aux, &nnz_aux, 0,
1221  Value, Column_index, Row_start,
1222  0, &n_aux, &transpose, &doc,
1223  &F_factors, &Info);
1224  }
1225 }
1226 
1227 
1228 //=================================================================
1229 /// Find the residulal to x of Ax=b, ie r=b-Ax
1230 //=================================================================
1231 void CRComplexMatrix::residual(const Vector<std::complex<double> > &x,
1232  const Vector<std::complex<double> > &rhs,
1233  Vector<std::complex<double> > &residual)
1234 {
1235 
1236 #ifdef PARANOID
1237  // Check that size of rhs = nrow()
1238  if (rhs.size()!=N)
1239  {
1240  std::ostringstream error_message_stream;
1241  error_message_stream
1242  << "The rhs vector is not the right size. It is " << rhs.size()
1243  << ", it should be " << N << std::endl;
1244 
1245  throw OomphLibError(error_message_stream.str(),
1246  OOMPH_CURRENT_FUNCTION,
1247  OOMPH_EXCEPTION_LOCATION);
1248  }
1249  // Check that the size of x is correct
1250  if (x.size()!=M)
1251  {
1252  std::ostringstream error_message_stream;
1253  error_message_stream
1254  << "The x vector is not the right size. It is " << x.size()
1255  << ", it should be " << M << std::endl;
1256 
1257  throw OomphLibError(error_message_stream.str(),
1258  OOMPH_CURRENT_FUNCTION,
1259  OOMPH_EXCEPTION_LOCATION);
1260  }
1261 #endif
1262 
1263  if (residual.size()!=N)
1264  {
1265  residual.resize(N);
1266  }
1267 
1268  for (unsigned long i=0;i<N;i++)
1269  {
1270  residual[i]=rhs[i];
1271  for (long k=Row_start[i];k<Row_start[i+1];k++)
1272  {
1273  unsigned long j=Column_index[k];
1274  std::complex<double> a_ij=Value[k];
1275  residual[i]-=a_ij*x[j];
1276  }
1277  }
1278 
1279 }
1280 
1281 //=================================================================
1282 /// Multiply the matrix by the vector x
1283 //=================================================================
1285  const Vector<std::complex<double> > &x,
1286  Vector<std::complex<double> > &soln)
1287 {
1288 #ifdef PARANOID
1289  // Check to see x.size() = ncol()
1290  if (x.size()!=M)
1291  {
1292  std::ostringstream error_message_stream;
1293  error_message_stream
1294  << "The x vector is not the right size. It is " << x.size()
1295  << ", it should be " << M << std::endl;
1296 
1297  throw OomphLibError(error_message_stream.str(),
1298  OOMPH_CURRENT_FUNCTION,
1299  OOMPH_EXCEPTION_LOCATION);
1300  }
1301 #endif
1302 
1303  if (soln.size() != N)
1304  {
1305  // Resize and initialize the solution vector
1306  soln.resize(N);
1307  }
1308  for (unsigned long i=0;i<N;i++)
1309  {
1310  soln[i] = 0.0;
1311  for (long k=Row_start[i];k<Row_start[i+1];k++)
1312  {
1313  unsigned long j=Column_index[k];
1314  std::complex<double> a_ij=Value[k];
1315  soln[i]+=a_ij*x[j];
1316  }
1317  }
1318 }
1319 
1320 
1321 
1322 
1323 
1324 //=================================================================
1325 /// Multiply the transposed matrix by the vector x: soln=A^T x
1326 //=================================================================
1328  const Vector<std::complex<double> > &x,
1329  Vector<std::complex<double> > &soln)
1330 {
1331 
1332 #ifdef PARANOID
1333  // Check to see x.size() = nrow()
1334  if (x.size()!=N)
1335  {
1336  std::ostringstream error_message_stream;
1337  error_message_stream
1338  << "The x vector is not the right size. It is " << x.size()
1339  << ", it should be " << N << std::endl;
1340 
1341  throw OomphLibError(error_message_stream.str(),
1342  OOMPH_CURRENT_FUNCTION,
1343  OOMPH_EXCEPTION_LOCATION);
1344  }
1345 #endif
1346 
1347  if (soln.size() != M)
1348  {
1349  // Resize and initialize the solution vector
1350  soln.resize(M);
1351  }
1352 
1353  // Initialise the solution
1354  for (unsigned long i=0;i<M;i++)
1355  {
1356  soln[i] = 0.0;
1357  }
1358 
1359  // Matrix vector product
1360  for (unsigned long i=0;i<N;i++)
1361  {
1362  for (long k=Row_start[i];k<Row_start[i+1];k++)
1363  {
1364  unsigned long j=Column_index[k];
1365  std::complex<double> a_ij=Value[k];
1366  soln[j]+=a_ij*x[i];
1367  }
1368  }
1369 }
1370 }
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 lubksub(Vector< std::complex< double > > &rhs)
LU back solve for given RHS.
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 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.
cstr elem_len * i
Definition: cfortran.h:607
int ludecompose()
LU decomposition using SuperLU.
void resize(const unsigned &N, const unsigned &M)
unsigned long ncol() const
Return the number of columns of the matrix.
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.
virtual std::complex< double > operator()(const unsigned long &i, const unsigned long &j) const
Round brackets to give access as a(i,j) for read only (we&#39;re not providing a general interface for co...
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.
virtual unsigned long nrow() const =0
Return the number of rows of the matrix.
int ludecompose()
Overload the LU decomposition. For this storage scheme the matrix storage will be over-writeen by its...
void clean_up_memory()
LU clean up (perhaps this should happen in the destructor)
void clean_up_memory()
LU clean up (perhaps this should happen in the destructor)
void multiply(const Vector< std::complex< double > > &x, Vector< std::complex< double > > &soln)
Multiply the matrix by the vector x: soln=Ax.
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 superlu_complex(int *, int *, int *, int *, std::complex< double > *, int *, int *, std::complex< double > *, int *, int *, int *, void *, int *)
virtual void residual(const Vector< std::complex< double > > &x, const Vector< std::complex< double > > &b, Vector< std::complex< double > > &residual)=0
Find the residual, i.e. r=b-Ax the residual.
void multiply(const Vector< std::complex< double > > &x, Vector< std::complex< double > > &result)
Multiply the matrix by the vector x: soln=Ax.
void lubksub(Vector< std::complex< double > > &rhs)
Overload the LU back substitution. Note that the rhs will be overwritten with the solution vector...
virtual ~DenseComplexMatrix()
Destructor, delete the storage for Index vector and LU storage (if any)
void lubksub(Vector< std::complex< double > > &rhs)
LU back solve for given RHS.
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...
unsigned long nrow() const
Return the number of rows of the matrix.
void multiply(const Vector< std::complex< double > > &x, Vector< std::complex< double > > &soln)
Multiply the matrix by the vector x: soln=Ax.
void scale(const double &c)
Scale this matrix by a double c.
virtual void solve(Vector< std::complex< double > > &rhs)
Complete LU solve (replaces matrix by its LU decomposition and overwrites RHS with solution)...
virtual int ludecompose()
LU decomposition of the matrix using the appropriate linear solver. Return the sign of the determinan...
Class of matrices containing double complex, and stored as a DenseMatrix<complex<double> >...
void multiply(const Vector< std::complex< double > > &x, Vector< std::complex< double > > &soln)
Multiply the matrix by the vector x: soln=Ax.
virtual unsigned long ncol() const =0
Return the number of columns of the matrix.
void resize(const unsigned long &n)
Definition: matrices.h:511