source: trunk/yat/utility/merge.h @ 3225

Last change on this file since 3225 was 3225, checked in by Peter, 9 years ago

make code more readable

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 9.2 KB
Line 
1#ifndef _theplu_yat_utility_merge_
2#define _theplu_yat_utility_merge_
3
4// $Id: merge.h 3225 2014-05-12 05:21:36Z peter $
5
6/*
7  Copyright (C) 2009, 2010, 2014 Peter Johansson
8
9  This file is part of the yat library, http://dev.thep.lu.se/yat
10
11  The yat library is free software; you can redistribute it and/or
12  modify it under the terms of the GNU General Public License as
13  published by the Free Software Foundation; either version 3 of the
14  License, or (at your option) any later version.
15
16  The yat library is distributed in the hope that it will be useful,
17  but WITHOUT ANY WARRANTY; without even the implied warranty of
18  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  General Public License for more details.
20
21  You should have received a copy of the GNU General Public License
22  along with yat. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#include "concept_check.h"
26#include "Matrix.h"
27#include "MatrixWeighted.h"
28#include "stl_utility.h"
29
30#include "yat/statistics/Average.h"
31
32#include <boost/concept_check.hpp>
33#include <boost/iterator/permutation_iterator.hpp>
34
35#include <algorithm>
36#include <map>
37#include <string>
38#include <vector>
39
40namespace theplu {
41namespace yat {
42namespace utility {
43
44  /**
45     \brief merge rows in a \ref concept_container_2d
46
47     When two (or several) elements in \a labels are found, the
48     corresponding rows in \a x are merged into one row vector. The
49     vector of \a labels are modified to reflect the rows in the
50     resulting container \a y. In this default implementation the
51     merge is calculated as the (weighted) arithmetic mean.
52
53     \a x must be a \ref concept_container_2d and it works for both
54     weighted and unweighted containers.
55
56     \param x input container to be merged.
57     \param labels telling which rows to merge.
58     \param y resulting merged container.
59
60     \note If \a x and \a y overlap in their underlying data
61     structures, the result is undefined.
62
63     \since New in yat 0.6
64  */
65  template<class Container2D>
66  void merge(const Container2D& x, std::vector<std::string>& labels, Matrix& y);
67
68
69  /**
70     \brief merge rows in a \ref concept_container_2d using a Functor
71
72     Same as merge(const Container2D&, std::vector<std::string>&,
73     Matrix&) but instead of calculating the merged element as the
74     (weighted) arithmetic mean, the merged element is calculated as
75     defined by \a func.
76
77     \param x input container to be merged.
78     \param labels telling which rows to merge.
79     \param y resulting merged container.
80     \param func defines how data values are calculated
81
82     \c Functor \a func has an \c operator()(Iterator first, Iterator
83     last) \c const that calculates the merged value from range
84     [first, last).
85
86     Type Requirements:
87     - \c Container2D is a \ref concept_container_2d
88     - \c Functor is a <a href=http://www.sgi.com/tech/stl/BinaryFunction.html>
89     Binary Function</a>.
90     - \c Container2D::const_column_iterator is convertible to
91       argument types of \c Functor.
92     - \c Return type of \c Functor is convertible to \c double
93
94     If Functor works on both unweighted and weighted iterators, merge
95     works on both unweighted and weighted Container2D.
96
97     \note If \a x and \a y overlap in their underlying data
98     structures, the result is undefined.
99
100     \since New in yat 0.6
101  */
102  template<class Container2D, class Functor>
103  void merge(const Container2D& x, std::vector<std::string>& labels, Matrix& y,
104             Functor func);
105
106  /**
107     \brief merge rows in a \ref concept_container_2d to a MatrixWeighted
108
109     When two (or several) elements in \a labels are found, the
110     corresponding rows in \a x are merged into one row vector. The
111     vector of \a labels are modified to reflect the rows in the
112     resulting container \a y.
113
114     The data value of each element is calculated as defined by \a
115     data_func and and the weight value is calculated as defined by \a
116     weight_func.
117
118     \a x must be a \ref concept_container_2d.  If Functor1 and
119     Functor2 work on both unweighted and weighted iterators, merge
120     works on both unweighted and weighted Container2D.
121
122     \param x input container to be merged.
123     \param labels telling which rows to merge.
124     \param y resulting merged container.
125     \param data_func defines how data values are calculated
126     \param weight_func defines how weight values are calculated
127
128     \c Functor1 and \c Functor2 have an \c operator()(Iterator first,
129     Iterator last) \c const that calculates the merged value and
130     weight, respectively, from range [first, last).
131
132     Type Requirements:
133     - \c Container2D is a \ref concept_container_2d
134     - \c Functor1 is a <a href=http://www.sgi.com/tech/stl/BinaryFunction.html>
135     Binary Function</a>.
136     - \c Functor2 is a <a href=http://www.sgi.com/tech/stl/BinaryFunction.html>
137     Binary Function</a>.
138     - \c Container2D::const_column_iterator is convertible to
139       argument types of \c Functor1 and \c Functor2.
140     - \c Return type of \c Functor1 is convertible to \c double
141     - \c Return type of \c Functor2 is convertible to \c double
142
143     If \c Functor1 and \c Functor2 work on both unweighted and
144     weighted iterators, merge works on both unweighted and weighted
145     Container2D.
146
147     \note If \a x and \a y overlap in their underlying data
148     structures, the result is undefined.
149
150     \since New in yat 0.6
151  */
152  template<class Container2D, class Functor1, class Functor2>
153  void merge(const Container2D& x, std::vector<std::string>& labels,
154             MatrixWeighted& y, Functor1 data_func, Functor2 weight_func);
155
156  namespace detail {
157
158    /**
159       assign x using func1 on range [first, last).
160
161       func2 is not used but exists solely to keep the signature
162       similar to assign(DataWeight&, ...)
163     */
164    template<typename Iterator, class Functor1, class Functor2>
165    void assign(double& x, Iterator first, Iterator last, Functor1 func1,
166                Functor2 func2);
167
168    /**
169       assign x.data() using func1 on range [first, last).
170       assign x.weight() using func2 on range [first, last).
171
172     */
173    template<typename Iterator, class Functor1, class Functor2>
174    void assign(DataWeight& x, Iterator first, Iterator last, Functor1 func1,
175                Functor2 func2);
176
177    void merge_labels(std::vector<std::string>&,
178                      std::map<std::string, std::vector<size_t> >&);
179
180
181    template<class Container2D, class MutableContainer2D,
182             class Functor1, class Functor2>
183    void merge(const Container2D& x,
184               std::map<std::string, std::vector<size_t> >& label2index,
185               MutableContainer2D& result, Functor1 func1, Functor2 func2);
186
187  } // end of private namespace detail
188
189
190  // template implementations //
191
192  template<class Container2D>
193  void merge(const Container2D& x, std::vector<std::string>& labels, Matrix& y)
194  {
195    BOOST_CONCEPT_ASSERT((utility::Container2D<Container2D>));
196    merge(x, labels, y, statistics::Average());
197  }
198
199  template<class Container2D, class Functor>
200  void merge(const Container2D& x, std::vector<std::string>& labels,
201             Matrix& result, Functor func)
202  {
203    BOOST_CONCEPT_ASSERT((utility::Container2D<Container2D>));
204    std::map<std::string, std::vector<size_t> > label2index;
205    detail::merge_labels(labels, label2index);
206    detail::merge(x, label2index, result, func, func);
207  }
208
209
210  template<class Container2D, class Functor1, class Functor2>
211  void merge(const Container2D& x, std::vector<std::string>& labels,
212             MatrixWeighted& result, Functor1 func1, Functor2 func2)
213  {
214    BOOST_CONCEPT_ASSERT((utility::Container2D<Container2D>));
215    std::map<std::string, std::vector<size_t> > label2index;
216    detail::merge_labels(labels, label2index);
217    detail::merge(x, label2index, result, func1, func2);
218  }
219
220  // implemantions of private functions
221
222  namespace detail {
223    template<typename Iterator, class Functor1, class Functor2>
224    void assign(double& x, Iterator first, Iterator last, Functor1 func1,
225                Functor2 func)
226    {
227      x = func1(first, last);
228    }
229
230
231    template<typename Iterator, class Functor1, class Functor2>
232    void assign(DataWeight& x, Iterator first, Iterator last, Functor1 func1,
233                Functor2 func2)
234    {
235      x.data() = func1(first, last);
236      x.weight() = func2(first, last);
237    }
238
239
240    void merge_labels(std::vector<std::string>& labels,
241                      std::map<std::string, std::vector<size_t> >& label2index)
242    {
243      inverse(labels.begin(), labels.end(), label2index);
244      labels.resize(label2index.size());
245      std::copy(pair_first_iterator(label2index.begin()),
246                pair_first_iterator(label2index.end()),
247                labels.begin());
248    }
249
250
251    template<class Container2D, class MutableContainer2D,
252             class Functor1, class Functor2>
253    void merge(const Container2D& x,
254               std::map<std::string, std::vector<size_t> >& label2index,
255               MutableContainer2D& result, Functor1 func1, Functor2 func2)
256    {
257      BOOST_CONCEPT_ASSERT((utility::Mutable_Container2D<MutableContainer2D>));
258      BOOST_CONCEPT_ASSERT((utility::Container2D<Container2D>));
259      result.resize(label2index.size(), x.columns());
260      typedef std::map<std::string, std::vector<size_t> > Map;
261      Map::const_iterator iter=label2index.begin();
262
263      for (size_t row=0; row<result.rows(); ++row) {
264        const std::vector<size_t>& index = iter->second;
265        for (size_t col=0; col<result.columns(); ++col) {
266          using boost::make_permutation_iterator;
267          assign(result(row,col),
268                 make_permutation_iterator(x.begin_column(col), index.begin()),
269                 make_permutation_iterator(x.end_column(col), index.end()),
270                 func1, func2);
271        }
272        ++iter;
273      }
274    }
275
276  } // end of namespace detail
277
278}}} // of namespace utility, yat, and theplu
279
280#endif
Note: See TracBrowser for help on using the repository browser.