vector_assign.hpp
Go to the documentation of this file.
1 /*!
2  * \brief Assignment kernels for vector expressions
3  *
4  * \author O. Krause
5  * \date 2015
6  *
7  *
8  * \par Copyright 1995-2015 Shark Development Team
9  *
10  * <BR><HR>
11  * This file is part of Shark.
12  * <http://image.diku.dk/shark/>
13  *
14  * Shark is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU Lesser General Public License as published
16  * by the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * Shark is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public License
25  * along with Shark. If not, see <http://www.gnu.org/licenses/>.
26  *
27  */
28 #ifndef REMORA_KERNELS_DEFAULT_VECTOR_ASSIGN_HPP
29 #define REMORA_KERNELS_DEFAULT_VECTOR_ASSIGN_HPP
30 
31 #include "../../expression_types.hpp"
32 
33 namespace remora{namespace bindings{
34 
35 template<class F, class V>
36 void assign(vector_expression<V, cpu_tag>& v, typename V::value_type t) {
37  F f;
38  typedef typename V::iterator iterator;
39  iterator end = v().end();
40  for (iterator it = v().begin(); it != end; ++it){
41  *it = f(*it, t);
42  }
43 }
44 
45 /////////////////////////////////////////////////////////
46 //direct assignment of two vectors
47 ////////////////////////////////////////////////////////
48 
49 // Dense-Dense case
50 template< class V, class E>
51 void vector_assign(
52  vector_expression<V, cpu_tag>& v, vector_expression<E, cpu_tag> const& e,
53  dense_tag, dense_tag
54 ) {
55  for(std::size_t i = 0; i != v().size(); ++i){
56  v()(i) = static_cast<typename V::value_type>(e()(i));
57  }
58 }
59 // Dense-packed case
60 template< class V, class E>
61 void vector_assign(
62  vector_expression<V, cpu_tag>& v, vector_expression<E, cpu_tag> const& e,
63  dense_tag, packed_tag
64 ) {
65  typedef typename E::const_iterator EIterator;
66  typedef typename V::value_type value_type;
67  EIterator eiter = e.begin();
68  EIterator eend = e.end();
69  //special case:
70  //right hand side is completely 0
71  if(eiter == eend){
72  v().clear();
73  return;
74  }
75  EIterator viter = v.begin();
76  EIterator vend = v.end();
77 
78  //set the first elements to zero
79  for(;viter.index() != eiter.index(); ++viter){
80  *viter= value_type/*zero*/();
81  }
82  //copy contents of right-hand side
83  for(;eiter != eend; ++eiter,++viter){
84  *viter= *eiter;
85  }
86 
87  for(;viter!= vend; ++viter){
88  *viter= value_type/*zero*/();
89  }
90 }
91 
92 // packed-packed case
93 template< class V, class E>
94 void vector_assign(
95  vector_expression<V, cpu_tag>& v, vector_expression<E, cpu_tag> const& e,
96  packed_tag, packed_tag
97 ) {
98  typedef typename E::const_iterator EIterator;
99  EIterator eiter = e.begin();
100  EIterator eend = e.end();
101  //special case:
102  //right hand side is completely 0
103  if(eiter == eend){
104  v().clear();
105  return;
106  }
107  EIterator viter = v.begin();
108  EIterator vend = v.end();
109 
110  //check for compatible layout
111  REMORA_SIZE_CHECK(vend-viter);//empty ranges can't be compatible
112  //check whether the right hand side range is included in the left hand side range
113  REMORA_SIZE_CHECK(viter.index() <= eiter.index());
114  REMORA_SIZE_CHECK(viter.index()+(vend-viter) >= eiter.index()+(eend-eiter));
115 
116  //copy contents of right-hand side
117  viter += eiter.index()-viter.index();
118  for(;eiter != eend; ++eiter,++viter){
119  *viter= *eiter;
120  }
121 }
122 
123 //Dense-Sparse case
124 template<class V, class E>
125 void vector_assign(
126  vector_expression<V, cpu_tag>& v,
127  vector_expression<E, cpu_tag> const& e,
128  dense_tag,
129  sparse_tag
130 ) {
131  v().clear();
132  typedef typename E::const_iterator iterator;
133  iterator end = e().end();
134  for(iterator it = e().begin(); it != end; ++it){
135  v()(it.index()) = *it;
136  }
137 }
138 //Sparse-Dense
139 template<class V, class E>
140 void vector_assign(
141  vector_expression<V, cpu_tag>& v,
142  vector_expression<E, cpu_tag> const& e,
143  sparse_tag,
144  dense_tag
145 ) {
146  v().clear();
147  v().reserve(e().size());
148  typename V::iterator targetPos = v().begin();
149  REMORA_RANGE_CHECK(targetPos == v().end());//as v is cleared, pos must be equal to end
150  for(std::size_t i = 0; i != e().size(); ++i,++targetPos){
151  targetPos = v().set_element(targetPos,i,e()(i));
152  }
153 }
154 // Sparse-Sparse case
155 template<class V, class E>
156 void vector_assign(
157  vector_expression<V, cpu_tag>& v,
158  vector_expression<E, cpu_tag> const& e,
159  sparse_tag,
160  sparse_tag
161 ) {
162  v().clear();
163  typedef typename E::const_iterator iteratorE;
164  typename V::iterator targetPos = v().begin();
165  REMORA_RANGE_CHECK(targetPos == v().end());//as v is cleared, pos must be equal to end
166  iteratorE end = e().end();
167  for(iteratorE it = e().begin(); it != end; ++it,++targetPos){
168  targetPos = v().set_element(targetPos,it.index(),*it);
169  }
170 }
171 
172 ////////////////////////////////////////////
173 //assignment with functor
174 ////////////////////////////////////////////
175 
176 //dense dense case
177 template<class V, class E, class F>
178 void vector_assign_functor(
179  vector_expression<V, cpu_tag>& v,
180  vector_expression<E, cpu_tag> const& e,
181  F f,
182  dense_tag, dense_tag
183 ) {
184  for(std::size_t i = 0; i != v().size(); ++i){
185  v()(i) = f(v()(i),e()(i));
186  }
187 }
188 
189 //dense packed case
190 template<class V, class E, class F>
191 void vector_assign_functor(
192  vector_expression<V, cpu_tag>& v,
193  vector_expression<E, cpu_tag> const& e,
194  F f,
195  dense_tag, packed_tag
196 ) {
197  typedef typename E::const_iterator EIterator;
198  typedef typename V::const_iterator VIterator;
199  typedef typename V::value_type value_type;
200  EIterator eiter = e().begin();
201  EIterator eend = e().end();
202  VIterator viter = v().begin();
203  VIterator vend = v().end();
204  //right hand side hasnonzero elements
205  if(eiter != eend){
206  //apply f to the first elements for which the right hand side is 0, unless f is the identity
207  for(;viter.index() != eiter.index() &&!F::right_zero_identity; ++viter){
208  *viter = f(*viter,value_type/*zero*/());
209  }
210  //copy contents of right-hand side
211  for(;eiter != eend; ++eiter,++viter){
212  *viter = f(*viter,*eiter);
213  }
214  }
215  //apply f to the last elements for which the right hand side is 0, unless f is the identity
216  for(;viter!= vend &&!F::right_zero_identity; ++viter){
217  *viter= value_type/*zero*/();
218  }
219 }
220 
221 //packed-packed case
222 template<class V, class E, class F>
223 void vector_assign_functor(
224  vector_expression<V, cpu_tag>& v,
225  vector_expression<E, cpu_tag> const& e,
226  F f,
227  packed_tag, packed_tag
228 ) {
229  typedef typename E::const_iterator EIterator;
230  typedef typename V::const_iterator VIterator;
231  typedef typename V::value_type value_type;
232  EIterator eiter = e().begin();
233  EIterator eend = e().end();
234  VIterator viter = v().begin();
235  VIterator vend = v().end();
236 
237  //right hand side has nonzero elements
238  if(eiter != eend){
239 
240  //check for compatible layout
241  REMORA_SIZE_CHECK(vend-viter);//empty ranges can't be compatible
242  //check whether the right hand side range is included in the left hand side range
243  REMORA_SIZE_CHECK(viter.index() <= eiter.index());
244  REMORA_SIZE_CHECK(viter.index()+(vend-viter) >= eiter.index()+(eend-eiter));
245 
246  //apply f to the first elements for which the right hand side is 0, unless f is the identity
247  for(;viter.index() != eiter.index() &&!F::right_zero_identity; ++viter){
248  *viter = f(*viter,value_type/*zero*/());
249  }
250  //copy contents of right-hand side
251  for(;eiter != eend; ++eiter,++viter){
252  *viter = f(*viter,*eiter);
253  }
254  }
255  //apply f to the last elements for which the right hand side is 0, unless f is the identity
256  for(;viter!= vend &&!F::right_zero_identity; ++viter){
257  *viter= f(*viter,value_type/*zero*/());
258  }
259 }
260 
261 //Dense-Sparse case
262 template<class V, class E, class F>
263 void vector_assign_functor(
264  vector_expression<V, cpu_tag>& v,
265  vector_expression<E, cpu_tag> const& e,
266  F f,
267  dense_tag, sparse_tag
268 ) {
269  typedef typename E::const_iterator iterator;
270  iterator end = e().end();
271  for(iterator it = e().begin(); it != end; ++it){
272  v()(it.index()) = f(v()(it.index()),*it);
273  }
274 }
275 
276 //sparse-dense case
277 template<class V, class E, class F>
278 void vector_assign_functor(
279  vector_expression<V, cpu_tag>& v,
280  vector_expression<E, cpu_tag> const& e,
281  F f,
282  sparse_tag tag, dense_tag
283 ){
284  typedef typename V::value_type value_type;
285  typedef typename V::size_type size_type;
286  value_type zero = value_type();
287  size_type size = e().size();
288 
289  typename V::iterator it = v().begin();
290  for(size_type i = 0; i != size; ++i,++it){
291  if(it == v().end() || it.index() != i){//insert missing elements
292  it = v().set_element(it,i,zero);
293  }
294  *it = f(*it, e()(i));
295  }
296 }
297 
298 // Sparse-Sparse case has three implementations.
299 //the stupidity of this case is, that we have to assume in the general case v and e share the same
300 //array memory and thus changing v might invalidate the iterators of e.
301 //This is not the same as aliasing of v and e, as v might be for example one matrix row and e another
302 //of the same matrix.
303 //thus we look at the cases where (at least) one of the arguments is a vector-container, which means
304 //that we are not facing the problem of same memory as this would otherwise mean that we are aliasing
305 //in which case the expression is not defined anyways.
306 
307 //called for independent argumeents v and e
308 template<class V, class E, class F>
309 void assign_sparse(
310  vector_expression<V, cpu_tag>& v,
311  vector_expression<E, cpu_tag> const& e,
312  F f
313 ){
314  typedef typename V::value_type value_type;
315  typedef typename V::size_type size_type;
316  value_type zero = value_type();
317 
318  typename V::iterator it = v().begin();
319  typename E::const_iterator ite = e().begin();
320  typename E::const_iterator ite_end = e().end();
321  while(it != v().end() && ite != ite_end) {
322  size_type it_index = it.index();
323  size_type ite_index = ite.index();
324  if (it_index == ite_index) {
325  *it = f(*it, *ite);
326  ++ ite;
327  } else if (it_index < ite_index) {
328  *it = f(*it, zero);
329  } else{//it_index > ite_index so insert new element in v()
330  it = v().set_element(it,ite_index,zero);
331  *it = f(*it, *ite);
332  ++ite;
333  }
334  ++it;
335  }
336  //apply zero transformation on elements which are not transformed yet
337  for(;it != v().end();++it) {
338  *it = f(*it, zero);
339  }
340  //add missing elements
341  for(;ite != ite_end;++it,++ite) {
342  it = v().set_element(it,ite.index(),zero);
343  *it = f(*it, *ite);
344  }
345 }
346 //as long as one argument is not a proxy, we are in the good case.
347 template<class V, class E, class F>
348 void vector_assign_functor(
349  vector_expression<V, cpu_tag>& v,
350  vector_container<E, cpu_tag> const& e,
351  F f,
352  sparse_tag tag, sparse_tag
353 ){
354  assign_sparse(v,e);
355 }
356 template<class V, class E, class F>
357 void vector_assign_functor(
358  vector_container<V, cpu_tag>& v,
359  vector_expression<E, cpu_tag> const& e,
360  F f,
361  sparse_tag tag, sparse_tag
362 ){
363  assign_sparse(v,e,f);
364 }
365 template<class V, class E, class F>
366 void vector_assign_functor(
367  vector_container<V, cpu_tag>& v,
368  vector_container<E, cpu_tag> const& e,
369  F f,
370  sparse_tag tag, sparse_tag
371 ){
372  assign_sparse(v,e,f);
373 }
374 
375 
376 //In the general case we have to take one bullet:
377 //either use a temporary, which has copying time and allocation time
378 //or count the non-zero elements of e which might be expensive as well. we decide
379 //to take the first route for now.
380 template<class V, class E, class F>
381 void vector_assign_functor(
382  vector_expression<V, cpu_tag>& v,
383  vector_expression<E, cpu_tag> const& e,
384  F f,
385  sparse_tag tag, sparse_tag
386 ){
387  typename vector_temporary<V>::type temporary(v());
388  assign_sparse(temporary,e, f);
389  v().clear();
390  bindings::vector_assign(v, temporary, tag, tag);
391 }
392 
393 }}
394 #endif