assignment.hpp
Go to the documentation of this file.
1 /*!
2  *
3  *
4  * \brief Assignment and evaluation of vector expressions
5  *
6  *
7  *
8  * \author O. Krause
9  * \date 2013
10  *
11  *
12  * \par Copyright 1995-2015 Shark Development Team
13  *
14  * <BR><HR>
15  * This file is part of Shark.
16  * <http://image.diku.dk/shark/>
17  *
18  * Shark is free software: you can redistribute it and/or modify
19  * it under the terms of the GNU Lesser General Public License as published
20  * by the Free Software Foundation, either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * Shark is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26  * GNU Lesser General Public License for more details.
27  *
28  * You should have received a copy of the GNU Lesser General Public License
29  * along with Shark. If not, see <http://www.gnu.org/licenses/>.
30  *
31  */
32 
33 #ifndef REMORA_ASSIGNMENT_HPP
34 #define REMORA_ASSIGNMENT_HPP
35 
38 #include "detail/traits.hpp"
39 
40 #include <type_traits>
41 namespace remora{
42 
43 //////////////////////////////////////////////////////////////////////
44 /////Evaluate blockwise expressions
45 //////////////////////////////////////////////////////////////////////
46 
47 ///\brief conditionally evaluates a vector expression if it is a block expression
48 ///
49 /// If the expression is a block expression, a temporary vector is created to which
50 /// the expression is assigned, which is then returned, otherwise the expression itself
51 /// is returned
52 template<class E, class Device>
53 typename std::conditional<
54  std::is_base_of<
55  blockwise_tag,
56  typename E::evaluation_category
57  >::value,
58  typename vector_temporary<E>::type,
59  E const&
60 >::type
61 eval_block(vector_expression<E, Device> const& e){
62  return e();//either casts to E const& or returns the copied expression
63 }
64 ///\brief conditionally evaluates a matrix expression if it is a block expression
65 ///
66 /// If the expression is a block expression, a temporary matrix is created to which
67 /// the expression is assigned, which is then returned, otherwise the expression itself
68 /// is returned
69 template<class E, class Device>
70 typename std::conditional<
71  std::is_base_of<
72  blockwise_tag,
73  typename E::evaluation_category
74  >::value,
75  typename matrix_temporary<E>::type,
76  E const&
77 >::type
78 eval_block(matrix_expression<E, Device> const& e){
79  return e();//either casts to E const& or returns the copied expression
80 }
81 
82 
83 ///\brief Evaluates an expression if it does not have a standard storage layout
84 ///
85 /// This function evaluates an expression to a temporary if it does not have
86 /// a known storage type. i.e. proxy expressions and containers are not evaluated but passed
87 /// through while everything else is evaluated.
88 template<class E, class Device>
89 typename std::conditional<
90  std::is_same<
91  unknown_storage,
92  typename E::storage_type
93  >::value,
94  typename vector_temporary<E>::type,
95  E const&
96 >::type
97 eval_expression(vector_expression<E, Device> const& e){
98  return e();//either casts to E const& or returns the evaluated expression
99 }
100 ///\brief Evaluates an expression if it does not have a standard storage layout
101 ///
102 /// This function evaluates an expression to a temporary if it does not have
103 /// a known storage type. i.e. proxy expressions and containers are not evaluated but passed
104 /// through while everything else is evaluated.
105 template<class E, class Device>
106 typename std::conditional<
107  std::is_same<
108  unknown_storage,
109  typename E::storage_type
110  >::value,
111  typename matrix_temporary<E>::type,
112  E const&
113 >::type
114 eval_expression(matrix_expression<E, Device> const& e){
115  return e();//either casts to E const& or returns the evaluated expression
116 }
117 
118 /////////////////////////////////////////////////////////////////////////////////////
119 ////// Vector Assign
120 ////////////////////////////////////////////////////////////////////////////////////
121 
122 namespace detail{
123  template<class VecX, class VecV, class Device>
124  void assign(vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v,elementwise_tag){
125  kernels::assign(x,v);
126  }
127  template<class VecX, class VecV, class Device>
128  void assign(
129  vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v,
130  elementwise_tag, typename VecX::value_type alpha
131  ){
132  typename device_traits<Device>:: template multiply_assign<typename common_value_type<VecX,VecV>::type> f(alpha);
133  kernels::assign(x, v,f);
134  }
135  template<class VecX, class VecV, class Device>
136  void assign(
137  vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v,
138  blockwise_tag, typename VecX::value_type alpha = 1
139  ){
140  v().assign_to(x,alpha);
141  }
142  template<class VecX, class VecV, class Device>
143  void plus_assign(vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v,elementwise_tag){
144  kernels::assign<typename device_traits<Device>:: template add<typename common_value_type<VecX,VecV>::type> > (x, v);
145  }
146  template<class VecX, class VecV, class Device>
147  void plus_assign(
148  vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v,
149  elementwise_tag, typename VecX::value_type alpha
150  ){
151  typename device_traits<Device>:: template multiply_and_add<typename common_value_type<VecX,VecV>::type> f(alpha);
152  kernels::assign(x, v,f);
153  }
154  template<class VecX, class VecV, class Device>
155  void plus_assign(
156  vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v,
157  blockwise_tag,typename VecX::value_type alpha = 1
158  ){
159  v().plus_assign_to(x,alpha);
160  }
161 }
162 
163 
164 /// \brief Dispatches vector assignment on an expression level
165 ///
166 /// This dispatcher takes care for whether the blockwise evaluation
167 /// or the elementwise evaluation is called
168 template<class VecX, class VecV, class Device>
169 VecX& assign(vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v){
170  REMORA_SIZE_CHECK(x().size() == v().size());
171  detail::assign(x,v,typename VecV::evaluation_category());
172  return x();
173 }
174 
175 /// \brief Dispatches vector assignment on an expression level
176 ///
177 /// This dispatcher takes care for whether the blockwise evaluation
178 /// or the elementwise evaluation is called
179 template<class VecX, class VecV, class Device>
180 VecX& assign(vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v, typename VecX::value_type alpha){
181  REMORA_SIZE_CHECK(x().size() == v().size());
182  detail::assign(x,v,typename VecV::evaluation_category(),alpha);
183  return x();
184 }
185 
186 /// \brief Dispatches vector plus-assignment on an expression level
187 ///
188 /// This dispatcher takes care for whether the blockwise evaluation
189 /// or the elementwise evaluation is called
190 template<class VecX, class VecV, class Device>
191 VecX& plus_assign(vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v){
192  REMORA_SIZE_CHECK(x().size() == v().size());
193  detail::plus_assign(x,v,typename VecV::evaluation_category());
194  return x();
195 }
196 
197 /// \brief Dispatches vector plus-assignment on an expression level
198 ///
199 /// This dispatcher takes care for whether the blockwise evaluation
200 /// or the elementwise evaluation is called
201 template<class VecX, class VecV, class Device>
202 VecX& plus_assign(vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v, typename VecX::value_type alpha){
203  REMORA_SIZE_CHECK(x().size() == v().size());
204  detail::plus_assign(x,v,typename VecV::evaluation_category(),alpha);
205  return x();
206 }
207 
208 /// \brief Dispatches vector multiply-assignment on an expression level
209 ///
210 /// This dispatcher takes care for whether the blockwise evaluation
211 /// or the elementwise evaluation is called
212 template<class VecX, class VecV, class Device>
213 VecX& multiply_assign(vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v){
214  REMORA_SIZE_CHECK(x().size() == v().size());
215  auto&& veval = eval_block(v);
216  kernels::assign<typename device_traits<Device>:: template multiply<typename common_value_type<VecX,VecV>::type>> (x, veval);
217  return x();
218 }
219 
220 /// \brief Dispatches vector multiply-assignment on an expression level
221 ///
222 /// This dispatcher takes care for whether the blockwise evaluation
223 /// or the elementwise evaluation is called
224 template<class VecX, class VecV, class Device>
225 VecX& divide_assign(vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v){
226  REMORA_SIZE_CHECK(x().size() == v().size());
227  auto&& veval = eval_block(v);
228  kernels::assign<typename device_traits<Device>:: template divide<typename common_value_type<VecX,VecV>::type>> (x, veval);
229  return x();
230 }
231 
232 /////////////////////////////////////////////////////////////////////////////////////
233 ////// Matrix Assign
234 ////////////////////////////////////////////////////////////////////////////////////
235 
236 namespace detail{
237  template<class MatA, class MatB, class Device>
238  void assign(matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B,elementwise_tag){
239  kernels::assign(A,B);
240  }
241  template<class MatA, class MatB, class Device>
242  void assign(
243  matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B,
244  elementwise_tag,typename MatA::value_type alpha
245  ){
246  typename device_traits<Device>:: template multiply_assign<typename common_value_type<MatA,MatB>::type> f(alpha);
247  kernels::assign(A,B,f);
248  }
249  template<class MatA, class MatB, class Device>
250  void assign(
251  matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B,
252  blockwise_tag, typename MatA::value_type alpha = 1
253  ){
254  B().assign_to(A,alpha);
255  }
256  template<class MatA, class MatB, class Device>
257  void plus_assign(matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B,elementwise_tag){
258  kernels::assign<typename device_traits<Device>:: template add<typename common_value_type<MatA,MatB>::type> > (A, B);
259  }
260  template<class MatA, class MatB, class Device>
261  void plus_assign(
262  matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B,
263  elementwise_tag, typename MatA::value_type alpha
264  ){
265  typename device_traits<Device>:: template multiply_and_add<typename common_value_type<MatA,MatB>::type> f(alpha);
266  kernels::assign(A,B,f);
267  }
268  template<class MatA, class MatB, class Device>
269  void plus_assign(
270  matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B,
271  blockwise_tag, typename MatA::value_type alpha = 1
272  ){
273  B().plus_assign_to(A,alpha);
274  }
275 }
276 
277 
278 /// \brief Dispatches matrix assignment on an expression level
279 ///
280 /// This dispatcher takes care for whether the blockwise evaluation
281 /// or the elementwise evaluation is called
282 template<class MatA, class MatB, class Device>
283 MatA& assign(matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B){
284  REMORA_SIZE_CHECK(A().size1() == B().size1());
285  REMORA_SIZE_CHECK(A().size2() == B().size2());
286  detail::assign(A,B, typename MatB::evaluation_category());
287  return A();
288 }
289 
290 /// \brief Dispatches matrix assignment on an expression level
291 ///
292 /// This dispatcher takes care for whether the blockwise evaluation
293 /// or the elementwise evaluation is called
294 template<class MatA, class MatB, class Device>
295 MatA& assign(matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B, typename MatA::value_type alpha){
296  REMORA_SIZE_CHECK(A().size1() == B().size1());
297  REMORA_SIZE_CHECK(A().size2() == B().size2());
298  detail::assign(A,B, typename MatB::evaluation_category(),alpha);
299  return A();
300 }
301 
302 /// \brief Dispatches matrix plus-assignment on an expression level
303 ///
304 /// This dispatcher takes care for whether the blockwise evaluation
305 /// or the elementwise evaluation is called
306 template<class MatA, class MatB, class Device>
307 MatA& plus_assign(matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B){
308  REMORA_SIZE_CHECK(A().size1() == B().size1());
309  REMORA_SIZE_CHECK(A().size2() == B().size2());
310  detail::plus_assign(A,B, typename MatB::evaluation_category());
311  return A();
312 }
313 
314 /// \brief Dispatches matrix plus-assignment on an expression level
315 ///
316 /// This dispatcher takes care for whether the blockwise evaluation
317 /// or the elementwise evaluation is called
318 template<class MatA, class MatB, class Device>
319 MatA& plus_assign(matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B, typename MatA::value_type alpha){
320  REMORA_SIZE_CHECK(A().size1() == B().size1());
321  REMORA_SIZE_CHECK(A().size2() == B().size2());
322  detail::plus_assign(A,B, typename MatB::evaluation_category(),alpha);
323  return A();
324 }
325 
326 /// \brief Dispatches matrix multiply-assignment on an expression level
327 ///
328 /// This dispatcher takes care for whether the blockwise evaluation
329 /// or the elementwise evaluation is called
330 template<class MatA, class MatB, class Device>
331 MatA& multiply_assign(matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B){
332  REMORA_SIZE_CHECK(A().size1() == B().size1());
333  REMORA_SIZE_CHECK(A().size2() == B().size2());
334  auto&& Beval = eval_block(B);
335  kernels::assign<typename device_traits<Device>:: template multiply<typename common_value_type<MatA,MatB>::type> > (A, Beval);
336  return A();
337 }
338 
339 /// \brief Dispatches matrix divide-assignment on an expression level
340 ///
341 /// This dispatcher takes care for whether the blockwise evaluation
342 /// or the elementwise evaluation is called
343 template<class MatA, class MatB, class Device>
344 MatA& divide_assign(matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B){
345  REMORA_SIZE_CHECK(A().size1() == B().size1());
346  REMORA_SIZE_CHECK(A().size2() == B().size2());
347  auto&& Beval = eval_block(B);
348  kernels::assign<typename device_traits<Device>:: template divide<typename common_value_type<MatA,MatB>::type> > (A, Beval);
349  return A();
350 }
351 
352 //////////////////////////////////////////////////////////////////////////////////////
353 ///// Vector Operators
354 /////////////////////////////////////////////////////////////////////////////////////
355 
356 /// \brief Add-Assigns two vector expressions
357 ///
358 /// Performs the operation x_i+=v_i for all elements.
359 /// Assumes that the right and left hand side aliases and therefore
360 /// performs a copy of the right hand side before assigning
361 /// use noalias as in noalias(x)+=v to avoid this if A and B do not alias
362 template<class VecX, class VecV, class Device>
363 VecX& operator+=(vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v){
364  REMORA_SIZE_CHECK(x().size() == v().size());
365  typename vector_temporary<VecX>::type temporary(v);
366  return plus_assign(x,temporary);
367 }
368 
369 /// \brief Subtract-Assigns two vector expressions
370 ///
371 /// Performs the operation x_i-=v_i for all elements.
372 /// Assumes that the right and left hand side aliases and therefore
373 /// performs a copy of the right hand side before assigning
374 /// use noalias as in noalias(x)-=v to avoid this if A and B do not alias
375 template<class VecX, class VecV, class Device>
376 VecX& operator-=(vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v){
377  REMORA_SIZE_CHECK(x().size() == v().size());
378  typename vector_temporary<VecX>::type temporary(v);
379  return plus_assign(x,temporary, typename VecX::value_type(-1.0));
380 }
381 
382 /// \brief Multiply-Assigns two vector expressions
383 ///
384 /// Performs the operation x_i*=v_i for all elements.
385 /// Assumes that the right and left hand side aliases and therefore
386 /// performs a copy of the right hand side before assigning
387 /// use noalias as in noalias(x)*=v to avoid this if A and B do not alias
388 template<class VecX, class VecV, class Device>
389 VecX& operator*=(vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v){
390  REMORA_SIZE_CHECK(x().size() == v().size());
391  typename vector_temporary<VecX>::type temporary(v);
392  return multiply_assign(x,temporary);
393 }
394 
395 /// \brief Divide-Assigns two vector expressions
396 ///
397 /// Performs the operation x_i/=v_i for all elements.
398 /// Assumes that the right and left hand side aliases and therefore
399 /// performs a copy of the right hand side before assigning
400 /// use noalias as in noalias(x)/=v to avoid this if A and B do not alias
401 template<class VecX, class VecV, class Device>
402 VecX& operator/=(vector_expression<VecX, Device>& x, vector_expression<VecV, Device> const& v){
403  REMORA_SIZE_CHECK(x().size() == v().size());
404  typename vector_temporary<VecX>::type temporary(v);
405  return divide_assign(x,temporary);
406 }
407 
408 /// \brief Adds a scalar to all elements of the vector
409 ///
410 /// Performs the operation x_i += t for all elements.
411 template<class VecX, class T, class Device>
412 typename std::enable_if<std::is_convertible<T, typename VecX::value_type>::value,VecX&>::type
413 operator+=(vector_expression<VecX, Device>& x, T t){
414  kernels::assign<typename device_traits<Device>:: template add<typename VecX::value_type> > (x, t);
415  return x();
416 }
417 
418 /// \brief Subtracts a scalar from all elements of the vector
419 ///
420 /// Performs the operation x_i += t for all elements.
421 template<class VecX, class T, class Device>
422 typename std::enable_if<std::is_convertible<T, typename VecX::value_type>::value,VecX&>::type
423 operator-=(vector_expression<VecX, Device>& x, T t){
424  kernels::assign<typename device_traits<Device>:: template subtract<typename VecX::value_type> > (x, t);
425  return x();
426 }
427 
428 /// \brief Multiplies a scalar with all elements of the vector
429 ///
430 /// Performs the operation x_i *= t for all elements.
431 template<class VecX, class T, class Device>
432 typename std::enable_if<std::is_convertible<T, typename VecX::value_type>::value,VecX&>::type
433 operator*=(vector_expression<VecX, Device>& x, T t){
434  kernels::assign<typename device_traits<Device>:: template multiply<typename VecX::value_type> > (x, t);
435  return x();
436 }
437 
438 /// \brief Divides all elements of the vector by a scalar
439 ///
440 /// Performs the operation x_i /= t for all elements.
441 template<class VecX, class T, class Device>
442 typename std::enable_if<std::is_convertible<T, typename VecX::value_type>::value,VecX&>::type
443 operator/=(vector_expression<VecX, Device>& x, T t){
444  kernels::assign<typename device_traits<Device>:: template divide<typename VecX::value_type> > (x, t);
445  return x();
446 }
447 
448 
449 
450 //////////////////////////////////////////////////////////////////////////////////////
451 ///// Matrix Operators
452 /////////////////////////////////////////////////////////////////////////////////////
453 
454 /// \brief Add-Assigns two matrix expressions
455 ///
456 /// Performs the operation A_ij+=B_ij for all elements.
457 /// Assumes that the right and left hand side aliases and therefore
458 /// performs a copy of the right hand side before assigning
459 /// use noalias as in noalias(A)+=B to avoid this if A and B do not alias
460 template<class MatA, class MatB, class Device>
461 MatA& operator+=(matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B){
462  REMORA_SIZE_CHECK(A().size1() == B().size1());
463  REMORA_SIZE_CHECK(A().size2() == B().size2());
464  typename matrix_temporary<MatA>::type temporary(B);
465  return plus_assign(A,temporary);
466 }
467 
468 /// \brief Subtract-Assigns two matrix expressions
469 ///
470 /// Performs the operation A_ij-=B_ij for all elements.
471 /// Assumes that the right and left hand side aliases and therefore
472 /// performs a copy of the right hand side before assigning
473 /// use noalias as in noalias(A)-=B to avoid this if A and B do not alias
474 template<class MatA, class MatB, class Device>
475 MatA& operator-=(matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B){
476  REMORA_SIZE_CHECK(A().size1() == B().size1());
477  REMORA_SIZE_CHECK(A().size2() == B().size2());
478  typename matrix_temporary<MatA>::type temporary(B);
479  return plus_assign(A,temporary, typename MatA::value_type(-1.0));
480 }
481 
482 /// \brief Multiply-Assigns two matrix expressions
483 ///
484 /// Performs the operation A_ij*=B_ij for all elements.
485 /// Assumes that the right and left hand side aliases and therefore
486 /// performs a copy of the right hand side before assigning
487 /// use noalias as in noalias(A)*=B to avoid this if A and B do not alias
488 template<class MatA, class MatB, class Device>
489 MatA& operator*=(matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B){
490  REMORA_SIZE_CHECK(A().size1() == B().size1());
491  REMORA_SIZE_CHECK(A().size2() == B().size2());
492  typename matrix_temporary<MatA>::type temporary(B);
493  return multiply_assign(A,temporary);
494 }
495 
496 /// \brief Divide-Assigns two matrix expressions
497 ///
498 /// Performs the operation A_ij/=B_ij for all elements.
499 /// Assumes that the right and left hand side aliases and therefore
500 /// performs a copy of the right hand side before assigning
501 /// use noalias as in noalias(A)/=B to avoid this if A and B do not alias
502 template<class MatA, class MatB, class Device>
503 MatA& operator/=(matrix_expression<MatA, Device>& A, matrix_expression<MatB, Device> const& B){
504  REMORA_SIZE_CHECK(A().size1() == B().size1());
505  REMORA_SIZE_CHECK(A().size2() == B().size2());
506  typename matrix_temporary<MatA>::type temporary(B);
507  return divide_assign(A,temporary);
508 }
509 
510 /// \brief Adds a scalar to all elements of the matrix
511 ///
512 /// Performs the operation A_ij += t for all elements.
513 template<class MatA, class T, class Device>
514 typename std::enable_if<std::is_convertible<T, typename MatA::value_type>::value,MatA&>::type
515 operator+=(matrix_expression<MatA, Device>& A, T t){
516  kernels::assign<typename device_traits<Device>:: template add<typename MatA::value_type> > (A, t);
517  return A();
518 }
519 
520 /// \brief Subtracts a scalar from all elements of the matrix
521 ///
522 /// Performs the operation A_ij -= t for all elements.
523 template<class MatA, class T, class Device>
524 typename std::enable_if<std::is_convertible<T, typename MatA::value_type>::value,MatA&>::type
525 operator-=(matrix_expression<MatA, Device>& A, T t){
526  kernels::assign<typename device_traits<Device>:: template subtract<typename MatA::value_type> > (A, t);
527  return A();
528 }
529 
530 /// \brief Multiplies a scalar to all elements of the matrix
531 ///
532 /// Performs the operation A_ij *= t for all elements.
533 template<class MatA, class T, class Device>
534 typename std::enable_if<std::is_convertible<T, typename MatA::value_type>::value,MatA&>::type
535 operator*=(matrix_expression<MatA, Device>& A, T t){
536  kernels::assign<typename device_traits<Device>:: template multiply<typename MatA::value_type> > (A, t);
537  return A();
538 }
539 
540 /// \brief Divides all elements of the matrix by a scalar
541 ///
542 /// Performs the operation A_ij /= t for all elements.
543 template<class MatA, class T, class Device>
544 typename std::enable_if<std::is_convertible<T, typename MatA::value_type>::value,MatA&>::type
545 operator/=(matrix_expression<MatA, Device>& A, T t){
546  kernels::assign<typename device_traits<Device>:: template divide<typename MatA::value_type> > (A, t);
547  return A();
548 }
549 
550 
551 
552 //////////////////////////////////////////////////////////////////////////////////////
553 ///// Temporary Proxy Operators
554 /////////////////////////////////////////////////////////////////////////////////////
555 
556 template<class T, class U>
557 temporary_proxy<T> operator+=(temporary_proxy<T> x, U const& arg){
558  static_cast<T&>(x) += arg;
559  return x;
560 }
561 template<class T, class U>
562 temporary_proxy<T> operator-=(temporary_proxy<T> x, U const& arg){
563  static_cast<T&>(x) -= arg;
564  return x;
565 }
566 template<class T, class U>
567 temporary_proxy<T> operator*=(temporary_proxy<T> x, U const& arg){
568  static_cast<T&>(x) *= arg;
569  return x;
570 }
571 template<class T, class U>
572 temporary_proxy<T> operator/=(temporary_proxy<T> x, U const& arg){
573  static_cast<T&>(x) /= arg;
574  return x;
575 }
576 
577 
578 
579 
580 // Assignment proxy.
581 // Provides temporary free assigment when LHS has no alias on RHS
582 template<class C>
583 class noalias_proxy{
584 public:
585  typedef typename C::closure_type closure_type;
586  typedef typename C::value_type value_type;
587 
588  noalias_proxy(C &lval): m_lval(lval) {}
589 
590  noalias_proxy(const noalias_proxy &p):m_lval(p.m_lval) {}
591 
592  template <class E>
593  closure_type &operator= (const E &e) {
594  return assign(m_lval, e);
595  }
596 
597  template <class E>
598  closure_type &operator+= (const E &e) {
599  return plus_assign(m_lval, e);
600  }
601 
602  template <class E>
603  closure_type &operator-= (const E &e) {
604  return plus_assign(m_lval, e, typename C::value_type(-1));
605  }
606 
607  template <class E>
608  closure_type &operator*= (const E &e) {
609  return multiply_assign(m_lval, e);
610  }
611 
612  template <class E>
613  closure_type &operator/= (const E &e) {
614  return divide_assign(m_lval, e);
615  }
616 
617  //this is not needed, but prevents errors when for example doing noalias(x)+=2;
618  closure_type &operator+= (value_type t) {
619  return m_lval += t;
620  }
621 
622  //this is not needed, but prevents errors when for example doing noalias(x)-=2;
623  closure_type &operator-= (value_type t) {
624  return m_lval -= t;
625  }
626 
627  //this is not needed, but prevents errors when for example doing noalias(x)*=2;
628  closure_type &operator*= (value_type t) {
629  return m_lval *= t;
630  }
631 
632  //this is not needed, but prevents errors when for example doing noalias(x)/=2;
633  closure_type &operator/= (value_type t) {
634  return m_lval /= t;
635  }
636 
637 private:
638  closure_type m_lval;
639 };
640 
641 // Improve syntax of efficient assignment where no aliases of LHS appear on the RHS
642 // noalias(lhs) = rhs_expression
643 template <class C, class Device>
644 noalias_proxy<C> noalias(matrix_expression<C, Device>& lvalue) {
645  return noalias_proxy<C> (lvalue());
646 }
647 template <class C, class Device>
648 noalias_proxy<C> noalias(vector_expression<C, Device>& lvalue) {
649  return noalias_proxy<C> (lvalue());
650 }
651 
652 template <class C, class Device>
653 noalias_proxy<C> noalias(vector_set_expression<C>& lvalue) {
654  return noalias_proxy<C> (lvalue());
655 }
656 template <class C>
657 noalias_proxy<C> noalias(temporary_proxy<C> lvalue) {
658  return noalias_proxy<C> (static_cast<C&>(lvalue));
659 }
660 
661 }
662 #endif