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