Math.h
1 /*
2 
3 MIT License
4 
5 Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 
25 */
26 /*
27 Part of Rack development has been done in the BALTRAD projects part-financed
28 by the European Union (European Regional Development Fund and European
29 Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30 */
31 /*
32  * Math.h
33  *
34  * Created on: Jul 23, 2013
35  * Author: mpeura
36  */
37 
38 #ifndef MATH_H_
39 #define MATH_H_
40 
41 #include <vector>
42 #include <iostream>
43 #include <stdexcept>
44 
45 // // using namespace std;
46 
47 namespace drain {
48 
49 // MatrixBase
50 template <class T=double>
51 class Matrix : protected std::vector<T> {
52 
53 public:
54 
55  Matrix(size_t rows=0, size_t columns = 0) : std::vector<T>(rows*columns), rows(rows), columns(columns) {
56  }
57 
58  Matrix(const Matrix &m) : std::vector<T>(m), rows(m.rows), columns(m.columns) {
59  }
60 
61  ~Matrix(){};
62 
63  virtual
64  void setSize(size_t rows, size_t columns){
65  this->rows = rows;
66  this->columns = columns;
67  std::vector<T>::resize(rows * columns);
68  }
69 
70  inline
71  size_t getSize() const { return std::vector<T>::size(); }
72 
73  inline
74  virtual
75  size_t getRows() const {
76  return rows;
77  }
78 
79  inline
80  virtual
81  size_t getColumns() const {
82  return columns;
83  }
84 
85  inline
86  T & operator()(const size_t & i){
87  return (*this)[i];
88  };
89 
90  inline
91  const T & operator()(const size_t & i) const {
92  return (*this)[i];
93  };
94 
95  inline
96  T & operator()(const size_t & i, const size_t & j){
97  //return (*this)[i*rows + j];
98  return (*this)[i*columns + j];
99  };
100 
101  inline
102  const T & operator()(const size_t & i, const size_t & j) const {
103  //return (*this)[i*rows + j];
104  return (*this)[i*columns + j];
105  };
106 
107 
109  inline
110  void fill(const T & x){
111  for (typename std::vector<T>::iterator it=this->begin(); it != this->end(); ++it){
112  *it = 0;
113  }
114  }
115 
116  inline
117  typename std::vector<T>::iterator begin() { return std::vector<T>::begin(); }
118 
119  inline
120  typename std::vector<T>::iterator end() { return std::vector<T>::end(); }
121 
122  inline
123  typename std::vector<T>::const_iterator begin() const { return std::vector<T>::begin(); }
124 
125  inline
126  typename std::vector<T>::const_iterator end() const { return std::vector<T>::end(); }
127 
128  template <class T2>
129  inline
130  Matrix<T> & operator=(const std::vector<T2> &v){
131  setSize(v.size(),1);
132  std::vector<T>::operator=(v);
133  return *this;
134  }
135 
136  operator std::vector<T> &() const {
137  return *this;
138  }
139 
140  void transpose(Matrix<T> & dst);
141 
142  template <class T2, class T3>
143  void multiply(const Matrix<T2> & src2, Matrix<T3> & dst);
144 
146 
149  template <class T2>
150  void inverse(Matrix<T2> & dst);
151 
153  template <class T2>
154  void inverse3(Matrix<T2> & dst);
155 
156 private:
157 
158  size_t rows;
159  size_t columns;
160 
161 };
162 
163 /*
164 template <class T=double>
165 class Matrix : public MatrixBase<T> {
166 
167 public:
168  Matrix(size_t rows=0, size_t columns = 0) : MatrixBase<T>(rows, columns) {
169  }
170 
171 };
172 */
173 
174 
175 template <class T>
176 void Matrix<T>::transpose(Matrix<T> & dst){
177 
178  Matrix<T> tmp;
179  const bool SELF = (&dst == this);
180 
181  const Matrix<T> & s = SELF ? tmp : *this;
182  if (SELF)
183  tmp = *this;
184 
185  dst.setSize(getColumns(), getRows());
186  for (size_t i = 0; i < getRows(); ++i) {
187  for (size_t j = 0; j < getColumns(); ++j) {
188  dst(j,i) = s(i,j);
189  //rand();
190  }
191  }
192 }
193 
194 
195 
196 template <class T>
197 template <class T2, class T3>
198 void Matrix<T>::multiply(const Matrix<T2> & src, Matrix<T3> & dst){
199 
200  if (getColumns() != src.getRows()){
201  std::cerr << "a=" << *this << std::endl;
202  std::cerr << getColumns() << std::endl;
203  std::cerr << "b=" << src << std::endl;
204  std::cerr << getRows() << std::endl;
205  throw std::runtime_error("multiply: w1 != h2");
206  }
207 
208  dst.setSize(getRows(), src.getColumns());
209 
210  /*
211  std::cout << " multiply\n";
212  std::cout << "C=" << dst << std::endl;
213  */
214 
215  T3 x;
216  for (size_t i = 0; i < getRows(); ++i) {
217  for (size_t j = 0; j < src.getColumns(); ++j) {
218  //T3 & x = dst(i,j);
219  x = 0.0;
220  for (size_t k = 0; k < src.getRows(); ++k) {
221  x += (*this)(i,k)*src(k,j);
222  }
223  dst(i,j) = x;
224  }
225  }
226 
227 }
228 
229 template <class T>
230 template <class T2>
232 
233  switch (getRows()) {
234  case 3:
235  inverse3(dst);
236  break;
237  default:
238  std::cerr << getRows() << std::endl;
239  throw std::runtime_error("inverse: not implemented for n>3");
240  break;
241  }
242 }
243 
245 template <class T>
246 template <class T2>
248 
249  if ((getRows() != 3) || (getColumns() != 3))
250  throw std::runtime_error("inverse: matrix not 3x3");
251 
252  dst.setSize(3,3);
253  //std::cout << dst << std::endl;
254 
256  /* a d g
257  * b e h
258  * c f i
259  */
260  const T & a = (*this)(0,0);
261  const T & b = (*this)(1,0);
262  const T & c = (*this)(2,0);
263 
264  const T & d = (*this)(0,1);
265  const T & e = (*this)(1,1);
266  const T & f = (*this)(2,1);
267 
268  const T & g = (*this)(0,2);
269  const T & h = (*this)(1,2);
270  const T & i = (*this)(2,2);
271 
272  // Determinant
273  const double det = a*(e*i-f*h) - d*(b*i-c*h) + g*(b*f-c*e);
274  if (det == 0.0)
275  throw std::runtime_error("inverse: zero determinant");
276 
277  // Inverse of determinant
278  const double detInv = 1.0/det;
279 
281  const T & A = (*this)(0,0);
282  const T & B = (*this)(0,1);
283  const T & C = (*this)(0,2);
284 
285  const T & D = (*this)(1,0);
286  const T & E = (*this)(1,1);
287  const T & F = (*this)(1,2);
288 
289  const T & G = (*this)(2,0);
290  const T & H = (*this)(2,1);
291  const T & I = (*this)(2,2);
292 
293  /* A D G
294  * B E H
295  * C F I
296  */
297  dst(0,0) = detInv * +(E*I - F*H);
298  dst(0,1) = detInv * -(B*I - C*H);
299  dst(0,2) = detInv * +(B*F - C*E);
300 
301  dst(1,0) = detInv * -(D*I - F*G);
302  dst(1,1) = detInv * +(A*I - C*G);
303  dst(1,2) = detInv * -(A*F - C*D);
304 
305  dst(2,0) = detInv * +(D*H - E*G);
306  dst(2,1) = detInv * -(A*H - B*G);
307  dst(2,2) = detInv * +(A*E - B*D);
308 
309 
310 }
311 
312 
313 template <class T=double>
314 class Vector : public Matrix<T> {
315 
316 public:
317 
318  Vector(size_t size=0, bool vertical=true) : Matrix<T>(vertical?size:1, vertical?1:size), vertical(vertical) {
319  }
320 
321  Vector(const Vector<T> &v) : Matrix<T>(v.getRows(), v.getColumns()), vertical(v.vertical) {
322  }
323  /*
324  void setSize(size_t rows, size_t columns){
325  if ((rows > 1) && (columns > 1)){
326  throw std::runtime_error("Vector::setSize: rows or colums != 1");
327  }
328  Matrix<T>::setSize(rows, columns);
329  vertical = (rows >= columns);
330  }*/
331 
332  template <class T2>
333  inline
334  Vector<T> & operator=(const std::vector<T2> &v){
335  // Vector<T>::
336  // Matrix<T>::
337  Matrix<T>::setSize(v.size(), size_t(1));
338  std::vector<T>::operator=(v);
339  return *this;
340  }
341 
342  template <class T2>
343  T innerProduct(Vector<T2> & src){
344  if (src.size() != std::vector<T>::size()){
345  std::cerr << (*this) << std::vector<T>::size() << std::endl;
346  std::cerr << src << src.size() << std::endl;
347  throw std::runtime_error("Vector::innerProduct: different sizes");
348  }
349  T result = 0;
350  //std::cout << "innerBegin" << flush;
351  typename std::vector<T>::const_iterator it = std::vector<T>::begin();
352  typename std::vector<T2>::const_iterator it2 = src.begin();
353  while (it != std::vector<T>::end()){
354  result += *it * *it2;
355  ++it;
356  ++it2;
357  }
358  //std::cout << "innerEnd" << std::endl;
359  return result;
360  }
361 
362 protected:
363  bool vertical;
364 
365 };
366 
367 
369 
372 //void fitCurve(const std::vector<double> &src, const std::vector<double> &weight, drain::Vector<double> &coeff) const;
373 template <class T>
374 void polynomialFit2nd(const T &src, const T &weight, std::vector<double> &coeff){
375 
376  coeff.resize(3);
377 
378  //const size_t n = src.size();
379 
380  double x = 0.0;
381  drain::Matrix<double> XTX(3,3);
382  drain::Matrix<double> XTXinv(3,3);
383  double sumX0, sumX1, sumX2, sumX3, sumX4;
384  sumX0 = sumX1 = sumX2 = sumX3 = sumX4 = 0.0;
385 
386 
387  double y;
388  drain::Matrix<double> XTy(3,1);
389  double & sumY = XTy(0);
390  double & sumYX = XTy(1);
391  double & sumYXX = XTy(2);
392  sumY = sumYX = sumYXX = 0.0;
393 
394  double w;
395 
396  //for (size_t i = 0; i < n; ++i) {
397  typename T::const_iterator its = src.begin();
398  typename T::const_iterator itw = weight.begin();
399 
400  while (its != src.end()){
401 
402  x += 1.0;
403  y = *its;
404  w = *itw;
405 
406  sumX0 += w* 1.0;
407  sumX1 += w* x;
408  sumX2 += w* x*x;
409  sumX3 += w* x*x*x;
410  sumX4 += w* x*x*x*x; // (optimise)
411 
412  sumY += w* y;
413  sumYX += w* y*x;
414  sumYXX += w* y*x*x;
415 
416  ++its;
417  ++itw;
418  }
419 
420  XTX(0,0) = static_cast<double>(sumX0);
421  XTX(0,1) = XTX(1,0) = sumX1;
422  XTX(0,2) = XTX(1,1) = XTX(2,0) = sumX2;
423  XTX(1,2) = XTX(2,1) = sumX3;
424  XTX(2,2) = sumX4;
425 
426  XTX.inverse(XTXinv); // Throws a runtime error, if fails.
427 
428  drain::Vector<double> coeffVector(3);
429  XTXinv.multiply( XTy, coeffVector);
430  coeff = (const std::vector<double> &)coeffVector;
431 
432 
433 }
434 
435 
436 
437 template <class T>
438 std::ostream & operator<<(std::ostream &ostr, const Matrix<T> & m){
439  ostr << '[';
440  for (size_t i = 0; i < m.getRows(); ++i) {
441  for (size_t j = 0; j < m.getColumns(); ++j) {
442  ostr << ' ' << m(i,j) ;
443  }
444  ostr << ';' << '\n';
445  }
446  ostr << ']';
447  ostr << " (" << m.getSize() << " elements)";
448  ostr << '\n';
449  return ostr;
450 }
451 
452 
453 } /* namespace drain */
454 #endif /* MATH_H_ */
455 
456 // Rack
Definition: Math.h:51
void inverse(Matrix< T2 > &dst)
Computes the inverse of a matrix.
Definition: Math.h:231
void fill(const T &x)
Resets the values, leaving geomatry.
Definition: Math.h:110
void inverse3(Matrix< T2 > &dst)
Computes the inverse of a 3-by-3 matrix.
Definition: Math.h:247
Definition: Math.h:314
Definition: DataSelector.cpp:1277
void polynomialFit2nd(const T &src, const T &weight, std::vector< double > &coeff)
Fits a 2nd order polynomial to a curve.
Definition: Math.h:374