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-2017 Shark Development Team
13  *
14  * <BR><HR>
15  * This file is part of Shark.
16  * <http://shark-ml.org/>
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  BatchTraits<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 getBatchElement(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 BatchTraits<T>::type::reference 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 getBatchElement(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 getBatchElement(container,index) on a container. Used as boost fusion functor in the creation 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 BatchTraits<T>::type::const_reference 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 getBatchElement(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 batchSize(boost::fusion::at_c<0>(fusionize(*this)));\
339  }\
340  reference operator[](std::size_t i){\
341  return *(begin()+i);\
342  }\
343  const_reference operator[](std::size_t i)const{\
344  return *(begin()+i);\
345  }\
346  template<class Archive>\
347  void serialize(Archive & archive,unsigned int version)\
348  {\
349  boost::fusion::for_each(fusionize(*this), detail::ItemSerializer<Archive>(archive));\
350  }\
351  };\
352  typedef NAME value_type;\
353  typedef typename type::reference reference;\
354  typedef typename type::const_reference const_reference;\
355  typedef typename type::iterator iterator;\
356  typedef typename type::const_iterator const_iterator;\
357  \
358  static type createBatch(value_type const& input, std::size_t size = 1){\
359  type batch;\
360  boost::fusion::copy(boost::fusion::transform(input,detail::CreateBatch(size)),fusionize(batch));\
361  return batch;\
362  }\
363  template<class Iterator>\
364  static type createBatchFromRange(Iterator const& begin, Iterator const& end){\
365  std::size_t points = end - begin;\
366  type batch = createBatch(*begin,points);\
367  Iterator pos = begin;\
368  for(std::size_t i = 0; i != points; ++i,++pos){\
369  getBatchElement(batch,i) = *pos;\
370  }\
371  return batch;\
372  }\
373  static void resize(type& batch, std::size_t batchSize, std::size_t elements){\
374  batch.resize(batchSize,elements);\
375  }\
376  template<class T>\
377  static std::size_t size(T const& batch){return batch.size();}\
378  \
379  template<class T>\
380  static typename T::reference get(T& batch, std::size_t i){\
381  return batch[i];\
382  }\
383  template<class T>\
384  static const_reference get(T const& batch, std::size_t i){\
385  return batch[i];\
386  }\
387  template<class T>\
388  static typename T::iterator begin(T& batch){\
389  return batch.begin();\
390  }\
391  template<class T>\
392  static const_iterator begin(T const& batch){\
393  return batch.begin();\
394  }\
395  template<class T>\
396  static typename T::iterator end(T& batch){\
397  return batch.end();\
398  }\
399  template<class T>\
400  static const_iterator end(T const& batch){\
401  return batch.end();\
402  }
403 
404 
405 ///\brief This macro can be used to specialize a structure type easily to a batch type.
406 ///
407 ///Assume, thjat your input Data looks like:
408 ///<code>
409 ///struct DataType{
410 /// RealVector A;
411 /// double B;
412 ///};
413 ///</code>
414 ///Than the Batch type should propably look like
415 ///<code>
416 ///struct DataTypeBatch{
417 /// RealMatrix A;
418 /// RealVector B;
419 ///};
420 ///</code>
421 ///In this case the macro can be used to generate a complete specialisation of Batch<DataType>
422 ///<code>
423 ///#define DataVars (RealVector, A)(double B)
424 ///
425 ///SHARK_CREATE_BATCH_INTERFACE( DataType,DataVars)
426 ///};
427 ///As any other batch model the result also offers iterators over the range of elements.
428 ///In this case also boost::fusion support is added to the sequence. e.g. it is
429 ///handled similar to any other tuple type (RealMatrix,RealVector). This is useful for MKL or Transfer
430 ///kernels
431 ///</code>
432 #define SHARK_CREATE_BATCH_INTERFACE_NO_TPL(NAME,ATTRIBUTES)\
433 private:\
434  SHARK_FUSION_DEFINE_STRUCT_INLINE(FusionType, SHARK_TRANSFORM_BATCH_ATTRIBUTES(type,ATTRIBUTES))\
435 public:\
436  struct type: public detail::FusionFacade<FusionType>{\
437  typedef NAME value_type;\
438  \
439  SHARK_CREATE_BATCH_REFERENCES(ATTRIBUTES)\
440  SHARK_CREATE_BATCH_ITERATORS()\
441  \
442  type(){}\
443  type(std::size_t size1, std::size_t size2){\
444  resize(size1,size2);\
445  }\
446  void resize(std::size_t batchSize, std::size_t elementSize){\
447  boost::fusion::for_each(fusionize(*this), detail::resize(batchSize,elementSize));\
448  }\
449  reference operator[](std::size_t i){\
450  return *(begin()+i);\
451  }\
452  const_reference operator[](std::size_t i)const{\
453  return *(begin()+i);\
454  }\
455  friend void swap(type& op1, type& op2){\
456  boost::fusion::swap(fusionize(op1),fusionize(op2));\
457  }\
458  std::size_t size()const{\
459  return batchSize(boost::fusion::at_c<0>(fusionize(*this)));\
460  }\
461  template<class Archive>\
462  void serialize(Archive & archive,unsigned int version)\
463  {\
464  boost::fusion::for_each(fusionize(*this), detail::ItemSerializer<Archive>(archive));\
465  }\
466  };\
467  typedef NAME value_type;\
468  typedef type::reference reference;\
469  typedef type::const_reference const_reference;\
470  typedef type::iterator iterator;\
471  typedef type::const_iterator const_iterator;\
472  \
473  static type createBatch(value_type const& input, std::size_t size = 1){\
474  type batch;\
475  boost::fusion::copy(boost::fusion::transform(input,detail::CreateBatch(size)),fusionize(batch));\
476  return batch;\
477  }\
478  template<class Iterator>\
479  static type createBatchFromRange(Iterator const& begin, Iterator const& end){\
480  std::size_t points = end - begin;\
481  type batch = createBatch(*begin,points);\
482  Iterator pos = begin;\
483  for(std::size_t i = 0; i != points; ++i,++pos){\
484  getBatchElement(batch,i) = *pos;\
485  }\
486  return batch;\
487  }\
488  static void resize(type& batch, std::size_t batchSize, std::size_t elements){\
489  batch.resize(batchSize,elements);\
490  }\
491  template<class T>\
492  static std::size_t size(T const& batch){return batch.size();}\
493  \
494  template<class T>\
495  static typename T::reference get(T& batch, std::size_t i){\
496  return batch[i];\
497  }\
498  template<class T>\
499  static const_reference get(T const& batch, std::size_t i){\
500  return batch[i];\
501  }\
502  template<class T>\
503  static typename T::iterator begin(T& batch){\
504  return batch.begin();\
505  }\
506  template<class T>\
507  static const_iterator begin(T const& batch){\
508  return batch.begin();\
509  }\
510  template<class T>\
511  static typename T::iterator end(T& batch){\
512  return batch.end();\
513  }\
514  template<class T>\
515  static const_iterator end(T const& batch){\
516  return batch.end();\
517  }
518 
519 #endif