1 /*
2 XLiFE++ is an extended library of finite elements written in C++
3 Copyright (C) 2014 Lunéville, Eric; Kielbasiewicz, Nicolas; Lafranche, Yvon; Nguyen, Manh-Ha; Chambeyron, Colin
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 /*!
18 \file Operand.hpp
19 \author E. Lunéville
20 \since 02 mar 2012
21 \date 4 may 2012
22
23 \brief Definition of the xlifepp::Operand class
24
25 Class xlifepp::Operand describes a couple (object, operation) where object is either an xlifepp::OperatorOnFunction,
26 xlifepp::OperatorOnKernel or a xlifepp::Value (scalar, xlifepp::Vector, xlifepp::Matrix constant) and operation is an
27 algebraic operator such as Fun* or *Fun or Mat*F ...
28
29 It is used by xlifepp::OperatorOnUnknown class.
30 Normally, end users has not to deal explicitly with this class
31
32 this class stores the couple (object,operation)
33 - when object is a xlifepp::Value, in a pointer to a Value
34 - when object is a xlifepp::OperatorOnFunction, in a pointer to a xlifepp::OperatorOnFunction
35 - when object is a xlifepp::OperatorOnKernel, in a pointer to a xlifepp::OperatorOnKernel,
36
37 and the algebraic operation, one among :
38 - standard product (operator *)
39 - inner product (operator |)
40 - cross product (operator ^)
41 - contracted product (operator %)
42
43 Besides, this class stores possibly additionnal operations such has conjugate and transpose
44 For instance, one may have the following syntaxes (F a function, V a value):
45 \verbatim
46 conj(F)* or *conj(F) or tran(V)^ ...
47 (conj() and tran() are functions defined in Function.hpp and Value.hpp)
48 \endverbatim
49 */
50
51 #ifndef OPERAND_HPP
52 #define OPERAND_HPP
53
54 #include "config.h"
55 #include "space.h"
56 #include "utils.h"
57 #include "OperatorOnKernel.hpp"
58 #include "OperatorOnFunction.hpp"
59
60 namespace xlifepp
61 {
62
63 enum AlgebraicOperator {_product, _innerProduct, _crossProduct, _contractedProduct};
64
65 /*!
66 \class Operand
67 to deal with syntax Value AlgebraicOperation
68 */
69 class Operand
70 {
71 protected :
72 const Value* val_p; //!< pointer to operand object (a Value)
73 OperatorOnFunction* opfun_p; //!< pointer to OperatorOnFunction object
74 OperatorOnKernel* opker_p; //!< pointer to OperatorOnKernel object
75 AlgebraicOperator operation_; //!< operand operator
76 dimPair dims_; //!< dimension of value or function, (1,1) by default
77
78 public :
79 mutable bool conjugate_; //!< true if the operand has to be conjugated
80 mutable bool transpose_; //!< true if the operand has to be transposed
81
82 public :
83 // constructors-destructor
84 Operand(const OperatorOnFunction&, AlgebraicOperator); //!< construct Operand from a OperatorOnFunction
85 Operand(const OperatorOnKernel&, AlgebraicOperator); //!< construct Operand from a OperatorOnKernel
86 Operand(OperatorOnKernel&, AlgebraicOperator); //!< construct Operand from a OperatorOnKernel
87 Operand(const Function&, AlgebraicOperator); //!< construct Operand from a Function (id on Function)
88 Operand(const Kernel&, AlgebraicOperator); //!< construct Operand from a Kernel (id on Function)
89 Operand(const Value&, AlgebraicOperator); //!< construct Operand from a Value (Value is copied)
90 Operand(const Value*, AlgebraicOperator); //!< construct Operand from a Value* (Value is not copied)
91 template <typename T>
92 Operand(const T&, AlgebraicOperator); //!< construct Operand from a scalar, a Vector or a Matrix
93 Operand(const Operand&); //!< copy construct
94 Operand& operator = (const Operand&); //!< assign operator
~Operand()95 ~Operand() //! destructor
96 {clear();}
97 void copy(const Operand&); //!< copy tool
98 void clear(); //!< delete allocated pointers and reset pointers to 0
99
100 // accessors
operation() const101 AlgebraicOperator operation() const //! returns algebraic operation
102 {return operation_;}
dims() const103 dimPair dims() const //! returns dimensions
104 {return dims_;}
105
isFunction() const106 bool isFunction() const //! true if operand with function
107 {return opfun_p!=0;}
isKernel() const108 bool isKernel() const //! true if operand with kernel
109 {return opker_p!=0;}
isValue() const110 bool isValue() const //! true if operand with value
111 {return val_p!=0;}
112 ValueType valueType() const; //!< return value type of value or function
113 StrucType strucType() const; //!< return structure type of value or function
114 bool normalRequired() const; //!< true if normal involved
115 bool xnormalRequired() const; //!< true if xnormal involved
116 bool ynormalRequired() const; //!< true if ynormal involved
117 bool elementRequired() const; //!< true if element is required by any function in
118
setX(const Point & P) const119 void setX(const Point& P) const //! set X point if Function involved (usefull for Kernel)
120 {if(opfun_p!=0) opfun_p->setX(P);if(opker_p!=0) opker_p->setX(P);}
setY(const Point & P) const121 void setY(const Point& P) const //! set Y point if Function involved (usefull for Kernel)
122 {if(opfun_p!=0) opfun_p->setY(P);if(opker_p!=0) opker_p->setY(P);}
123 // void setN(const Vector<real_t>* np) const //! set normal pointer if function involved (not for Kernel)
124 // {if(opfun_p!=0) opfun_p->setN(np);}
125
126 const Value& value() const; //!< return the operand value as object
127 // const Value& value(); //!< return the operand value as object
128 Value& value(); //!< return the operand value as object
129 const OperatorOnFunction& opfunction() const; //!< return operand object as operator on function
130 const OperatorOnKernel& opkernel() const; //!< return operand object as operator on kernel
opfunctionp() const131 const OperatorOnFunction* opfunctionp() const //! return operand object as pointer to operator on function
132 {return opfun_p;}
opkernelp() const133 const OperatorOnKernel* opkernelp() const //! return operand object as pointer to operator on kernel
134 {return opker_p;}
135 const Function& function() const; //!< return operand object as function
136 const Kernel& kernel() const; //!< return operand object as kernel
functionp() const137 const Function* functionp() const //! return pointer to function (0 if not)
138 {if(opfun_p!=0) return opfun_p->funp(); else return 0;}
kernelp() const139 const Kernel* kernelp() const //! return pointer to kernel (0 if not)
140 {if(opker_p!=0) return opker_p->kernelp(); else return 0;}
changeKernel(Kernel * ker)141 void changeKernel(Kernel* ker) //! change Kernel in operator
142 {if(opker_p!=0) opker_p->changeKernel(ker);}
hasExtension() const143 bool hasExtension() const //! true if opfun or opker handle an extension
144 {if ((opfun_p!=0 && opfun_p->ext_p!=0) || (opker_p!=0 && opker_p->ext_p!=0)) return true;
145 return false;}
extension() const146 const Extension* extension() const //! return extension
147 {
148 if(opfun_p!=0) return opfun_p->ext_p;
149 if(opker_p!=0) return opker_p->ext_p;
150 return 0;
151 }
152
153 template<class T> T& valueT() const; //!< return operand object as value of T type
154 template<class T>
155 T& value(T&, const Point&, const Vector<real_t>* np=0, const ExtensionData* =0) const; //!< compute value function
156 template<class T>
157 T& value(T&, const Point&, const Point&, const Vector<real_t>* nxp=0, const Vector<real_t>* nyp=0) const; //!< compute value kernel
158 template<class T>
159 T& value(T&) const; //!< return const value
160
161 template<typename T, typename R>
162 Vector<T> leftEval(const Vector<R>&, dimen_t&, dimen_t&, number_t) const; //!< evaluate value operand at left
163 template<typename T, typename R>
164 Vector<T> rightEval(const Vector<R>&, dimen_t&, dimen_t&, number_t) const; //!< evaluate value operand at right
165 template<typename T, typename R>
166 Vector<T> leftEval(const Point&, const Vector<R>&, dimen_t&, dimen_t&, number_t,
167 const Vector<real_t>* =0, const ExtensionData* =0) const; //!< evaluate function operand at left
168 template<typename T, typename R>
169 Vector<T> rightEval(const Point&, const Vector<R>&, dimen_t&, dimen_t&, number_t,
170 const Vector<real_t>* =0, const ExtensionData* =0) const; //!< evaluate function operand at right
171 template<typename T, typename R>
172 Vector<T> leftEval(const Point&, const Point&, const Vector<R>&, dimen_t&, dimen_t&, number_t,
173 const Vector<real_t>* =0, const Vector<real_t>* =0) const; //!< evaluate kernel operand at left
174 template<typename T, typename R>
175 Vector<T> rightEval(const Point&,const Point&, const Vector<R>&, dimen_t&, dimen_t&, number_t,
176 const Vector<real_t>* =0, const Vector<real_t>* =0) const; //!< evaluate kernel operand at right
177
178 void print(std::ostream&) const; //!< print Operand attributes
print(PrintStream & os) const179 void print(PrintStream& os) const {print(os.currentStream());} //!< print Operand attributes
180 void printsymbolic(std::ostream&) const; //!< print Operand in symbolic form
printsymbolic(PrintStream & os) const181 void printsymbolic(PrintStream& os) const {printsymbolic(os.currentStream());} //!< print Operand in symbolic form
182 string_t asString() const; //!< return as symbolic string
183 };
184
185 // external Operand functions
186 bool operator==(const Operand&,const Operand&); //!< compare Operands
187 bool operator!=(const Operand&,const Operand&); //!< compare Operands
188 std::ostream& operator<<(std::ostream&, const Operand&); //!< outputs Operand attributes
189
190 // implementation of template member functions
191 // constructor from a scalar, a vector or a matrix, ...
192 template <typename T>
Operand(const T & v,AlgebraicOperator aop)193 Operand::Operand(const T& v, AlgebraicOperator aop)
194 {
195 operation_ = aop;
196 conjugate_ = false;
197 transpose_ = false;
198 opfun_p = 0;
199 opker_p = 0;
200 // check type of v
201 Value::checkTypeInList(v);
202 val_p = new Value(v);
203 }
204
205 // return the value in a operand
206 template<typename T> inline
valueT() const207 T& Operand::valueT() const
208 {
209 if(val_p == 0)
210 {
211 where("Operand::valueT()");
212 error("operand_notavalue");
213 }
214 return val_p->value<T>();
215 }
216
217 // compute value function
218 // T has to be compliant with function return type, no check !!!
219 template<typename T> inline
value(T & val,const Point & pt,const Vector<real_t> * np,const ExtensionData * extdata) const220 T& Operand::value(T& val, const Point& pt, const Vector<real_t>* np, const ExtensionData* extdata) const
221 {
222 if(opfun_p!=0) return opfun_p->eval(pt, val, np, extdata);
223 if(opker_p!=0)
224 {
225 if(opker_p->kernelp()->xpar) return opker_p->eval(pt, val, 0, np);
226 else return opker_p->eval(pt, val, np, 0);
227 }
228 return val; // dummy return
229 }
230
231 // compute value kernel
232 // T has to be compliant with kernel return type, no check !!!
233 template<typename T> inline
value(T & val,const Point & p,const Point & q,const Vector<real_t> * nxp,const Vector<real_t> * nyp) const234 T& Operand::value(T& val, const Point& p, const Point& q, const Vector<real_t>* nxp, const Vector<real_t>* nyp) const
235 {
236 return opker_p->eval(p, q, val, nxp, nyp);
237 }
238
239 // return const value,
240 // T has to be compliant with value,no check !!!
241 template<typename T> inline
value(T & val) const242 T& Operand::value(T& val) const
243 {
244 val = val_p->value<T>();
245 return val;
246 }
247
248 //@{
249 //!for template compilation reasons, fake definition of dot and crossproduct in 1D
250 real_t dot(const real_t& x, const real_t& y);
251 complex_t dot(const complex_t& x, const complex_t& y);
252 complex_t dot(const complex_t& x, const real_t& y);
253 complex_t dot(const real_t& x, const complex_t& y);
254 real_t crossProduct(const real_t& x, const real_t& y);
255 complex_t crossProduct(const complex_t& x, const complex_t& y);
256 complex_t crossProduct(const complex_t& x, const real_t& y);
257 complex_t crossProduct(const real_t& x, const complex_t& y);
258 //@}
259
260 /*-------------------------------------------------------------------------------------
261 evaluate Operand
262 -------------------------------------------------------------------------------------*/
263
264 //@{
265 //! Product by a scalar
266 template<typename T, typename R> inline
evalScalarProduct(const T & val,const Vector<R> & v,Vector<T> & res)267 void evalScalarProduct(const T& val, const Vector<R>& v, Vector<T>& res)
268 {
269 // val is a scalar and v a sequence of anything
270 typename std::vector<R>::const_iterator itv=v.begin();
271 res.resize(v.size());
272 typename std::vector<T>::iterator itr=res.begin();
273 for(; itv != v.end(); itv++, itr++) *itr = val * * itv;
274 }
275
276 template<>
evalScalarProduct(const real_t & val,const Vector<complex_t> & v,Vector<real_t> & res)277 inline void evalScalarProduct(const real_t& val, const Vector<complex_t>& v, Vector<real_t>& res)
278 {
279 error("not_handled","evalScalarProduct(Real, Vector<Complex>, Vector<Real>)");
280 }
281
282 template<typename T, typename R> inline
evalScalarProduct(const Vector<T> & vec,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,Vector<T> & res)283 void evalScalarProduct(const Vector<T>& vec, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m, Vector<T>& res)
284 {
285 // val is a vector or a matrix and v a sequence of scalar
286 d=vec.size();
287 res.resize(m*d);
288 n=1;
289 typename std::vector<R>::const_iterator itv=v.begin();
290 typename std::vector<T>::iterator itr=res.begin();
291 typename std::vector<T>::const_iterator itvec;
292 for(number_t k = 0; k < m; k++, itv ++)
293 {
294 itvec=vec.begin();
295 for(number_t i=0; i<d; i++, itr++, itvec++) *itr = *itv * *itvec;
296 }
297 }
298
299 template<>
evalScalarProduct(const Vector<real_t> & vec,const Vector<complex_t> & v,dimen_t & d,dimen_t & n,number_t m,Vector<real_t> & res)300 inline void evalScalarProduct(const Vector<real_t>& vec, const Vector<complex_t>& v, dimen_t& d, dimen_t& n, number_t m, Vector<real_t>& res)
301 {
302 error("not_handled","evalScalarProduct(Vector<Real>, Vector<Complex>, Dimen, Dimen, Number, Vector<Real>)");
303 }
304
305 template<typename T, typename R> inline
evalScalarProduct(const Matrix<T> & mat,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,Vector<T> & res)306 void evalScalarProduct(const Matrix<T>& mat, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m, Vector<T>& res)
307 {
308 // val is a vector or a matrix and v a sequence of scalar
309 d=mat.size();
310 res.resize(m*d);
311 n=mat.numberOfColumns();
312 typename std::vector<R>::const_iterator itv=v.begin();
313 typename std::vector<T>::iterator itr=res.begin();
314 typename std::vector<T>::const_iterator itmat;
315 for(number_t k = 0; k < m; k++, itv ++)
316 {
317 itmat=mat.begin();
318 for(number_t i=0; i<d; i++, itr++, itmat++) *itr = *itv * *itmat;
319 }
320 }
321
322 template<>
evalScalarProduct(const Matrix<real_t> & mat,const Vector<complex_t> & v,dimen_t & d,dimen_t & n,number_t m,Vector<real_t> & res)323 inline void evalScalarProduct(const Matrix<real_t>& mat, const Vector<complex_t>& v, dimen_t& d, dimen_t& n, number_t m, Vector<real_t>& res)
324 {
325 error("not_handled","evalScalarProduct(Matrix<Real>, Vector<Complex>, Dimen, Dimen, Number, Vector<Real>)");
326 }
327 //@}
328
329 //@{
330 //! Inner product
331 template<typename T, typename R>
evalInnerProduct(const Vector<T> & vec,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,Vector<T> & res)332 void evalInnerProduct(const Vector<T>& vec, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m, Vector<T>& res)
333 {
334 // vec is a vector and v a sequence of vectors of size > val.size()
335 typename std::vector<R>::const_iterator itv=v.begin();
336 res.resize(m);
337 typename std::vector<T>::iterator itr=res.begin();
338 for(number_t k = 0; k < m; k++, itr++, itv += d)
339 {
340 T zero(0);
341 *itr = std::inner_product(vec.begin(), vec.end(), itv, zero);
342 }
343 d=1;
344 n=1; //new block size
345 }
346
347 template<>
evalInnerProduct(const Vector<real_t> & vec,const Vector<complex_t> & v,dimen_t & d,dimen_t & n,number_t m,Vector<real_t> & res)348 inline void evalInnerProduct(const Vector<real_t>& vec, const Vector<complex_t>& v, dimen_t& d, dimen_t& n, number_t m, Vector<real_t>& res)
349 {
350 error("not_handled","evalInnerProduct(Vector<Real>, Vector<Complex>, Dimen, Dimen, Number, Vector<Real>)");
351 }
352 //@}
353
354 //@{
355 //! Cross product
356 template<typename T, typename R>
evalCrossProduct(const Vector<T> & vec,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,Vector<T> & res,bool right)357 void evalCrossProduct(const Vector<T>& vec, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m, Vector<T>& res, bool right)
358 {
359 // vec is a vector and v a sequence of vectors of size > val.size()
360 typename std::vector<R>::const_iterator itv;
361 typename std::vector<T>::iterator itr, itr2;
362 dimen_t s = 1;
363 if(d == 3) s = 3; //3D
364 res.resize(m * s);
365 itr = res.begin();
366 itv = v.begin();
367 for(number_t k = 0; k < m; k++, itv += d)
368 {
369 itr2=itr;
370 crossProduct(vec, itv, itr);
371 itr++; //the last is not incremented in crossProduct
372 if(right)
373 for(number_t j = 0; j < s; j++, itr2++) *itr2 *= -1; //reverse sign v x u = -u x v
374 }
375 d=s;
376 n=1; //new block size
377 }
378
379 template<>
evalCrossProduct(const Vector<real_t> & vec,const Vector<complex_t> & v,dimen_t & d,dimen_t & n,number_t m,Vector<real_t> & res,bool right)380 inline void evalCrossProduct(const Vector<real_t>& vec, const Vector<complex_t>& v, dimen_t& d, dimen_t& n, number_t m, Vector<real_t>& res, bool right)
381 {
382 error("not_handled","evalCrossProduct(Vector<Real>, Vector<Complex>, Dimen, Dimen, Number, Vector<Real>)");
383 }
384 //@}
385
386 //@{
387 //! Matrix product
388 template<typename T, typename R> inline
evalMatrixVectorProduct(const Matrix<T> & mat,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,Vector<T> & res)389 void evalMatrixVectorProduct(const Matrix<T>& mat, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m, Vector<T>& res)
390 {
391 // mat is a matrix nbr x nbc and v a sequence of m vectors of size d >= nbc (n should be 1)
392 dimen_t s = mat.numberOfRows();
393 res.resize(m * s);
394 typename std::vector<R>::const_iterator itv=v.begin();
395 typename std::vector<T>::iterator itr=res.begin();
396 for(number_t k = 0; k < m; k++, itr += s, itv += d)
397 matvec(mat.begin(), itv, itv + d, itr, itr + s);
398 d=s; n=1; //new block size
399 }
400
401 template<>
evalMatrixVectorProduct(const Matrix<real_t> & mat,const Vector<complex_t> & v,dimen_t & d,dimen_t & n,number_t m,Vector<real_t> & res)402 inline void evalMatrixVectorProduct(const Matrix<real_t>& mat, const Vector<complex_t>& v, dimen_t& d, dimen_t& n, number_t m, Vector<real_t>& res)
403 {
404 error("not_handled","evalMatrixVectorProduct(Matrix<Real>, Vector<Complex, Dimen, Dimen, Number, Vector<Real>)");
405 }
406
407 template<typename T, typename R> inline
evalVectorMatrixProduct(const Matrix<T> & mat,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,Vector<T> & res)408 void evalVectorMatrixProduct(const Matrix<T>& mat, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m, Vector<T>& res)
409 {
410 // mat is a matrix and v a sequence of vectors of size >= number of matrix rows
411 dimen_t s = mat.numberOfColumns();
412 res.resize(m * s);
413 typename std::vector<R>::const_iterator itv=v.begin();
414 typename std::vector<T>::iterator itr=res.begin();
415 for(number_t k = 0; k < m; k++, itr += s, itv += d)
416 vecmat(mat.begin(), itv, itv + d, itr, itr + s);
417 d=s; n=1; //new block size
418 }
419
420 template<>
evalVectorMatrixProduct(const Matrix<real_t> & mat,const Vector<complex_t> & v,dimen_t & d,dimen_t & n,number_t m,Vector<real_t> & res)421 inline void evalVectorMatrixProduct(const Matrix<real_t>& mat, const Vector<complex_t>& v, dimen_t& d, dimen_t& n, number_t m, Vector<real_t>& res)
422 {
423 error("not_handled","evalMatrixProduct(Matrix<Real>, Vector<Complex>, Dimen, Dimen, Number, Vector<Real>)");
424 }
425 //@}
426
427 //@{
428 //! Matrix product using vector representation of matrix
429 template<typename T, typename R> inline
evalMatrixVectorProduct(const Vector<T> & vec,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,Vector<T> & res)430 void evalMatrixVectorProduct(const Vector<T>& vec, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m, Vector<T>& res)
431 {
432 //assume v is a matrices sequence (d=n*n) and vec a vector of size >= n
433 res.resize(m * n);
434 typename std::vector<R>::const_iterator itv=v.begin();
435 typename std::vector<T>::const_iterator itvec=vec.begin();
436 typename std::vector<T>::iterator itr=res.begin();
437 for(number_t k = 0; k < m; k++, itr += n, itv += d)
438 matvec(itv, itvec, itvec + n, itr, itr + n);
439 d=n;
440 n=1; //new block size
441 }
442
443 template<>
evalMatrixVectorProduct(const Vector<real_t> & vec,const Vector<complex_t> & v,dimen_t & d,dimen_t & n,number_t m,Vector<real_t> & res)444 inline void evalMatrixVectorProduct(const Vector<real_t>& vec, const Vector<complex_t>& v, dimen_t& d, dimen_t& n, number_t m, Vector<real_t>& res)
445 {
446 error("not_handled","evalMatrixVectorProduct(Vector<Real>, Vector<COmplex>, Dimen, Dimen, Number, Vector<Real>)");
447 }
448
449 template<typename T, typename R> inline
evalVectorMatrixProduct(const Vector<T> & vec,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,Vector<T> & res)450 void evalVectorMatrixProduct(const Vector<T>& vec, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m, Vector<T>& res)
451 {
452 //assume v is a matrices sequence (d=n*n) and vec a vector of size >= n
453 res.resize(m * n);
454 typename std::vector<R>::const_iterator itv=v.begin();
455 typename std::vector<T>::const_iterator itvec=vec.begin();
456 typename std::vector<T>::iterator itr=res.begin();
457 for(number_t k = 0; k < m; k++, itr += n, itv += d)
458 vecmat(itv, itvec, itvec + n, itr, itr + n);
459 d=n;
460 n=1; //new block size
461 }
462
463 template<>
evalVectorMatrixProduct(const Vector<real_t> & vec,const Vector<complex_t> & v,dimen_t & d,dimen_t & n,number_t m,Vector<real_t> & res)464 inline void evalVectorMatrixProduct(const Vector<real_t>& vec, const Vector<complex_t>& v, dimen_t& d, dimen_t& n, number_t m, Vector<real_t>& res)
465 {
466 error("not_handled","evalVectorMatrixProduct(Vector<Real>, Vector<Complex>, Dimen, Dimen, Number, Vector<Real>)");
467 }
468
469 template<typename T, typename R> inline
evalMatrixMatrixProduct(const Matrix<T> & mat,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,Vector<T> & res)470 void evalMatrixMatrixProduct(const Matrix<T>& mat, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m, Vector<T>& res)
471 {
472 // product mat * v_m : mat is a matrix and v_m a matrice d/n x n
473 dimen_t nbr = mat.numberOfRows(), nbc=mat.numberOfColumns(), s=nbr*n;
474 res.resize(m * s);
475 typename std::vector<R>::const_iterator itv=v.begin();
476 typename std::vector<T>::iterator itr=res.begin();
477 typename Matrix<T>::const_iterator itm = mat.begin();
478 for(number_t k = 0; k < m; k++, itr += s, itv += d)
479 matmat(itm, nbc, itv, nbr, n, itr);
480 d=s; //new block size
481 }
482
483 template<>
evalMatrixMatrixProduct(const Matrix<real_t> & vec,const Vector<complex_t> & v,dimen_t & d,dimen_t & n,number_t m,Vector<real_t> & res)484 inline void evalMatrixMatrixProduct(const Matrix<real_t>& vec, const Vector<complex_t>& v, dimen_t& d, dimen_t& n, number_t m, Vector<real_t>& res)
485 {
486 error("not_handled","evalMatrixMatrixProduct(Matrix<Real>, Vector<Complex, Dimen, Dimen, Number, Vector<Real>)");
487 }
488
489 template<typename T, typename R> inline
evalMatrixMatrixProduct2(const Matrix<T> & mat,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,Vector<T> & res)490 void evalMatrixMatrixProduct2(const Matrix<T>& mat, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m, Vector<T>& res)
491 {
492 // product v_m * mat: mat is a matrix and v_m a matrice d/n x n
493 dimen_t nbr = d/n, nbc=mat.numberOfColumns(), s=nbr*nbc;
494 res.resize(m * s);
495 typename std::vector<R>::const_iterator itv=v.begin();
496 typename std::vector<T>::iterator itr=res.begin();
497 typename Matrix<T>::const_iterator itm = mat.begin();
498 for(number_t k = 0; k < m; k++, itr += s, itv += d)
499 matmat(itv, n, itm, nbr, nbc, itr);
500 d=s;
501 n=nbr; //new block size
502 }
503
504 template<>
evalMatrixMatrixProduct2(const Matrix<real_t> & mat,const Vector<complex_t> & v,dimen_t & d,dimen_t & n,number_t m,Vector<real_t> & res)505 inline void evalMatrixMatrixProduct2(const Matrix<real_t>& mat, const Vector<complex_t>& v, dimen_t& d, dimen_t& n, number_t m, Vector<real_t>& res)
506 {
507 error("not_handled","evalMatrixMatrixProduct2(Matrix<Real, Vector<Complex>, Dimen, Dimen, Number, Vector<Real>)");
508 }
509 //@}
510
511 //@{
512 //! Contracted product
513 template<typename T, typename R> inline
evalContractedProduct(const Matrix<T> & mat,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,Vector<T> & res)514 void evalContractedProduct(const Matrix<T>& mat, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m, Vector<T>& res)
515 {
516 /* it is assumed that vector entry v is a sequence of m dense SQUARE matrices of size n (row storage and n*n=d)
517 we consider 3 cases (for each matrix)
518 - operand is a matrix nxn : standard contracted product returning a scalar r = sum_ij A_ij*E_ij = trace(A*B)
519 - operand is a n(n+1)/2 square matrix : symmetric extended contracting product returning a symmetric nxn matrix, say S
520 n=3 : [S11 S22 S33 S12 S13 S23] = A *[E11 E22 E33 E32 E31 E21] (Voigt notation)
521 n=2 : [S11 S22 S12] = A *[E11 E22 E12]
522 n=1 : [S11] = A *[E11]
523 - operand is a matrix of n^2 x n^2 : full extended contracting product returning a nxn matrix
524 Sij = C[(i-1)n+1:in;(j-1)n+1:jn]%E (block contracted product)
525 the last 2 cases are generally involved in anisotropic elasticity computation, case 2 corresponds to the Voigt notation
526 */
527
528 typename std::vector<R>::const_iterator itv;
529 typename std::vector<T>::iterator itr;
530 number_t nA=mat.numberOfRows();
531
532 if(nA==1) // same as scalar * E
533 {
534 T val= mat[0];
535 res.resize(m);
536 itr=res.begin();
537 for(itv = v.begin(); itv != v.end(); itv++, itr++) *itr = val * *itv;
538 return;
539 }
540 if(nA == n) //standard contracted product
541 {
542 res.resize(m);
543 itv = v.begin();
544 itr=res.begin();
545 for(number_t k = 0; k < m; k++, itr++, itv += d)
546 {
547 T zero(0);
548 *itr = std::inner_product(mat.begin(), mat.end(), itv, zero);
549 }
550 d=1;
551 n=1; //new block size
552 return;
553 }
554
555 if(nA == number_t(n*n) ) //full extended contracted product
556 {
557 res.resize(m*d);
558 itv = v.begin();
559 itr=res.begin();
560 number_t n2=n*n;
561 typename std::vector<R>::const_iterator it;
562 typename Vector<T>::const_iterator itAb= mat.begin(), itA, itAij;
563 for(number_t k = 0; k < m; k++, itv += d) //block m
564 for(number_t i=0; i<n; i++)
565 for(number_t j=0; j<n; j++, itr++) //compute Sij
566 {
567 *itr=T(0);
568 it=itv;
569 itAij=itAb + (i*d+j*n);
570 for(number_t p=0; p<n; p++) //contracted product
571 {
572 itA =itAij +p*n2;
573 for(number_t q=0; q<n; q++, it++, itA++)
574 *itr += *itA** it;
575 }
576 }
577 //unchanged block size
578 return;
579 }
580
581 if(2*nA == number_t(n*(n+1))) //symmetric extended contracted product
582 {
583 res.resize(m*d);
584 itv = v.begin();
585 itr=res.begin();
586 Vector<R> E(nA);
587 Vector<T> S(nA);
588 typename Vector<R>::iterator itE;
589 typename Vector<T>::iterator itS;
590 for(number_t k = 0; k < m; k++, itv += d) //block k
591 {
592 if(n==2)
593 {
594 itE=E.begin();
595 *itE = *itv; itE++; //E11
596 *itE = *(itv+3); itE++; //E22
597 *itE = *(itv+1); //E21
598 matvec(mat.begin(), E.begin(), E.end(), S.begin(), S.end());
599 itS=S.begin();
600 *itr= *itS; itr++; //S11
601 *itr= *(itS+2); itr++; //S12
602 *itr= *(itS+2); itr++; //S21
603 *itr= *(itS+1); itr++; //S22
604 }
605 else
606 {
607 itE=E.begin();
608 *itE = *itv; itE++; //E11
609 *itE = *(itv+4); itE++; //E22
610 *itE = *(itv+8); itE++; //E33
611 *itE = *(itv+5); itE++; //E23
612 *itE = *(itv+2); itE++; //E13
613 *itE = *(itv+1); //E12
614 matvec(mat.begin(), E.begin(), E.end(), S.begin(), S.end());
615 itS=S.begin();
616 *itr= *itS; itr++; //S11
617 *itr = *(itS+5); itr++; //S12
618 *itr = *(itS+4); itr++; //S13
619 *itr = *(itS+5); itr++; //S21
620 *itr = *(itS+1); itr++; //S22
621 *itr = *(itS+3); itr++; //S23
622 *itr = *(itS+4); itr++; //S31
623 *itr = *(itS+3); itr++; //S32
624 *itr = *(itS+2); itr++; //S33
625 }
626 }
627 //unchanged block size
628 return;
629 }
630 }
631
632 template<>
evalContractedProduct(const Matrix<real_t> & mat,const Vector<complex_t> & v,dimen_t & d,dimen_t & n,number_t m,Vector<real_t> & res)633 inline void evalContractedProduct(const Matrix<real_t>& mat, const Vector<complex_t>& v, dimen_t& d, dimen_t& n, number_t m, Vector<real_t>& res)
634 {
635 error("not_handled","evalContractedProduct(Matrix<Real>, Vector<Complex>, Dimen, Dimen, Number, Vector<Real>)");
636 }
637 //@}
638
639 //-----------------------------------------------------
640 // left and right operand action
641 //-----------------------------------------------------
642 //@{
643 /*! evaluate operand with value or function at left or right applied to a collection of scalar/vector/matrix values of m basis functions
644 (v_1)_1,...,(v_1)_d,(v_2)_1,...,(v_2)_d, ..., (v_m)_1,...,(v_m)_d
645 return in same structure w= op aop v
646 (w_1)_1,...,(w_1)_q,(w_2)_1,...,(w_2)_q, ..., (w_m)_1,...,(w_m)_q
647
648 v : basis function values
649 m : number of blocks (each block corresponds to a basis function)
650 d : size of block (may be updated)
651 n : dimension of matrix, when blocks are matrices (p=d/n):
652 [v_1,...,v_d] = [v_11,...,v_1n, v_21,...,v_2n, ..., v_p1,...,v_pn]
653
654 Note : no consistency test are done here !!!
655 Note : d and n may be updated by operations
656 */
657 template<typename T, typename R> inline
leftEval(const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m) const658 Vector<T> Operand::leftEval(const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m) const //! value op V
659 {
660 Vector<T> r;
661 StrucType sto=strucType(); //struct of operand (scalar, vector, matrix)
662 ValueType vt=valueType();
663 if(sto == _scalar) //scalar value in operand all operations degenerate as a scalar product
664 {
665 T val=val_p->value<T>();
666 if(vt==_complex && conjugate_) val=conj(val);
667 evalScalarProduct(val, v, r);
668 return r;
669 }
670
671 if(sto == _vector)
672 {
673 Vector<T> vec= val_p->value<Vector<T> >();
674 if(vt==_complex && conjugate_) vec=conj(vec);
675 switch(operation_)
676 {
677 case _innerProduct : //not hermitian product
678 {
679 evalInnerProduct(vec, v, d, n, m, r);
680 return r;
681 }
682 case _crossProduct : //in 3D or 2D (return a scalar)
683 {
684 evalCrossProduct(vec, v, d, n, m, r, false);
685 return r;
686 }
687 case _product : //vector * scalar or vector * matrix
688 {
689 if (d==1) //vector * scalar
690 {
691 evalScalarProduct(vec, v, d, n, m, r);
692 return r;
693 }
694 else if (n>=1) //vector * matrix
695 {
696 evalVectorMatrixProduct(vec, v, d, n, m, r);
697 return r;
698 }
699 }
700 default:
701 break;
702 }
703 }
704
705 if(sto == _matrix)
706 {
707 Matrix<T> mat= val_p->value<Matrix<T> >();
708 if(vt==_complex && conjugate_) mat=conj(mat);
709 if(vt==_real && transpose_) mat.transpose();
710 switch(operation_)
711 {
712 case _product :
713 {
714 if (d==1) //vector * scalar
715 {
716 evalScalarProduct(mat, v, d, n, m, r);
717 return r;
718 }
719 else
720 {
721 if (n==1) { evalMatrixVectorProduct(mat, v, d, n, m, r); return r; }
722 else { evalMatrixMatrixProduct(mat, v, d, n, m, r); return r; }
723 }
724 }
725 case _contractedProduct:
726 {
727 evalContractedProduct(mat, v, d, n, m, r);
728 return r;
729 }
730 default:
731 break;
732 }
733 }
734
735 error("not_handled", "Operand::leftEval");
736 return r;
737 }
738
739 template<typename T, typename R> inline
rightEval(const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m) const740 Vector<T> Operand::rightEval(const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m) const //! V op value
741 {
742 Vector<T> r;
743 StrucType sto=strucType(); //struct of operand (scalar, vector, matrix)
744 ValueType vt=valueType();
745 if (sto == _scalar) //scalar value in operand all operations degenerate as a scalar product
746 {
747 T val=val_p->value<T>();
748 if(vt==_complex && conjugate_) val=conj(val);
749 evalScalarProduct(val, v, r);
750 return r;
751 }
752
753 if (sto == _vector)
754 {
755 Vector<T> vec= val_p->value<Vector<T> >();
756 if(vt==_complex && conjugate_) vec=conj(vec);
757 switch (operation_)
758 {
759 case _innerProduct : //not hermitian product
760 {
761 evalInnerProduct(vec, v, d, n, m, r);
762 return r;
763 }
764 case _crossProduct : //in 3D or 2D (return a scalar)
765 {
766 evalCrossProduct(vec, v, d, n, m, r, true);
767 return r;
768 }
769 case _product : //vector * scalar or vector * matrix
770 {
771 if (d==1) //vector * scalar
772 {
773 evalScalarProduct(vec, v, d, n, m, r);
774 return r;
775 }
776 else if (n>=1) //vector * matrix
777 {
778 evalMatrixVectorProduct(vec, v, d, n, m, r);
779 return r;
780 }
781 }
782 default:
783 break;
784 }
785 }
786
787 if (sto == _matrix)
788 {
789 Matrix<T> mat= val_p->value<Matrix<T> >();
790 if (vt==_complex && conjugate_) mat=conj(mat);
791 if (vt==_real && transpose_) mat.transpose();
792 switch (operation_)
793 {
794 case _product :
795 {
796 if (d==1) //vector * scalar
797 {
798 evalScalarProduct(mat, v, d, n, m, r);
799 return r;
800 }
801 else
802 {
803 if (n==1) { evalVectorMatrixProduct(mat, v, d, n, m, r); return r; }
804 else { evalMatrixMatrixProduct2(mat, v, d, n, m, r); return r; }
805 }
806 }
807 case _contractedProduct :
808 {
809 evalContractedProduct(mat, v, d, n, m, r);
810 return r;
811 }
812 default:
813 break;
814 }
815 }
816
817 error("not_handled", "Operand::leftEval");
818 return r;
819 }
820
821 //=========================================================================================
822 // operand with function
823 //=========================================================================================
824
825 template<typename T, typename R> inline
leftEval(const Point & pt,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,const Vector<real_t> * np,const ExtensionData * extdata) const826 Vector<T> Operand::leftEval(const Point& pt, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m,
827 const Vector<real_t>* np, const ExtensionData* extdata) const //! f(p) op V
828 {
829 Vector<T> r;
830 StrucType sto=strucType(); //struct of operand (scalar, vector, matrix)
831 ValueType vt=valueType();
832 if (sto == _scalar) //scalar value in operand or vector, all operations degenerate as a scalar product
833 {
834 T val;
835 if(vt==_real) //to deal with real matrix and complex result
836 {
837 real_t valR;
838 value(valR, pt, np, extdata);
839 val=valR;
840 }
841 else value(val, pt, np, extdata); //result is mandatory complex
842 if (vt==_complex && conjugate_) val=conj(val);
843 evalScalarProduct(val,v,r);
844 return r;
845 }
846
847 if (sto == _vector)
848 {
849 Vector<T> vec;
850 if(vt==_real) //to deal with real matrix and complex result
851 {
852 Vector<real_t> vecR;
853 value(vecR, pt, np, extdata);
854 vec=vecR;
855 }
856 else value(vec, pt, np); //result is mandatory complex
857 if (vt==_complex && conjugate_) vec=conj(vec);
858 switch (operation_)
859 {
860 case _innerProduct : //not hermitian product
861 {
862 evalInnerProduct(vec, v, d, n, m, r);
863 return r;
864 }
865 case _crossProduct : //in 3D or 2D (return a scalar)
866 {
867 evalCrossProduct(vec, v, d, n, m, r, false);
868 return r;
869 }
870 case _product : //only vector * matrix
871 {
872 if (d==1) //vector * scalar
873 {
874 evalScalarProduct(vec, v, d, n, m, r);
875 return r;
876 }
877 else if (n>=1) //vector * matrix
878 {
879 evalVectorMatrixProduct(vec, v, d, n, m, r);
880 return r;
881 }
882 }
883 default :
884 break;
885 }
886 }
887
888 if(sto == _matrix)
889 {
890 Matrix<T> mat;
891 if(vt==_real) //to deal with real matrix and complex result
892 {
893 Matrix<real_t> matR;
894 value(matR, pt, np, extdata);
895 mat=matR;
896 }
897 else value(mat, pt, np, extdata);//result is mandatory complex
898 if (vt==_complex && conjugate_) mat=conj(mat);
899 if (vt==_real && transpose_) mat.transpose();
900 switch (operation_)
901 {
902 case _product : // matrix * vector
903 {
904 if (d==1) //vector * scalar
905 {
906 evalScalarProduct(mat, v, d, n, m, r);
907 return r;
908 }
909 else
910 {
911 //if (n==mat.numberOfColumns()) { evalMatrixVectorProduct(mat, v, d, n, m, r); return r; }
912 if (n==1) { evalMatrixVectorProduct(mat, v, d, n, m, r); return r; }
913 else { evalMatrixMatrixProduct(mat, v, d, n, m, r); return r; }
914 }
915 }
916 case _contractedProduct :
917 {
918 evalContractedProduct(mat, v, d, n, m, r);
919 return r;
920 }
921 default:
922 break;
923 }
924 }
925
926 error("not_handled", "Operand::leftEval");
927 return r;
928 }
929
930
931 template<typename T, typename R> inline
rightEval(const Point & pt,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,const Vector<real_t> * np,const ExtensionData * extdata) const932 Vector<T> Operand::rightEval(const Point& pt, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m,
933 const Vector<real_t>* np, const ExtensionData* extdata) const //! V op f(p)
934 {
935 Vector<T> r;
936 StrucType sto=strucType(); //struct of operand (scalar, vector, matrix)
937 ValueType vt=valueType();
938 if (sto == _scalar) //scalar value in operand or vector, all operations degenerate as a scalar product
939 {
940 T val;
941 if(vt==_real) //to deal with real matrix and complex result (T)
942 {
943 real_t valR;
944 value(valR, pt, np, extdata);
945 val=valR;
946 }
947 else value(val, pt, np, extdata); //result is mandatory complex
948 if (vt==_complex && conjugate_) val=conj(val);
949 evalScalarProduct(val,v,r);
950 return r;
951 }
952
953 if (sto == _vector)
954 {
955 Vector<T> vec;
956 if(vt==_real) //to deal with real matrix and complex result
957 {
958 Vector<real_t> vecR;
959 value(vecR, pt, np, extdata);
960 vec=vecR;
961 }
962 else value(vec, pt, np, extdata); //result is mandatory complex
963 if (vt==_complex && conjugate_) vec=conj(vec);
964 switch(operation_)
965 {
966 case _innerProduct : //not hermitian product
967 evalInnerProduct(vec, v, d, n, m, r);
968 return r;
969 case _crossProduct : //in 3D or 2D (return a scalar)
970 evalCrossProduct(vec, v, d, n, m, r, false);
971 return r;
972 case _product : //only vector * matrix
973 if (d==1) //vector * scalar
974 { evalScalarProduct(vec, v, d, n, m, r); return r; }
975 else if (n>=1) //vector * matrix
976 { evalMatrixVectorProduct(vec, v, d, n, m, r); return r; }
977 default:
978 break;
979 }
980 }
981
982 if(sto == _matrix)
983 {
984 Matrix<T> mat;
985 if(vt==_real) //to deal with real matrix and complex result
986 {
987 Matrix<real_t> matR;
988 value(matR, pt, np, extdata);
989 mat=matR;
990 }
991 else value(mat, pt, np, extdata); //result is mandatory complex
992 if (vt==_complex && conjugate_) mat=conj(mat);
993 if (vt==_real && transpose_) mat.transpose();
994 switch(operation_)
995 {
996 case _product : // matrix * vector
997 if (d==1) //vector * scalar
998 { evalScalarProduct(mat, v, d, n, m, r); return r; }
999 else
1000 {
1001 //if (n==mat.numberOfRows()) { evalVectorMatrixProduct(mat, v, d, n, m, r); return r; }
1002 if (n==1) { evalVectorMatrixProduct(mat, v, d, n, m, r); return r; }
1003 else { evalMatrixMatrixProduct2(mat, v, d, n, m, r); return r; }
1004 }
1005 case _contractedProduct :
1006 evalContractedProduct(mat, v, d, n, m, r);
1007 return r;
1008 default:
1009 break;
1010 }
1011 }
1012
1013 error("not_handled", "Operand::rightEval");
1014 return r;
1015 }
1016
1017 //=========================================================================================
1018 // operand with kernel
1019 //=========================================================================================
1020 // pointer opker cannot be a null pointer !!!
1021
1022 template<typename T, typename R> inline
leftEval(const Point & x,const Point & y,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,const Vector<real_t> * nx,const Vector<real_t> * ny) const1023 Vector<T> Operand::leftEval(const Point& x, const Point& y, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m,
1024 const Vector<real_t>* nx, const Vector<real_t>* ny) const //! f(p) op V
1025 {
1026 Vector<T> r;
1027 StrucType sto=strucType(); //struct of operand (scalar, vector, matrix)
1028 ValueType vt=valueType();
1029 if (sto == _scalar) //scalar value in operand or vector, all operations degenerate as a scalar product
1030 {
1031 T val;
1032 if(vt==_real) //to deal with real matrix and complex result
1033 {
1034 real_t valR;
1035 opker_p->eval(x, y, valR, nx, ny);
1036 val=valR;
1037 }
1038 else opker_p->eval(x, y, val, nx, ny); //result is mandatory complex
1039 if (vt==_complex && conjugate_) val=conj(val);
1040 evalScalarProduct(val,v,r);
1041 return r;
1042 }
1043
1044 if (sto == _vector)
1045 {
1046 Vector<T> vec;
1047 if(vt==_real) //to deal with real matrix and complex result
1048 {
1049 Vector<real_t> vecR;
1050 opker_p->eval(x, y, vecR, nx, ny);
1051 vec=vecR;
1052 }
1053 else opker_p->eval(x, y, vec, nx, ny); //result is mandatory complex
1054 if (vt==_complex && conjugate_) vec=conj(vec);
1055 switch (operation_)
1056 {
1057 case _innerProduct : //not hermitian product
1058 {
1059 evalInnerProduct(vec, v, d, n, m, r);
1060 return r;
1061 }
1062 case _crossProduct : //in 3D or 2D (return a scalar)
1063 {
1064 evalCrossProduct(vec, v, d, n, m, r, false);
1065 return r;
1066 }
1067 case _product :
1068 {
1069 if (d==1) //vector * scalar
1070 {
1071 evalScalarProduct(vec, v, d, n, m, r);
1072 return r;
1073 }
1074 else if (n>=1) //vector * matrix
1075 {
1076 evalVectorMatrixProduct(vec, v, d, n, m, r);
1077 return r;
1078 }
1079 }
1080 default :
1081 break;
1082 }
1083 }
1084
1085 if(sto == _matrix) // compute kernel matrix in a vector
1086 {
1087 dimPair dims(0,0);
1088 Matrix<T> mat;
1089 if(vt==_real) //to deal with real matrix and complex result
1090 {
1091 Vector<real_t> matR;
1092 opker_p->eval(x, y, matR, nx, ny, &dims);
1093 mat = Matrix<T>(dims.first, dims.second, matR.begin(), matR.end());
1094 }
1095 else
1096 {
1097 Vector<T> matT;
1098 opker_p->eval(x, y, matT, nx, ny, &dims); //result is mandatory complex
1099 mat = Matrix<T>(dims.first, dims.second, matT.begin(), matT.end());
1100 }
1101
1102 if (vt==_complex && conjugate_) mat.conjugate();
1103 if (transpose_) mat.transpose();
1104 switch (operation_)
1105 {
1106 case _product : // matrix * vector
1107 {
1108 if (d==1) //vector * scalar
1109 {
1110 evalScalarProduct(mat, v, d, n, m, r);
1111 return r;
1112 }
1113 else
1114 {
1115 //if (n==mat.numberOfColumns()) { evalMatrixVectorProduct(mat, v, d, n, m, r); return r; }
1116 if (n==1) { evalMatrixVectorProduct(mat, v, d, n, m, r); return r; }
1117 else { evalMatrixMatrixProduct(mat, v, d, n, m, r); return r; }
1118 }
1119 }
1120 case _contractedProduct :
1121 {
1122 evalContractedProduct(mat, v, d, n, m, r);
1123 return r;
1124 }
1125 default:
1126 break;
1127 }
1128 }
1129
1130 error("not_handled", "Operand::leftEval");
1131 return r;
1132 }
1133
1134
1135 template<typename T, typename R> inline
rightEval(const Point & x,const Point & y,const Vector<R> & v,dimen_t & d,dimen_t & n,number_t m,const Vector<real_t> * nx,const Vector<real_t> * ny) const1136 Vector<T> Operand::rightEval(const Point& x, const Point& y, const Vector<R>& v, dimen_t& d, dimen_t& n, number_t m,
1137 const Vector<real_t>* nx, const Vector<real_t>* ny) const //! V op f(p)
1138 {
1139 Vector<T> r;
1140 StrucType sto=strucType(); //struct of operand (scalar, vector, matrix)
1141 ValueType vt=valueType();
1142 if (sto == _scalar) //scalar value in operand or vector, all operations degenerate as a scalar product
1143 {
1144 T val;
1145 if(vt==_real) //to deal with real matrix and complex result (T)
1146 {
1147 real_t valR;
1148 opker_p->eval(x, y, valR, nx, ny);
1149 val=valR;
1150 }
1151 else opker_p->eval(x, y, val, nx, ny); //result is mandatory complex
1152 if (vt==_complex && conjugate_) val=conj(val);
1153 evalScalarProduct(val,v,r);
1154 return r;
1155 }
1156
1157 if (sto == _vector)
1158 {
1159 Vector<T> vec;
1160 if(vt==_real) //to deal with real matrix and complex result
1161 {
1162 Vector<real_t> vecR;
1163 opker_p->eval(x, y, vecR, nx, ny);
1164 vec=vecR;
1165 }
1166 else opker_p->eval(x, y, vec, nx, ny); //result is mandatory complex
1167 if (vt==_complex && conjugate_) vec=conj(vec);
1168 switch(operation_)
1169 {
1170 case _innerProduct : //not hermitian product
1171 evalInnerProduct(vec, v, d, n, m, r);
1172 return r;
1173 case _crossProduct : //in 3D or 2D (return a scalar)
1174 evalCrossProduct(vec, v, d, n, m, r, false);
1175 return r;
1176 case _product : //only vector * matrix
1177 if (d==1) //vector * scalar
1178 { evalScalarProduct(vec, v, d, n, m, r); return r; }
1179 else if (n>=1) //vector * matrix
1180 { evalMatrixVectorProduct(vec, v, d, n, m, r); return r; }
1181 default:
1182 break;
1183 }
1184 }
1185
1186 if(sto == _matrix)
1187 {
1188 Matrix<T> mat;
1189 if(vt==_real) //to deal with real matrix and complex result
1190 {
1191 Matrix<real_t> matR;
1192 opker_p->eval(x, y, matR, nx, ny);
1193 mat=matR;
1194 }
1195 else opker_p->eval(x, y, mat, nx, ny);//result is mandatory complex
1196 if (vt==_complex && conjugate_) mat=conj(mat);
1197 if (vt==_real && transpose_) mat.transpose();
1198 switch(operation_)
1199 {
1200 case _product : // matrix * vector
1201 if (d==1) //vector * scalar
1202 { evalScalarProduct(mat, v, d, n, m, r); return r; }
1203 else
1204 {
1205 //if (n==mat.numberOfRows()) { evalVectorMatrixProduct(mat, v, d, n, m, r); return r; }
1206 if (n==1) { evalVectorMatrixProduct(mat, v, d, n, m, r); return r; }
1207 else { evalMatrixMatrixProduct2(mat, v, d, n, m, r); return r; }
1208 }
1209 case _contractedProduct :
1210 evalContractedProduct(mat, v, d, n, m, r);
1211 return r;
1212 default:
1213 break;
1214 }
1215 }
1216
1217 error("not_handled", "Operand::rightEval");
1218 return r;
1219 }
1220 //@}
1221
1222 /*! evaluate "tensor" operation between 2 small vectors, and add it to a given a nu x nv matrix mat (stored by rows)
1223
1224 op : algebraic operator involved (either product, inner product, cross product, contracted product)
1225 alpha is a coefficient applied to the added "tensor" matrix
1226 u (resp. v) is
1227 - either a list of nu scalar values (resp. nv scalar values)
1228 - or a list of nbu (resp. nbv) vector values (u_1,u_2,..u_nu) stored as
1229 (u_1)1 ...(u_1)mu (u_2)1 ... (u_2)mu .....(u_nu)1 ...(u_nu)mu
1230 with mu=u.size()/nu
1231 for scalar case (mu=mv=1) all product are equivalent
1232 for vector case (mu=mv>1) only inner product is currently available
1233 for matrix case (mu=mv>1) only contracted product is currently available
1234
1235 */
1236 template <typename T, typename KU, typename KV> inline
tensorOpAdd(const AlgebraicOperator & op,const std::vector<KU> & u,number_t nu,const std::vector<KV> & v,number_t nv,Matrix<T> & mat,const T & alpha)1237 Matrix<T>& tensorOpAdd(const AlgebraicOperator& op, const std::vector<KU>& u, number_t nu,
1238 const std::vector<KV>& v, number_t nv, Matrix<T>& mat, const T& alpha)
1239 {
1240
1241 typename Matrix<T>::iterator itm = mat.begin();
1242 typename std::vector<KU>::const_iterator itu;
1243 typename std::vector<KV>::const_iterator itv;
1244 number_t mu = u.size() / nu, mv = v.size() / nv;
1245 if(mu != mv)
1246 {
1247 where("tensorOpAdd(...)");
1248 error("bad_size", mv, mu);
1249 }
1250
1251 if(mu == 1) //scalar case
1252 {
1253 for(itu = u.begin(); itu != u.end(); itu++)
1254 for(itv = v.begin(); itv != v.end(); itv++, itm++)
1255 *itm += alpha** itu** itv;
1256 }
1257 else
1258 switch(op)
1259 {
1260 case _innerProduct :
1261 {
1262 for(itu = u.begin(); itu != u.end(); itu += mu)
1263 for(itv = v.begin(); itv != v.end(); itv += mv, itm++)
1264 {
1265 T zero(0);
1266 *itm += alpha * std::inner_product(itu, itu + mu, itv, zero);
1267 }
1268 return mat;
1269 break;
1270 }
1271 case _contractedProduct:
1272 {
1273 for(itu = u.begin(); itu != u.end(); itu += mu)
1274 for(itv = v.begin(); itv != v.end(); itv += mv, itm++)
1275 for(number_t i=0; i<mu; i++)
1276 *itm += alpha * *(itu+i) * *(itv+i);
1277 return mat;
1278 break;
1279 }
1280 case _product :
1281 case _crossProduct :
1282 error("not_handled", "tensorOpAdd(...)");
1283 }
1284 return mat; //fake return
1285 }
1286
1287 //template <typename T> inline
1288 //Matrix<T>& tensorOpAdd(const AlgebraicOperator& op, const std::vector<T>& u, number_t nu,
1289 // const std::vector<T>& v, number_t nv, Matrix<T>& mat, const T& alpha)
1290 //{
1291 //
1292 // typename Matrix<T>::iterator itm = mat.begin();
1293 // typename std::vector<T>::const_iterator itu, itv;
1294 // number_t mu = dimen_t(u.size()) / nu, mv = dimen_t(v.size()) / nv;
1295 // if(mu != mv) error("free_error", "in tensorOpAdd(...) : not the same size of vectors");
1296 //
1297 // if(mu == 1) //scalar case
1298 // {
1299 // for(itu = u.begin(); itu != u.end(); itu++)
1300 // for(itv = v.begin(); itv != v.end(); itv++, itm++)
1301 // *itm += alpha** itu** itv;
1302 // }
1303 // else
1304 // switch(op)
1305 // {
1306 // case _innerProduct :
1307 // {
1308 // for(itu = u.begin(); itu != u.end(); itu += mu)
1309 // for(itv = v.begin(); itv != v.end(); itv += mv, itm++)
1310 // {
1311 // T zero(0);
1312 // *itm += alpha * std::inner_product(itu, itu + mu, itv, zero);
1313 // }
1314 // return mat;
1315 // }
1316 // break;
1317 // case _contractedProduct:
1318 // {
1319 // for(itu = u.begin(); itu != u.end(); itu += mu)
1320 // for(itv = v.begin(); itv != v.end(); itv += mv, itm++)
1321 // for(number_t i=0; i<mu; i++)
1322 // *itm += alpha * *(itu+i) * *(itv+i);
1323 // return mat;
1324 // }
1325 // break;
1326 // case _product :
1327 // case _crossProduct :
1328 // error("free_error", "in tensorOp(...) : operator on vectors not available");
1329 // }
1330 // return mat; //fake return
1331 //}
1332
1333
1334 //same function with iterator instead of Matrix<T>
1335 //template <typename T, typename iterator> inline
1336 //void tensorOpAdd(const AlgebraicOperator& op, const std::vector<T>& u, number_t nu,
1337 // const std::vector<T>& v, number_t nv, iterator itm, const T& alpha)
1338 //{
1339 //
1340 // typename std::vector<T>::const_iterator itu, itv;
1341 // number_t mu = dimen_t(u.size()) / nu, mv = dimen_t(v.size()) / nv;
1342 // if(mu != mv) error("free_error", "in tensorOpAdd(...) : not the same size of vectors");
1343 // if(mu == 1) //scalar case
1344 // {
1345 // for(itu = u.begin(); itu != u.end(); itu++)
1346 // for(itv = v.begin(); itv != v.end(); itv++, itm++)
1347 // *itm += alpha** itu** itv;
1348 // }
1349 // else
1350 // switch(op)
1351 // {
1352 // case _innerProduct :
1353 // {
1354 // for(itu = u.begin(); itu != u.end(); itu += mu)
1355 // for(itv = v.begin(); itv != v.end(); itv += mv, itm++)
1356 // {
1357 // T zero(0);
1358 // *itm += alpha * std::inner_product(itu, itu + mu, itv, zero);
1359 // }
1360 // }
1361 // break;
1362 // case _product :
1363 // case _crossProduct :
1364 // case _contractedProduct:
1365 // error("free_error", "in tensorOp(...) : operator on vectors not available");
1366 // }
1367 //}
1368
1369 /*! evaluate "tensor" operation between 2 small vectors and "coefficient" ker, and add it to a given a nu x nv matrix mat (stored by rows)
1370 u opu ker opv v
1371 u (resp. v) is
1372 - either a list of nu scalar values (resp. nv scalar values)
1373 - or a list of nbu (resp. nbv) vector values (u_1,u_2,..u_nu) stored as
1374 (u_1)1 ...(u_1)mu (u_2)1 ... (u_2)mu .....(u_nu)1 ...(u_nu)mu
1375 with mu=u.size()/nu
1376 for scalar case (mu=mv=1) all product are equivalent
1377 for vector case (mu=mv>1) only inner product is currently available
1378
1379 itk is an iterator to the kernel part (either a scalar, a vector (mk or nk) or a matrix (mk x nk))
1380 */
1381 template <typename T, typename iteratorM, typename iteratorK> inline
tensorOpAdd(const AlgebraicOperator & opu,const AlgebraicOperator & opv,const std::vector<T> & u,number_t nu,const std::vector<T> & v,number_t nv,iteratorM itm,iteratorK itk,number_t mk,number_t nk)1382 void tensorOpAdd(const AlgebraicOperator& opu, const AlgebraicOperator& opv, const std::vector<T>& u, number_t nu,
1383 const std::vector<T>& v, number_t nv, iteratorM itm, iteratorK itk, number_t mk, number_t nk)
1384 {
1385
1386 typename std::vector<T>::const_iterator itu, itv;
1387 number_t mu = dimen_t(u.size()) / nu, mv = dimen_t(v.size()) / nv;
1388 if(mu != mv)
1389 {
1390 where("tensorOpAdd(...)");
1391 error("bad_size", mv, mu);
1392 }
1393 if(mu == 1) //scalar case, all, operations are product
1394 {
1395 for(itu = u.begin(); itu != u.end(); ++itu)
1396 for(itv = v.begin(); itv != v.end(); ++itv, ++itm)
1397 *itm += *itu * *itk * *itv;
1398 return;
1399 }
1400
1401 /*vector case mu = mv > 1, supported operations :
1402 U | alpha * V means U | (alpha * V) alpha a scalar or a matrix mu x mv
1403 U * alpha | V means (U * alpha) | V alpha a scalar or a matrix mu x mv
1404 U | alpha ^ V means U | (alpha ^ V) alpha a vector mv x 1
1405 U ^ alpha | V means (U ^ alpha) | V alpha a vector mu x 1
1406 */
1407 if(opu==_innerProduct && opv==_product)
1408 {
1409 for(itu = u.begin(); itu != u.end(); itu += mu)
1410 for(itv = v.begin(); itv != v.end(); itv += mv, itm++)
1411 {
1412 // T zero(0);
1413 //*itm += alpha * std::inner_product(itu, itu + mu, itv, zero);
1414 }
1415 return;
1416 }
1417
1418 if(opu==_innerProduct && opv==_product)
1419 {
1420 return;
1421 }
1422
1423 if(opu==_innerProduct && opv==_product)
1424 {
1425 return;
1426 }
1427
1428 error("not_handled", "tensorOpAdd(...)");
1429 }
1430
1431 } // end of namespace xlifepp
1432
1433 #endif /* OPERAND_HPP */
1434