Normalizer.h
Go to the documentation of this file.
1 /*!
2  *
3  *
4  * \brief Model for scaling and translation of data vectors.
5  *
6  *
7  *
8  * \author T. Glasmachers
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 #ifndef SHARK_MODELS_NORMALIZER_H
33 #define SHARK_MODELS_NORMALIZER_H
34 
36 #include <shark/LinAlg/Base.h>
37 
38 
39 namespace shark {
40 
41 
42 ///
43 /// \brief "Diagonal" linear model for data normalization.
44 ///
45 /// \par
46 /// The Normalizer is a restricted and often more efficient variant of
47 /// the LinearModel class. It restricts the linear model in two respects:
48 /// (1) input and output dimension must agree,
49 /// (2) computations are independent for each component.
50 /// This is useful mostly for data normalization (therefore the name).
51 /// The model's operation is of the form \f$ x \mapsto A x + b \f$ where
52 /// A is a diagonal matrix. This reduces memory requirements to linear,
53 /// which is why there is no sparse version of this model (as opposed to
54 /// the more general linear model). Also, the addition of b is optional.
55 ///
56 template <class DataType = RealVector>
57 class Normalizer : public AbstractModel<DataType, DataType>
58 {
59 public:
62 
65 
66  /// Constructor of an invalid model; use setStructure later
68  { }
69 
70  /// copy constructor
71  Normalizer(const self_type& model)
72  : m_A(model.m_A)
73  , m_b(model.m_b)
74  , m_hasOffset(model.m_hasOffset)
75  { }
76 
77  /// Construction from dimension
78  Normalizer(std::size_t dimension, bool hasOffset = false)
79  : m_A(dimension, dimension)
80  , m_b(dimension)
82  { }
83 
84  /// Construction from matrix
85  Normalizer(RealVector diagonal)
86  : m_A(diagonal)
87  , m_hasOffset(false)
88  { }
89 
90  /// Construction from matrix and vector
91  Normalizer(RealVector diagonal, RealVector vector)
92  : m_A(diagonal)
93  , m_b(vector)
94  , m_hasOffset(true)
95  { }
96 
97 
98  /// \brief From INameable: return the class name.
99  std::string name() const
100  { return "Normalizer"; }
101 
102  /// swap
103  friend void swap(const Normalizer& model1, const Normalizer& model2)
104  {
105  std::swap(model1.m_A, model2.m_A);
106  std::swap(model1.m_b, model2.m_b);
107  std::swap(model1.m_hasOffset, model2.m_hasOffset);
108  }
109 
110  /// assignment operator
111  const self_type operator = (const self_type& model)
112  {
113  m_A = model.m_A;
114  m_b = model.m_b;
115  m_hasOffset = model.m_hasOffset;
116  }
117 
118  /// derivative storage object (empty for this model)
119  boost::shared_ptr<State> createState() const
120  {
121  return boost::shared_ptr<State>(new EmptyState());
122  }
123 
124 
125  /// check if the model is properly initialized
126  bool isValid() const
127  {
128  return (m_A.size() != 0);
129  }
130 
131  /// check for the presence of an offset term
132  bool hasOffset() const
133  {
134  return m_hasOffset;
135  }
136 
137  /// return the diagonal of the matrix
138  RealVector const& diagonal() const
139  {
140  SHARK_CHECK(isValid(), "[Normalizer::matrix] model is not initialized");
141  return m_A;
142  }
143 
144  /// return the offset vector
145  RealVector const& offset() const
146  {
147  SHARK_CHECK(isValid(), "[Normalizer::vector] model is not initialized");
148  return m_b;
149  }
150 
151  /// obtain the input dimension
152  std::size_t inputSize() const
153  {
154  SHARK_CHECK(isValid(), "[Normalizer::inputSize] model is not initialized");
155  return m_A.size();
156  }
157 
158  /// obtain the output dimension
159  std::size_t outputSize() const
160  {
161  SHARK_CHECK(isValid(), "[Normalizer::outputSize] model is not initialized");
162  return m_A.size();
163  }
164 
165  /// obtain the parameter vector
166  RealVector parameterVector() const
167  {
168  SHARK_CHECK(isValid(), "[Normalizer::parameterVector] model is not initialized");
169  std::size_t dim = m_A.size();
170  if (hasOffset())
171  {
172  RealVector param(2 * dim);
173  init(param)<<m_A,m_b;
174  return param;
175  }
176  else
177  {
178  RealVector param(dim);
179  init(param)<<m_A;
180  return param;
181  }
182  }
183 
184  /// overwrite the parameter vector
185  void setParameterVector(RealVector const& newParameters)
186  {
187  SHARK_CHECK(isValid(), "[Normalizer::setParameterVector] model is not initialized");
188  std::size_t dim = m_A.size();
189  if (hasOffset())
190  {
191  SIZE_CHECK(newParameters.size() == 2 * dim);
192  init(newParameters)>>m_A,m_b;
193  }
194  else
195  {
196  SIZE_CHECK(newParameters.size() == dim);
197  init(newParameters)>>m_A;
198  }
199  }
200 
201  /// return the number of parameter
202  std::size_t numberOfParameters() const
203  {
204  SHARK_CHECK(isValid(), "[Normalizer::numberOfParameters] model is not initialized");
205  return (m_hasOffset) ? m_A.size() + m_b.size() : m_A.size();
206  }
207 
208  /// overwrite structure and parameters
209  void setStructure(RealVector const& diagonal)
210  {
211  m_A = diagonal;
212  m_hasOffset = false;
213  }
214 
215  /// overwrite structure and parameters
216  void setStructure(std::size_t dimension, bool hasOffset = false)
217  {
218  m_A.resize(dimension);
220  if (hasOffset) m_b.resize(dimension);
221  }
222 
223  /// overwrite structure and parameters
224  void setStructure(RealVector const& diagonal, RealVector const& offset)
225  {
226  SHARK_CHECK(diagonal.size() == offset.size(), "[Normalizer::setStructure] dimension conflict");
227  m_A = diagonal;
228  m_b = offset;
229  m_hasOffset = true;
230  }
231 
232  using base_type::eval;
233 
234  /// \brief Evaluate the model: output = matrix * input + offset.
235  void eval(BatchInputType const& input, BatchOutputType& output) const
236  {
237  SHARK_CHECK(isValid(), "[Normalizer::eval] model is not initialized");
238  output.resize(input.size1(), input.size2());
239  noalias(output) = input * repeat(m_A,input.size1());
240  if (hasOffset())
241  {
242  noalias(output) += repeat(m_b,input.size1());
243  }
244  }
245 
246  /// \brief Evaluate the model: output = matrix * input + offset.
247  void eval(BatchInputType const& input, BatchOutputType& output, State& state) const
248  {
249  eval(input, output);
250  }
251 
252  /// from ISerializable
253  void read(InArchive& archive)
254  {
255  archive & m_A;
256  archive & m_b;
257  archive & m_hasOffset;
258  }
259 
260  /// from ISerializable
261  void write(OutArchive& archive) const
262  {
263  archive & m_A;
264  archive & m_b;
265  archive & m_hasOffset;
266  }
267 
268 protected:
269  RealVector m_A; ///< matrix A (see class documentation)
270  RealVector m_b; ///< vector b (see class documentation)
271  bool m_hasOffset; ///< if true: add offset therm b; if false: don't.
272 };
273 
274 
275 }
276 #endif