BatchInterfaceAdaptStruct.h
Go to the documentation of this file.
1 /*!
2  *
3  *
4  * \brief Defines an batch adptor for structures.
5  *
6  *
7  *
8  * \author O.Krause
9  * \date 2012
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 #ifndef SHARK_DATA_BATCHINTERFACEADAPTSTRUCT_H
33 #define SHARK_DATA_BATCHINTERFACEADAPTSTRUCT_H
34 
35 #include <boost/fusion/sequence/intrinsic/swap.hpp>
36 #include <boost/fusion/algorithm/iteration/for_each.hpp>
37 #include <boost/fusion/algorithm/transformation/transform.hpp>
39 
40 #include <boost/preprocessor/seq/transform.hpp>
41 #include "Impl/BoostFusion151DefineStructInl.hpp"
42 namespace shark{
43 namespace detail{
44 ///serializes the object into the archive
45 template<class Archive>
46 struct ItemSerializer {
47  ItemSerializer(Archive& ar):m_ar(ar) {}
48 
49  template<typename T>
50  void operator()(T& o)const{
51  m_ar & o;
52  }
53 private:
54  Archive& m_ar;
55 };
56 
57 
58 struct CreateBatch{
59  CreateBatch(std::size_t size):m_size(size) {}
60 
61  template<class> struct result;
62  template<class T>
63  struct result<CreateBatch(T const&)> {
64  typedef typename shark::Batch<T>::type type;
65  };
66 
67  template<class T>
68  typename result<CreateBatch(T const&)>::type operator()(T const& value)const{
69  return shark::Batch<T>::createBatch(value,m_size);
70  }
71 private:
72  std::size_t m_size;
73 };
74 struct resize{
75  resize(std::size_t size1, std::size_t size2):m_size1(size1),m_size2(size2){};
76  template<class T>
77  void operator()(T& batch)const{
78  shark::Batch<typename boost::range_value<T>::type>::resize(batch,m_size1,m_size2);
79  }
80 private:
81  std::size_t m_size1;
82  std::size_t m_size2;
83 };
84 
85 ///calls get(container,index) on a container. Used as boost fusion functor in the creation of references in the Batch Interface
86 struct MakeRef{
87  template<class> struct result;
88  template<class T>
89  struct result<MakeRef(T const&)> {
90  typedef typename boost::range_reference<T>::type type;
91  };
92 
93  MakeRef(std::size_t index):m_index(index){}
94 
95  template<class T>
96  typename result<MakeRef(T const&) >::type operator()(T const& container)const{
97  return get(const_cast<T&>(container),m_index);//we need the const cast since the argument type must be a const ref.
98  }
99 private:
100  std::size_t m_index;
101 };
102 ///calls get(container,index) on a container. Used as boost fusion functor in the cration of references in the Batch Interface
103 struct MakeConstRef{
104  template<class> struct result;
105  template<class T>
106  struct result<MakeConstRef(T const&)> {
107  typedef typename boost::range_reference<T const>::type type;
108  };
109 
110  MakeConstRef(std::size_t index):m_index(index){}
111 
112  template<class T>
113  typename result<MakeConstRef(T const&) >::type operator()(T const& container)const{
114  return get(container,m_index);
115  }
116 private:
117  std::size_t m_index;
118 };
119 
120 template<class FusionSequence>
121 struct FusionFacade: public FusionSequence{
122  FusionFacade(){}
123  template<class Sequence>
124  FusionFacade(Sequence const& sequence):FusionSequence(sequence){}
125 };
126 
127 template<class Type>
128 struct isFusionFacade{
129 private:
130  struct Big{ int big[100]; };
131  template <class S>
132  static Big tester(FusionFacade<S>*);
133  template <class S>
134  static Big tester(FusionFacade<S> const*);
135  static char tester(...);
136  static Type* generator();
137 
138  BOOST_STATIC_CONSTANT(std::size_t, size = sizeof(tester(generator())));
139 public:
140  BOOST_STATIC_CONSTANT(bool, value = (size!= 1));
141  typedef boost::mpl::bool_<value> type;
142 };
143 
144 }
145 
146 template<class S>
147 S& fusionize(detail::FusionFacade<S> & facade){
148  return static_cast<S&>(facade);
149 }
150 template<class S>
151 S const& fusionize(detail::FusionFacade<S> const& facade){
152  return static_cast<S const&>(facade);
153 }
154 
155 template<class S>
156 typename boost::disable_if<detail::isFusionFacade<S>,S&>::type
157 fusionize(S& facade){
158  return facade;
159 }
160 template<class S>
161 typename boost::disable_if<detail::isFusionFacade<S>,S const& >::type
162 fusionize(S const& facade){
163  return facade;
164 }
165 }
166 #define SHARK_TRANSFORM_BATCH_ATTRIBUTES_TPL_IMPL(s,TYPE,ELEM)\
167  ( typename Batch<BOOST_PP_TUPLE_ELEM(2, 0, ELEM)>::TYPE,BOOST_PP_TUPLE_ELEM(2, 1, ELEM))
168 
169 #define SHARK_TRANSFORM_TUPLELIST_IMPL(s, data,ELEM)\
170  BOOST_PP_TUPLE_ELEM(2, 0, ELEM),BOOST_PP_TUPLE_ELEM(2, 1, ELEM)
171 #define SHARK_TRANSFORM_TUPLELIST(ELEMS)\
172  BOOST_PP_SEQ_TRANSFORM(SHARK_TRANSFORM_TUPLELIST_IMPL, _ , ELEMS)
173 
174 #define SHARK_TRANSFORM_BATCH_ATTRIBUTES_TPL(TYPE,ATTRIBUTES)\
175  SHARK_TRANSFORM_TUPLELIST(BOOST_PP_SEQ_TRANSFORM(\
176  SHARK_TRANSFORM_BATCH_ATTRIBUTES_TPL_IMPL,\
177  TYPE, BOOST_PP_CAT(SHARK_FUSION_ADAPT_STRUCT_FILLER_0 ATTRIBUTES,_END)))
178 
179 #define SHARK_TRANSFORM_BATCH_ATTRIBUTES_IMPL(s,TYPE,ELEM)\
180  ( Batch<BOOST_PP_TUPLE_ELEM(2, 0, ELEM)>::TYPE,BOOST_PP_TUPLE_ELEM(2, 1, ELEM))
181 
182 #define SHARK_TRANSFORM_BATCH_ATTRIBUTES(TYPE,ATTRIBUTES)\
183  SHARK_TRANSFORM_TUPLELIST(BOOST_PP_SEQ_TRANSFORM(\
184  SHARK_TRANSFORM_BATCH_ATTRIBUTES_IMPL,\
185  TYPE, BOOST_PP_CAT(SHARK_FUSION_ADAPT_STRUCT_FILLER_0 ATTRIBUTES,_END)))
186 
187 ///\brief creates default implementation for reference or const_reference types of Batches
188 #define SHARK_CREATE_BATCH_REFERENCES_TPL(ATTRIBUTES)\
189 private:\
190 SHARK_FUSION_DEFINE_STRUCT_REF_INLINE(FusionRef, SHARK_TRANSFORM_BATCH_ATTRIBUTES_TPL(reference,ATTRIBUTES))\
191 SHARK_FUSION_DEFINE_STRUCT_CONST_REF_INLINE(FusionConstRef, SHARK_TRANSFORM_BATCH_ATTRIBUTES_TPL(const_reference,ATTRIBUTES))\
192 public:\
193 struct reference: public detail::FusionFacade<FusionRef>{\
194  template<class Batch>\
195  reference(Batch& batch, std::size_t i)\
196  :detail::FusionFacade<FusionRef>(boost::fusion::transform(fusionize(batch),detail::MakeRef(i))){}\
197  template<class Other>\
198  reference& operator= (Other const& other ){\
199  fusionize(*this) = other;\
200  return *this;\
201  }\
202  reference& operator= (reference const& other ){\
203  fusionize(*this) = other;\
204  return *this;\
205  }\
206  friend void swap(reference op1, reference op2){\
207  boost::fusion::swap(op1,op2);\
208  }\
209  operator value_type()const{\
210  value_type ret;\
211  boost::fusion::copy(fusionize(*this), ret);\
212  return ret;\
213  }\
214 };\
215 struct const_reference: public detail::FusionFacade<FusionConstRef>{\
216 private:\
217 const_reference& operator= (const_reference const& other );\
218 public:\
219  template<class Batch>\
220  const_reference(Batch& batch, std::size_t i)\
221  :detail::FusionFacade<FusionConstRef>(boost::fusion::transform(fusionize(batch),detail::MakeConstRef(i))){}\
222  operator value_type()const{\
223  value_type ret;\
224  boost::fusion::copy(fusionize(*this), ret);\
225  return ret;\
226  }\
227 };
228 
229 #define SHARK_CREATE_BATCH_REFERENCES(ATTRIBUTES)\
230 private:\
231 SHARK_FUSION_DEFINE_STRUCT_REF_INLINE(FusionRef, SHARK_TRANSFORM_BATCH_ATTRIBUTES(reference,ATTRIBUTES))\
232 SHARK_FUSION_DEFINE_STRUCT_CONST_REF_INLINE(FusionConstRef, SHARK_TRANSFORM_BATCH_ATTRIBUTES(const_reference,ATTRIBUTES))\
233 public:\
234 struct reference: public detail::FusionFacade<FusionRef>{\
235  template<class Batch>\
236  reference(Batch& batch, std::size_t i)\
237  :detail::FusionFacade<FusionRef>(boost::fusion::transform(fusionize(batch),detail::MakeRef(i))){}\
238  template<class Other>\
239  reference& operator= (Other const& other ){\
240  fusionize(*this) = other;\
241  return *this;\
242  }\
243  reference& operator= (reference const& other ){\
244  fusionize(*this) = other;\
245  return *this;\
246  }\
247  friend void swap(reference& op1, reference& op2){\
248  boost::fusion::swap(op1,op2);\
249  }\
250  operator value_type()const{\
251  value_type ret;\
252  boost::fusion::copy(fusionize(*this), ret);\
253  return ret;\
254  }\
255 };\
256 struct const_reference: public detail::FusionFacade<FusionConstRef>{\
257  template<class Batch>\
258  const_reference(Batch& batch, std::size_t i)\
259  :detail::FusionFacade<FusionConstRef>(boost::fusion::transform(fusionize(batch),detail::MakeConstRef(i))){}\
260  template<class Other>\
261  const_reference& operator= (Other const& other ){\
262  fusionize(*this) = other;\
263  return *this;\
264  }\
265  operator value_type()const{\
266  value_type ret;\
267  boost::fusion::copy(fusionize(*this), ret);\
268  return ret;\
269  }\
270 };
271 
272 ///\brief creates default typedefs for iterator or const_iterator types of Batches
273 #define SHARK_CREATE_BATCH_ITERATORS()\
274 typedef ProxyIterator<type, value_type, reference > iterator;\
275 typedef ProxyIterator<const type, value_type, const_reference > const_iterator;\
276 iterator begin(){\
277  return iterator(*this,0);\
278 }\
279 const_iterator begin()const{\
280  return const_iterator(*this,0);\
281 }\
282 iterator end(){\
283  return iterator(*this,size());\
284 }\
285 const_iterator end()const{\
286  return const_iterator(*this,size());\
287 }\
288 ///\brief This macro can be used to specialize a structure type easily to a batch type.
289 ///
290 ///Assume, that your input Data looks like:
291 ///<code>
292 ///template<class T>
293 ///struct DataType{
294 /// RealVector A;
295 /// T B;
296 ///};
297 ///</code>
298 ///Than the Batch type should propably look like
299 ///<code>
300 ///struct DataTypeBatch{
301 /// RealMatrix A;
302 /// RealVector B;
303 ///};
304 ///</code>
305 ///In this case the macro can be used to generate a complete specialisation of Batch<DataType>
306 ///<code>
307 ///#define DataVars (RealVector, A)(double B)
308 ///
309 ///SHARK_CREATE_BATCH_INTERFACE( DataType,DataVars)
310 ///};
311 ///As any other batch model th result also offers iterators over the range of elements.
312 ///In this case also boost::fusion support is added to the sequence. e.g. it is
313 ///handled similar to any other tuple type (RealMatrix,RealVector). This is useful for MKL or Transfer
314 ///kernels
315 ///</code>
316 #define SHARK_CREATE_BATCH_INTERFACE(NAME,ATTRIBUTES)\
317 private:\
318  SHARK_FUSION_DEFINE_STRUCT_INLINE(FusionType, SHARK_TRANSFORM_BATCH_ATTRIBUTES_TPL(type,ATTRIBUTES))\
319 public:\
320  struct type: public detail::FusionFacade<FusionType>{\
321  typedef NAME value_type;\
322  \
323  SHARK_CREATE_BATCH_REFERENCES_TPL(ATTRIBUTES)\
324  SHARK_CREATE_BATCH_ITERATORS()\
325  \
326  type(){}\
327  type(std::size_t size1, std::size_t size2){\
328  resize(size1,size2);\
329  }\
330  void resize(std::size_t batchSize, std::size_t elementSize){\
331  boost::fusion::for_each(fusionize(*this), detail::resize(batchSize,elementSize));\
332  }\
333  \
334  friend void swap(type& op1, type& op2){\
335  boost::fusion::swap(fusionize(op1),fusionize(op2));\
336  }\
337  std::size_t size()const{\
338  return shark::size(boost::fusion::at_c<0>(fusionize(*this)));\
339  }\
340  template<class Archive>\
341  void serialize(Archive & archive,unsigned int version)\
342  {\
343  boost::fusion::for_each(fusionize(*this), detail::ItemSerializer<Archive>(archive));\
344  }\
345  };\
346  typedef NAME value_type;\
347  typedef typename type::reference reference;\
348  typedef typename type::const_reference const_reference;\
349  typedef typename type::iterator iterator;\
350  typedef typename type::const_iterator const_iterator;\
351  \
352  static type createBatch(value_type const& input, std::size_t size = 1){\
353  type batch;\
354  boost::fusion::copy(boost::fusion::transform(input,detail::CreateBatch(size)),fusionize(batch));\
355  return batch;\
356  }\
357  template<class Range>\
358  static type createBatchFromRange(Range const& range){\
359  std::size_t points = shark::size(range);\
360  type batch = createBatch(*range.begin(),points);\
361  typename boost::range_iterator<Range>::type pos = range.begin();\
362  for(std::size_t i = 0; i != points; ++i,++pos){\
363  get(batch,i) = *pos;\
364  }\
365  return batch;\
366  }\
367  static void resize(type& batch, std::size_t batchSize, std::size_t elements){\
368  batch.resize(batchSize,elements);\
369  }
370 
371 
372 ///\brief This macro can be used to specialize a structure type easily to a batch type.
373 ///
374 ///Assume, thjat your input Data looks like:
375 ///<code>
376 ///struct DataType{
377 /// RealVector A;
378 /// double B;
379 ///};
380 ///</code>
381 ///Than the Batch type should propably look like
382 ///<code>
383 ///struct DataTypeBatch{
384 /// RealMatrix A;
385 /// RealVector B;
386 ///};
387 ///</code>
388 ///In this case the macro can be used to generate a complete specialisation of Batch<DataType>
389 ///<code>
390 ///#define DataVars (RealVector, A)(double B)
391 ///
392 ///SHARK_CREATE_BATCH_INTERFACE( DataType,DataVars)
393 ///};
394 ///As any other batch model the result also offers iterators over the range of elements.
395 ///In this case also boost::fusion support is added to the sequence. e.g. it is
396 ///handled similar to any other tuple type (RealMatrix,RealVector). This is useful for MKL or Transfer
397 ///kernels
398 ///</code>
399 #define SHARK_CREATE_BATCH_INTERFACE_NO_TPL(NAME,ATTRIBUTES)\
400 private:\
401  SHARK_FUSION_DEFINE_STRUCT_INLINE(FusionType, SHARK_TRANSFORM_BATCH_ATTRIBUTES(type,ATTRIBUTES))\
402 public:\
403  struct type: public detail::FusionFacade<FusionType>{\
404  typedef NAME value_type;\
405  \
406  SHARK_CREATE_BATCH_REFERENCES(ATTRIBUTES)\
407  SHARK_CREATE_BATCH_ITERATORS()\
408  \
409  type(){}\
410  type(std::size_t size1, std::size_t size2){\
411  resize(size1,size2);\
412  }\
413  void resize(std::size_t batchSize, std::size_t elementSize){\
414  boost::fusion::for_each(fusionize(*this), detail::resize(batchSize,elementSize));\
415  }\
416  \
417  friend void swap(type& op1, type& op2){\
418  boost::fusion::swap(fusionize(op1),fusionize(op2));\
419  }\
420  std::size_t size()const{\
421  return shark::size(boost::fusion::at_c<0>(fusionize(*this)));\
422  }\
423  template<class Archive>\
424  void serialize(Archive & archive,unsigned int version)\
425  {\
426  boost::fusion::for_each(fusionize(*this), detail::ItemSerializer<Archive>(archive));\
427  }\
428  };\
429  typedef NAME value_type;\
430  typedef type::reference reference;\
431  typedef type::const_reference const_reference;\
432  typedef type::iterator iterator;\
433  typedef type::const_iterator const_iterator;\
434  \
435  static type createBatch(value_type const& input, std::size_t size = 1){\
436  type batch;\
437  boost::fusion::copy(boost::fusion::transform(input,detail::CreateBatch(size)),fusionize(batch));\
438  return batch;\
439  }\
440  template<class Range>\
441  static type createBatchFromRange(Range const& range){\
442  std::size_t points = shark::size(range);\
443  type batch = createBatch(*range.begin(),points);\
444  typename boost::range_iterator<Range>::type pos = range.begin();\
445  for(std::size_t i = 0; i != points; ++i,++pos){\
446  get(batch,i) = *pos;\
447  }\
448  return batch;\
449  }\
450  static void resize(type& batch, std::size_t batchSize, std::size_t elements){\
451  batch.resize(batchSize,elements);\
452  }
453 
454 #endif