Extension: Matrix functions
#include "dg/matrix/matrix.h"
Loading...
Searching...
No Matches
outer.h
Go to the documentation of this file.
1#pragma once
2
3
4#include <vector>
5#include "dg/algorithm.h"
6#include "tridiaginv.h" // lapack wrapper
7
8namespace dg{
9namespace mat{
10
12template<class index_type, class value_type>
14{
15 if( mat.num_rows() != mat.num_cols())
16 throw dg::Error( dg::Message( _ping_) << "Cannot convert non square sparse matrix with "<<mat.num_rows()<<" rows and "<<mat.num_cols()<<" columns\n");
18 for( unsigned row=0; row<mat.num_rows(); row++)
19 for( index_type jj = mat.row_offsets()[row]; jj< mat.row_offsets()[row+1]; jj++)
20 {
21 index_type col = mat.column_indices()[jj];
22 value_type val = mat.values()[jj];
23 out( row, col ) = val;
24 }
25 return out;
26}
27
35template<class value_type>
36std::array<dg::SquareMatrix<value_type>,2> sym_laplace1d(
37 const thrust::host_vector<value_type>& volume,
39 direction dir = forward,
40 value_type jfactor = 1.)
41{
42
43 auto w1d = dg::create::weights( g1d);
44 dg::SquareMatrix<value_type> VOL ( volume.size()), W1D( volume.size());
45 for( unsigned u=0; u<volume.size(); u++)
46 {
47 VOL(u,u) = volume[u];
48 W1D(u,u) = w1d[u];
49 }
50 auto leftx = asSquareMatrix( dg::create::dx( g1d, inverse( bcx), inverse(dir) ).asCuspMatrix() );
51 auto rightx = asSquareMatrix( dg::create::dx( g1d, bcx, dir).asCuspMatrix());
52 auto jumpx = asSquareMatrix( dg::create::jumpX(g1d, bcx).asCuspMatrix());
53
54 std::array<dg::SquareMatrix<value_type>,2> out;
55 out[0] = W1D * (- leftx * (VOL * rightx) + jfactor*jumpx); // get symmetric part of A
56 dg::blas1::pointwiseDot( W1D.data(), VOL.data(), W1D.data());
57 out[1] = W1D;
58 return out;
59}
60
61template< class ContainerType>
62struct LaplaceDecomposition
63{
65
67 LaplaceDecomposition() = default;
68 LaplaceDecomposition( RealGrid2d<value_type> g, bc bcx, bc bcy,
69 direction dir = forward,
70 value_type jfactor=1.)
71 {
72 m_v = m_f = m_weights = dg::create::weights( g);
73 auto lapX = sym_laplace1d(dg::evaluate( dg::one, g.gx()), g.gx(), bcx,
74 dir, jfactor);
75 unsigned Nx = g.gx().size();
76 m_EX.resize( Nx);
77 thrust::host_vector<value_type> work( 3*Nx-1);
78 lapack::sygv( 1, 'V', 'U', Nx, lapX[0].data(), Nx, lapX[1].data(), Nx, m_EX, work);
79 // Eigenvalues are sorted in ascending order
80 // now convert to device vectors
81 m_VX.resize( Nx);
82 for( unsigned i=0; i<Nx; i++)
83 {
84 dg::HVec temp(Nx);
85 for( unsigned u=0; u<Nx; u++)
86 temp[u] = lapX[0](i, u); // i-th row of lapX[0] is i-th Eigenvector
87 dg::assign( temp, m_VX[i]);
88 }
89 // orthogonality is maintained with off-diagonal elements of order 1e-16
90 //ContainerType w1d = dg::create::weights( g.gx());
91 //for( unsigned i=0; i<m_EX.size(); i++)
92 //{
93 // std::cout << std::endl;
94 // for( unsigned j=0; j<m_EX.size(); j++)
95 // std::cout << dg::blas2::dot( m_VX[i], w1d, m_VX[j])<<" ";
96 //}
97
98 auto lapY = sym_laplace1d(dg::evaluate( dg::one, g.gy()), g.gy(), bcy,
99 dir, jfactor);
100 unsigned Ny = g.gy().size();
101 m_EY.resize( Ny);
102 work.resize( 3*Ny-1);
103 lapack::sygv( 1, 'V', 'U', Ny, lapY[0].data(), Ny, lapY[1].data(), Ny, m_EY, work);
104 // Eigenvalues are sorted in ascending order
105 // now convert to device vectors
106 m_VY.resize( Ny);
107 for( unsigned i=0; i<Nx; i++)
108 {
109 dg::HVec temp(Ny);
110 for( unsigned u=0; u<Ny; u++)
111 temp[u] = lapY[0](i, u); // i-th row of lapY[0] is i-th Eigenvector
112 dg::assign( temp, m_VY[i]);
113 }
114 // Get the sorted indices of Eigenvalues
115 thrust::host_vector<value_type> evs( m_EY.size()*m_EX.size());
116 thrust::host_vector<unsigned> idx( evs.size());
117 thrust::sequence( idx.begin(), idx.end());
118 for( unsigned i=0; i<evs.size(); i++)
119 evs[i] = m_EY[i/m_EX.size()] + m_EX[i%m_EX.size()];
120 thrust::stable_sort_by_key( evs.begin(), evs.end(), idx.begin());
121 m_idx = idx;
122 //for( unsigned i=0; i<idx.size(); i++)
123 // std::cout << "("<<idx[i]%m_EX.size()<<","<<idx[i]/m_EX.size()<<") ";
124 //std::cout << std::endl;
125 }
126 // f(Lap)b
127 template<class ContainerType0, class UnaryOp,
128 class ContainerType1>
129 unsigned matrix_function(
130 ContainerType0& x,
131 UnaryOp op,
132 const ContainerType1& b,
133 value_type eps,
134 value_type nrmb_correction = 1.)
135 {
136 unsigned size = m_idx.size(), Nx = m_EX.size();
137 value_type normb = sqrt( dg::blas2::dot( b, m_weights, b));
138 value_type normx2 = 0.;
139 dg::blas1::copy( 0, x);
140 for( unsigned i=0; i<size; i++)
141 {
142 unsigned ix = m_idx[i]%Nx, iy = m_idx[i]/Nx;
143 value_type alpha = op(m_EX[ix]+m_EY[iy]);
144 if( alpha*normb <= eps*(sqrt(normx2)+nrmb_correction))
145 return i;
146 //func(lambda_i)*(vyXVx)_i .dot ( Mb) (vyXVx)_i
147 dg::blas1::kronecker( m_v, dg::equals(), dg::Product(), m_VX[ix], m_VY[iy]);
148 alpha*=dg::blas2::dot( m_v, b, m_weights);
149 dg::blas1::axpby( alpha, m_v, 1., x);
150 normx2 += alpha*alpha;
151 }
152 return size;
153 }
154 // f(Lap, diag)b
155 template<class ContainerType0, class BinaryOp,
156 class ContainerType1, class ContainerType2>
157 unsigned product_function_adjoint(
158 ContainerType0& x,
159 BinaryOp op,
160 const ContainerType1& diag,
161 const ContainerType2& b,
162 value_type eps,
163 value_type nrmb_correction = 1.)
164 {
165 unsigned size = m_idx.size(), Nx = m_EX.size();
166 value_type normb = sqrt( dg::blas2::dot( b, m_weights, b));
167 value_type dmin = dg::blas1::reduce( diag, (value_type)1e50, thrust::minimum<value_type>());
168 value_type normx2 = 0.;
169 dg::blas1::copy( 0, x);
170 for( unsigned i=0; i<size; i++)
171 {
172 unsigned ix = m_idx[i]%Nx, iy = m_idx[i]/Nx;
173 value_type err = normb*op(m_EX[ix] + m_EY[iy], dmin)*sqrt(size);
174 //std::cout << "Eigenvalue "<<(m_EX[i%Nx]+m_EY[i/Nx])<<"\n";
175 //std::cout << "alpha "<<op(m_EX[i%Nx]+m_EY[i/Nx], dmin)<<"\n";
176 //std::cout << "normx2 "<<normx2<<"\n";
177 if( err <= eps*(sqrt(normx2)+nrmb_correction))
178 return i;
179 //func( d, lambda_ij)*(vyXVx)_ij .dot ( Mx) (vyXVx)_ij
180 dg::blas1::kronecker( m_v, dg::equals(), dg::Product(), m_VX[ix], m_VY[iy]);
181 dg::blas1::evaluate( m_f, dg::equals(), op, m_EX[ix] + m_EY[iy], diag);
182 dg::blas1::pointwiseDot( m_f, m_v, m_f);
183 value_type gamma = dg::blas2::dot( m_f, b, m_weights);
184 dg::blas1::axpby( gamma, m_v, 1., x);
185 normx2 += gamma*gamma;
186 }
187 return size;
188 }
189 // f(diag, Lap)b
190 // is this faster than Lanczos?
191 template<class ContainerType0, class BinaryOp,
192 class ContainerType1, class ContainerType2>
193 unsigned product_function(
194 ContainerType0& x,
195 BinaryOp op,
196 const ContainerType1& diag,
197 const ContainerType2& b,
198 value_type eps,
199 value_type nrmb_correction = 1.)
200 {
201 unsigned size = m_idx.size(), Nx = m_EX.size();
202 value_type normb = sqrt( dg::blas2::dot( b, m_weights, b));
203 value_type dmin = dg::blas1::reduce( diag, (value_type)1e50, thrust::minimum<value_type>());
204 dg::blas1::copy( 0, x);
205 for( unsigned i=0; i<size; i++)
206 {
207 unsigned ix = m_idx[i]%Nx, iy = m_idx[i]/Nx;
208 value_type err = normb*op(dmin, m_EX[ix] + m_EY[iy])*sqrt(size);
209 value_type normx = sqrt(dg::blas2::dot( x, m_weights, x));
210 if( err <= eps*(normx+nrmb_correction))
211 return i;
212
213 //func( d, lambda_i)*(vyXVx)_i .dot ( Mx) (vyXVx)_i
214 dg::blas1::kronecker( m_v, dg::equals(), dg::Product(), m_VX[ix], m_VY[iy]);
215 value_type beta = dg::blas2::dot( m_v, b, m_weights);
216 dg::blas1::evaluate( m_f, dg::equals(), op, diag, m_EX[ix] + m_EY[iy]);
217 dg::blas1::pointwiseDot( beta, m_f, m_v, 1., x);
218 }
219 return size;
220 }
221 private:
222 thrust::host_vector<value_type> m_EX, m_EY;
223 std::vector<ContainerType> m_VX, m_VY;
224 ContainerType m_weights, m_v, m_f;
225 thrust::host_vector<unsigned> m_idx;
226};
228
229
230} // namespace mat
231} // namespace dg
DG_DEVICE T one(T, Ts ...)
void copy(const ContainerTypeIn &source, ContainerTypeOut &target)
void axpby(value_type alpha, const ContainerType1 &x, value_type1 beta, ContainerType &y)
void pointwiseDot(value_type alpha, const ContainerType1 &x1, const ContainerType2 &x2, value_type1 beta, ContainerType &y)
OutputType reduce(const ContainerType &x, OutputType zero, BinaryOp binary_op, UnaryOp unary_op=UnaryOp())
void evaluate(ContainerType &y, BinarySubroutine f, Functor g, const ContainerType0 &x0, const ContainerTypes &...xs)
void assign(const from_ContainerType &from, ContainerType &to, Params &&... ps)
void kronecker(ContainerType0 &y, BinarySubroutine f, Functor g, const ContainerType1 &x0, const ContainerTypes &...xs)
auto dot(const ContainerType1 &x, const MatrixType &m, const ContainerType2 &y)
auto dx(const Topology &g, dg::bc bc, dg::direction dir=centered)
direction
bc inverse(bc bound)
auto jumpX(const Topology &g, bc bc)
typename TensorTraits< std::decay_t< Vector > >::value_type get_value_type
auto weights(const Topology &g)
auto evaluate(Functor &&f, const Topology &g)
dg::RealGrid< T, 1 > RealGrid1d
Geometry::host_vector volume(const Geometry &g)
thrust::host_vector< double > HVec
dg::bc bcy
Definition lanczos_b.cpp:10
dg::bc bcx
Definition lanczos_b.cpp:9
const double alpha
Definition lanczos_b.cpp:11
Functions for optimizing Contours.
const double beta
Definition polarization_b.cpp:10
size_t & num_cols()
const Vector< Index > & row_offsets() const
size_t & num_rows()
const Vector< Index > & column_indices() const
const Vector< Value > & values() const
double value_type
Definition tridiaginv_b.cpp:6