Extension: Matrix functions
#include "dg/matrix/matrix.h"
tridiaginv.h
Go to the documentation of this file.
1#pragma once
2
3#include <boost/math/special_functions.hpp> // has to be included before lapack in certain versions
4#include <cusp/dia_matrix.h>
5#include <cusp/coo_matrix.h>
6#include <cusp/lapack/lapack.h>
7#include "dg/algorithm.h"
8
9#include "functors.h"
14namespace dg{
15namespace mat{
16
19
31template<class value_type>
32value_type compute_Tinv_m1( const cusp::dia_matrix<int, value_type,
33 cusp::host_memory>& T, unsigned size)
34{
35 value_type ci = T.values(0,2)/T.values(0,1), ciold = 0.;
36 value_type di = 1./T.values(0,1), diold = 0.;
37 for( unsigned i=1; i<size; i++)
38 {
39 ciold = ci, diold = di;
40 ci = T.values(i,2)/ ( T.values(i,1)-T.values(i,0)*ciold);
41 di = -T.values( i, 0)*diold/(T.values(i,1)-T.values(i,0)*ciold);
42 }
43 return di;
44}
57template<class value_type>
58void compute_Tinv_y( const cusp::dia_matrix<int, value_type,
59 cusp::host_memory>& T,
60 thrust::host_vector<value_type>& x,
61 const thrust::host_vector<value_type>& y, value_type a = 1.,
62 value_type d = 0.)
63{
64 unsigned size = y.size();
65 x.resize(size);
66 thrust::host_vector<value_type> ci(size), di(size);
67 ci[0] = a*T.values(0,2)/( a*T.values(0,1) + d);
68 di[0] = y[0]/( a*T.values(0,1) + d);
69 for( unsigned i=1; i<size; i++)
70 {
71 ci[i] = a*T.values(i,2)/ ( a*T.values(i,1) + d -a*T.values(i,0)*ci[i-1]);
72 di[i] = (y[i]-a*T.values( i, 0)*di[i-1])/(a*T.values(i,1) + d
73 -a*T.values(i,0)*ci[i-1]);
74 }
75 x[size-1] = di[size-1];
76 for( int i=size-2; i>=0; i--)
77 x[i] = di[i] - ci[i]*x[i+1];
78}
79
80
93template< class ContainerType, class DiaMatrix, class CooMatrix>
95{
96 public:
105 TridiagInvHMGTI(const ContainerType& copyable)
106 {
107 m_size = copyable.size();
108 m_alphas.assign(m_size+1,0.);
109 m_betas.assign(m_size+1,0.);
110 }
116 TridiagInvHMGTI(unsigned size)
117 {
118 m_size = size;
119 m_alphas.assign(m_size+1,0.);
120 m_betas.assign(m_size+1,0.);
121 }
127 void resize(unsigned new_size) {
128 m_size = new_size;
129 m_alphas.resize(m_size+1,0.);
130 m_betas.resize(m_size+1,0.);
131 }
139 void operator()(const DiaMatrix& T, CooMatrix& Tinv)
140 {
141 this->operator()(
142 T.values.column(1), // 0 diagonal
143 T.values.column(2), // +1 diagonal
144 T.values.column(0), // -1 diagonal
145 Tinv);
146 }
153 CooMatrix operator()(const DiaMatrix& T)
154 {
155 CooMatrix Tinv;
156 this->operator()( T, Tinv);
157 return Tinv;
158 }
169 template<class ContainerType0, class ContainerType1, class ContainerType2>
170 void operator()(const ContainerType0& a, const ContainerType1& b,
171 const ContainerType2& c, CooMatrix& Tinv)
172 {
173 unsigned ss = m_size;
174 Tinv.resize(ss, ss, ss* ss);
175 if( ss == 1)
176 {
177 Tinv.row_indices[0] = 0;
178 Tinv.column_indices[0] = 0;
179 Tinv.values[0] = 1./b[0];
180 return;
181 }
182 //fill alphas
183 m_alphas[0]=1.0;
184 m_alphas[1]=a[0];
185 for( unsigned i = 2; i<ss+1; i++)
186 {
187 m_alphas[i] = a[i-1]*m_alphas[i-1] - c[i-1]*b[i-2]*m_alphas[i-2];
188 if (m_alphas[i] ==0 && i<ss) {
189 throw dg::Error( dg::Message(_ping_) << "# Failure in alpha["<<i<<"] !");
190 }
191 }
192 if (m_alphas[ss] ==0)
193 throw dg::Error( dg::Message(_ping_) << "# No Inverse of tridiagonal matrix exists !");
194
195 //fill betas
196 m_betas[ss]=1.0;
197 m_betas[ss-1]=a[ss-1];
198 m_betas[0] = m_alphas[ss];
199 for( int i = ss-2; i>0; i--)
200 {
201 m_betas[i] = a[i]*m_betas[i+1] - c[i+1]*b[i]*m_betas[i+2];
202 if (m_betas[i] ==0)
203 {
204 throw dg::Error( dg::Message(_ping_) << "# Failure in beta["<<i<<"] !");
205 }
206 }
207 //Diagonal entries
208 Tinv.row_indices[0*ss+0] = 0;
209 Tinv.column_indices[0*ss+0] = 0;
210 Tinv.row_indices[(ss-1)*ss+(ss-1)] = (ss-1);
211 Tinv.column_indices[(ss-1)*ss+(ss-1)] = (ss-1);
212 Tinv.values[0*ss+0] = 1.0/(a[0]-c[1]*b[0]*m_betas[2]/m_betas[1]);
213 Tinv.values[(ss-1)*ss+(ss-1)] = 1.0/(a[ss-1] -
214 c[ss-1]*b[ss-2]*m_alphas[ss-2]/m_alphas[ss-1]);
215 for( unsigned i=1; i<ss-1; i++)
216 {
217 Tinv.row_indices[i*ss+i] = i;
218 Tinv.column_indices[i*ss+i] = i;
219 Tinv.values[i*ss+i] =
220 1.0/(a[i]-c[i]*b[i-1]*m_alphas[i-1]/m_alphas[i]
221 -c[i+1]*b[i]*m_betas[i+2]/m_betas[i+1]);
222 }
223 //Off-diagonal entries
224 for( unsigned i=0; i<ss; i++)
225 {
226 for( unsigned j=0; j<ss; j++)
227 {
228 Tinv.row_indices[i*ss+j] = j;
229 Tinv.column_indices[i*ss+j] = i;
230 if (i<j) {
231 Tinv.values[i*ss+j] =
232 sign(j-i)*std::accumulate(std::next(b.begin(),i),
233 std::next(b.begin(),j), 1.,
234 std::multiplies<value_type>())*
235 m_alphas[i]/m_alphas[j]*Tinv.values[j*ss+j];
236 }
237 else if (i>j)
238 {
239 Tinv.values[i*ss+j] =
240 sign(i-j)*std::accumulate(std::next(c.begin(),j+1),
241 std::next(c.begin(),i+1), 1.,
242 std::multiplies<value_type>())*
243 m_betas[i+1]/m_betas[j+1]*Tinv.values[j*ss+j];
244 }
245 }
246 }
247 }
248 private:
250 int sign(unsigned i)
251 {
252 if (i%2==0) return 1;
253 else return -1;
254 }
255 ContainerType m_alphas, m_betas;
256 unsigned m_size;
257};
258
259
270template< class ContainerType, class DiaMatrix, class CooMatrix>
272{
273 public:
282 TridiagInvDF(const ContainerType& copyable)
283 {
284 m_size = copyable.size();
285 m_phi.assign(m_size,0.);
286 m_theta.assign(m_size,0.);
287 }
293 TridiagInvDF(unsigned size)
294 {
295 m_size = size;
296 m_phi.assign(m_size,0.);
297 m_theta.assign(m_size,0.);
298 }
304 void resize(unsigned new_size) {
305 m_size = new_size;
306 m_phi.resize(m_size,0.);
307 m_theta.resize(m_size,0.);
308 }
316 void operator()(const DiaMatrix& T, CooMatrix& Tinv)
317 {
318 this->operator()(
319 T.values.column(1), // 0 diagonal
320 T.values.column(2), // +1 diagonal
321 T.values.column(0), // -1 diagonal
322 Tinv);
323 }
330 CooMatrix operator()(const DiaMatrix& T)
331 {
332 CooMatrix Tinv;
333 this->operator()( T, Tinv);
334 return Tinv;
335 }
346 template<class ContainerType0, class ContainerType1, class ContainerType2>
347 void operator()(const ContainerType0& a, const ContainerType1& b,
348 const ContainerType2& c, CooMatrix& Tinv)
349 {
350 Tinv.resize(m_size, m_size, m_size* m_size);
351 value_type helper = 0.0;
352 //fill phi values
353 m_phi[0] = - b[0]/a[0];
354 for( unsigned i = 1; i<m_size; i++)
355 {
356 helper = m_phi[i-1]* c[i] + a[i];
357 if (helper==0) throw dg::Error( dg::Message(_ping_)<< "Failure: Division by zero\n");
358 else m_phi[i] = -b[i]/helper;
359 }
360// m_phi[m_size] = 0.0;
361
362 //fill theta values
363 if (m_size == 1) m_theta[m_size-1] = 0.0;
364 else
365 {
366 m_theta[m_size-1] = - c[m_size-1]/a[m_size-1];
367 for( int i = m_size-2; i>=0; i--)
368 {
369 helper = m_theta[i+1]*b[i] + a[i];
370 if (helper==0) throw dg::Error( dg::Message(_ping_)<< "Failure: Division by zero\n");
371 else m_theta[i] = -c[i]/helper;
372 }
373 }
374// m_theta[0] = 0.0;
375 //Diagonal entries
376 Tinv.row_indices[0*m_size+0] = 0;
377 Tinv.column_indices[0*m_size+0] = 0;
378 helper = a[0] + b[0]* m_theta[1];
379 if (helper==0) throw dg::Error( dg::Message(_ping_)<< "Failure: No inverse exists\n");
380 else Tinv.values[0*m_size+0] = 1.0/helper;
381
382 Tinv.row_indices[(m_size-1)*m_size+(m_size-1)] = (m_size-1);
383 Tinv.column_indices[(m_size-1)*m_size+(m_size-1)] = (m_size-1);
384 if (m_size == 1) helper = a[m_size-1];
385 else helper = a[m_size-1] + c[m_size-1]*m_phi[m_size-2];
386
387 if (helper==0) throw dg::Error( dg::Message(_ping_)<< "Failure: No inverse exists\n");
388 else Tinv.values[(m_size-1)*m_size+m_size-1] = 1.0/helper;
389
390 for( unsigned i=1; i<m_size-1; i++)
391 {
392 Tinv.row_indices[i*m_size+i] = i;
393 Tinv.column_indices[i*m_size+i] = i;
394 helper = a[i] + c[i]*m_phi[i-1] + b[i]* m_theta[i+1];
395 if (helper==0) throw dg::Error( dg::Message(_ping_)<< "Failure: No inverse exists\n");
396 else Tinv.values[i*m_size+i] = 1.0/helper;
397 }
398 //Off-diagonal entries
399 for( unsigned j=0; j<m_size-1; j++) //row index
400 {
401 for (unsigned i=j+1; i<m_size; i++)
402 {
403 Tinv.row_indices[i*m_size+j] = i;
404 Tinv.column_indices[i*m_size+j] = j;
405 Tinv.values[i*m_size+j] = m_theta[i]*Tinv.values[(i-1)*m_size+j];
406 }
407 }
408 for( unsigned j=1; j<m_size; j++) //row index
409 {
410 for (int i=j-1; i>=0; i--)
411 {
412 Tinv.row_indices[i*m_size+j] = i;
413 Tinv.column_indices[i*m_size+j] = j;
414 Tinv.values[i*m_size+j] = m_phi[i]*Tinv.values[(i+1)*m_size+j];
415 }
416 }
417 }
418 private:
419 ContainerType m_phi, m_theta;
420 unsigned m_size;
421};
422
434template< class ContainerType, class DiaMatrix, class CooMatrix>
436{
437 public:
446 TridiagInvD(const ContainerType& copyable)
447 {
448 m_size = copyable.size();
449 m_phi.assign(m_size+1,0.);
450 m_theta.assign(m_size+1,0.);
451 }
457 TridiagInvD(unsigned size)
458 {
459 m_size = size;
460 m_phi.assign(m_size+1,0.);
461 m_theta.assign(m_size+1,0.);
462 }
468 void resize(unsigned new_size) {
469 m_size = new_size;
470 m_phi.resize(m_size+1,0.);
471 m_theta.resize(m_size+1,0.);
472 }
480 void operator()(const DiaMatrix& T, CooMatrix& Tinv)
481 {
482 this->operator()(
483 T.values.column(1), // 0 diagonal
484 T.values.column(2), // +1 diagonal
485 T.values.column(0), // -1 diagonal
486 Tinv);
487 }
494 CooMatrix operator()(const DiaMatrix& T)
495 {
496 CooMatrix Tinv;
497 this->operator()( T, Tinv);
498 return Tinv;
499 }
510 template<class ContainerType0, class ContainerType1, class ContainerType2>
511 void operator()(const ContainerType0& a, const ContainerType1& b,
512 const ContainerType2& c, CooMatrix& Tinv)
513 {
514 Tinv.resize( m_size, m_size, m_size*m_size);
515 unsigned is=0;
516 for( unsigned i = 0; i<m_size+1; i++)
517 {
518 is = m_size - i;
519 if (i==0)
520 {
521 m_theta[0] = 1.;
522 m_phi[is] = 1.;
523 }
524 else if (i==1)
525 {
526 m_theta[1] = a[0];
527 m_phi[is] = a[is];
528 }
529 else
530 {
531 m_theta[i] = a[i-1] * m_theta[i-1] - b[i-2] * c[i-1] * m_theta[i-2];
532 m_phi[is] = a[is] * m_phi[is+1] - b[is] * c[is+1] * m_phi[is+2];
533 }
534 }
535
536 //Compute inverse tridiagonal matrix elements
537 for( unsigned i=0; i<m_size; i++) //row index
538 {
539 for( unsigned j=0; j<m_size; j++) //column index
540 {
541 Tinv.row_indices[i*m_size+j] = i;
542 Tinv.column_indices[i*m_size+j] = j;
543 if (i<j) {
544 Tinv.values[i*m_size+j] =
545 std::accumulate(std::next(b.begin(),i),
546 std::next(b.begin(),j), 1.,
547 std::multiplies<value_type>())*sign(i+j) *
548 m_theta[i] * m_phi[j+1]/m_theta[m_size];
549 }
550 else if (i==j)
551 {
552 Tinv.values[i*m_size+j] = m_theta[i] * m_phi[i+1]/m_theta[m_size];
553 }
554 else // if (i>j)
555 {
556 Tinv.values[i*m_size+j] =
557 std::accumulate(std::next(c.begin(),j+1),
558 std::next(c.begin(),i+1), 1.,
559 std::multiplies<value_type>())*sign(i+j) *
560 m_theta[j] * m_phi[i+1]/m_theta[m_size];
561 }
562 }
563 }
564 }
565 private:
567 int sign(unsigned i)
568 {
569 if (i%2==0) return 1;
570 else return -1;
571 }
572 ContainerType m_phi, m_theta;
573 unsigned m_size;
574};
575
587template<class value_type>
588void invert(const cusp::dia_matrix<int,value_type,cusp::host_memory>& T,
589 cusp::coo_matrix<int,value_type,cusp::host_memory>& Tinv)
590{
591 using HCooMatrix = cusp::coo_matrix<int, value_type, cusp::host_memory>;
592 using HDiaMatrix = cusp::dia_matrix<int, value_type, cusp::host_memory>;
593 using HVec = dg::HVec;
594 return TridiagInvDF<HVec,HDiaMatrix,HCooMatrix>( T.num_rows)(T, Tinv);
595}
607template<class value_type>
608cusp::coo_matrix<int,value_type,cusp::host_memory> invert(
609 const cusp::dia_matrix<int,value_type,cusp::host_memory>& T)
610{
611 using HCooMatrix = cusp::coo_matrix<int, value_type, cusp::host_memory>;
612 using HDiaMatrix = cusp::dia_matrix<int, value_type, cusp::host_memory>;
613 using HVec = dg::HVec;
614 return TridiagInvDF<HVec,HDiaMatrix,HCooMatrix>( T.num_rows)(T);
615}
616
630template<class value_type>
631std::array<value_type, 2> compute_extreme_EV( const cusp::dia_matrix<int,value_type, cusp::host_memory>& T)
632{
633 unsigned size = T.num_rows;
634 cusp::array2d< value_type, cusp::host_memory> evecs;
635 cusp::array1d< value_type, cusp::host_memory> evals(size);
636 cusp::lapack::stev(T.values.column(1), T.values.column(2),
637 evals, evecs, 'N');
638 value_type EVmax = dg::blas1::reduce( evals, 0., dg::AbsMax<value_type>());
639 value_type EVmin = dg::blas1::reduce( evals, EVmax, dg::AbsMin<value_type>());
640 return std::array<value_type, 2>{EVmin, EVmax};
641}
642
643
645
646} // namespace mat
647} // namespace dg
USE THIS ONE Compute the inverse of a general tridiagonal matrix. The algorithm does not rely on the ...
Definition: tridiaginv.h:272
void resize(unsigned new_size)
Resize inverse tridiagonal matrix and helper vectors.
Definition: tridiaginv.h:304
TridiagInvDF(unsigned size)
Construct from size of vector.
Definition: tridiaginv.h:293
void operator()(const ContainerType0 &a, const ContainerType1 &b, const ContainerType2 &c, CooMatrix &Tinv)
Compute the inverse of a tridiagonal matrix with diagonal vectors a,b,c.
Definition: tridiaginv.h:347
CooMatrix operator()(const DiaMatrix &T)
Compute the inverse of a tridiagonal matrix T.
Definition: tridiaginv.h:330
void operator()(const DiaMatrix &T, CooMatrix &Tinv)
Compute the inverse of a tridiagonal matrix T.
Definition: tridiaginv.h:316
TridiagInvDF()
Allocate nothing, Call construct method before usage.
Definition: tridiaginv.h:276
TridiagInvDF(const ContainerType &copyable)
Construct from vector.
Definition: tridiaginv.h:282
dg::get_value_type< ContainerType > value_type
Definition: tridiaginv.h:274
Compute the inverse of a general tridiagonal matrix.
Definition: tridiaginv.h:436
void operator()(const DiaMatrix &T, CooMatrix &Tinv)
Compute the inverse of a tridiagonal matrix T.
Definition: tridiaginv.h:480
TridiagInvD()
Allocate nothing, Call construct method before usage.
Definition: tridiaginv.h:440
TridiagInvD(const ContainerType &copyable)
Construct from vector.
Definition: tridiaginv.h:446
dg::get_value_type< ContainerType > value_type
Definition: tridiaginv.h:438
void operator()(const ContainerType0 &a, const ContainerType1 &b, const ContainerType2 &c, CooMatrix &Tinv)
Compute the inverse of a tridiagonal matrix with diagonal vectors a,b,c.
Definition: tridiaginv.h:511
CooMatrix operator()(const DiaMatrix &T)
Compute the inverse of a tridiagonal matrix T.
Definition: tridiaginv.h:494
TridiagInvD(unsigned size)
Construct from size of vector.
Definition: tridiaginv.h:457
void resize(unsigned new_size)
Resize inverse tridiagonal matrix and helper vectors.
Definition: tridiaginv.h:468
Compute the inverse of a general tridiagonal matrix.
Definition: tridiaginv.h:95
dg::get_value_type< ContainerType > value_type
Definition: tridiaginv.h:97
TridiagInvHMGTI()
Allocate nothing, Call construct method before usage.
Definition: tridiaginv.h:99
void resize(unsigned new_size)
Resize inverse tridiagonal matrix and helper vectors.
Definition: tridiaginv.h:127
CooMatrix operator()(const DiaMatrix &T)
Compute the inverse of a tridiagonal matrix T.
Definition: tridiaginv.h:153
void operator()(const ContainerType0 &a, const ContainerType1 &b, const ContainerType2 &c, CooMatrix &Tinv)
Compute the inverse of a tridiagonal matrix with diagonal vectors a,b,c.
Definition: tridiaginv.h:170
TridiagInvHMGTI(unsigned size)
Construct from size of vector.
Definition: tridiaginv.h:116
TridiagInvHMGTI(const ContainerType &copyable)
Construct from vector.
Definition: tridiaginv.h:105
void operator()(const DiaMatrix &T, CooMatrix &Tinv)
Compute the inverse of a tridiagonal matrix T.
Definition: tridiaginv.h:139
#define _ping_
OutputType reduce(const ContainerType &x, OutputType zero, BinaryOp binary_op, UnaryOp unary_op=UnaryOp())
value_type compute_Tinv_m1(const cusp::dia_matrix< int, value_type, cusp::host_memory > &T, unsigned size)
Computes the value of via a Thomas algorithm.
Definition: tridiaginv.h:32
std::array< value_type, 2 > compute_extreme_EV(const cusp::dia_matrix< int, value_type, cusp::host_memory > &T)
Compute extreme Eigenvalues of a symmetric tridiangular matrix.
Definition: tridiaginv.h:631
void compute_Tinv_y(const cusp::dia_matrix< int, value_type, cusp::host_memory > &T, thrust::host_vector< value_type > &x, const thrust::host_vector< value_type > &y, value_type a=1., value_type d=0.)
Computes the value of via Thomas algorithm.
Definition: tridiaginv.h:58
void invert(const cusp::dia_matrix< int, value_type, cusp::host_memory > &T, cusp::coo_matrix< int, value_type, cusp::host_memory > &Tinv)
Invert a tridiagonal matrix.
Definition: tridiaginv.h:588
typename TensorTraits< std::decay_t< Vector > >::value_type get_value_type
thrust::host_vector< double > HVec
Classes for Krylov space approximations of a Matrix-Vector product.