source: trunk/test/distance_test.cc @ 2334

Last change on this file since 2334 was 2334, checked in by Peter, 11 years ago

fixes #625

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.9 KB
Line 
1// $Id: distance_test.cc 2334 2010-10-15 02:35:09Z peter $
2
3/*
4  Copyright (C) 2007 Jari Häkkinen, Markus Ringnér
5  Copyright (C) 2008 Jari Häkkinen, Peter Johansson, Markus Ringnér
6  Copyright (C) 2009, 2010 Peter Johansson
7
8  This file is part of the yat library, http://dev.thep.lu.se/yat
9
10  The yat library is free software; you can redistribute it and/or
11  modify it under the terms of the GNU General Public License as
12  published by the Free Software Foundation; either version 3 of the
13  License, or (at your option) any later version.
14
15  The yat library is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  General Public License for more details.
19
20  You should have received a copy of the GNU General Public License
21  along with yat. If not, see <http://www.gnu.org/licenses/>.
22*/
23
24#include "Suite.h"
25
26#include "yat/classifier/DataLookupWeighted1D.h"
27#include "yat/classifier/MatrixLookupWeighted.h"
28#include "yat/statistics/EuclideanDistance.h"
29#include "yat/statistics/PearsonDistance.h"
30#include "yat/utility/concept_check.h"
31#include "yat/utility/DataIterator.h"
32#include "yat/utility/Matrix.h"
33#include "yat/utility/MatrixWeighted.h"
34#include "yat/utility/Vector.h"
35#include "yat/utility/WeightIterator.h"
36
37#include <boost/concept_archetype.hpp>
38#include <boost/concept_check.hpp>
39
40#include <cassert>
41#include <fstream>
42#include <iostream>
43#include <limits>
44#include <list>
45#include <vector>
46
47
48using namespace theplu::yat;
49
50void check_equality(double, double, test::Suite&, const std::string&, 
51                    unsigned long int N=1);
52utility::Matrix data(void);
53utility::MatrixWeighted data_weighted(void);
54
55template<class Distance>
56void test_distance(Distance, theplu::yat::test::Suite&, unsigned long int N=1);
57
58template<class Distance>
59void test_duplicate(Distance, theplu::yat::test::Suite&, unsigned long int N=1);
60
61template<class Distance>
62void test_rescaling(Distance, theplu::yat::test::Suite&, unsigned long int N=1);
63
64template<class Distance>
65void test_unity_weights(Distance, theplu::yat::test::Suite&, 
66                        unsigned long int N=1);
67
68template<class Distance>
69void test_self_distance(Distance, theplu::yat::test::Suite&, 
70                        unsigned long int N=1);
71
72template<class Distance>
73void test_symmetry(Distance, theplu::yat::test::Suite&, unsigned long int N=1);
74
75template<class Distance>
76void test_zero_weight(Distance, theplu::yat::test::Suite&, 
77                      unsigned long int N=1);
78
79utility::Matrix weight(void);
80
81int main(int argc, char* argv[])
82{ 
83  theplu::yat::test::Suite suite(argc, argv);
84  suite.err() << "testing distance" << std::endl;
85 
86  utility::Vector a(3,1);
87  a(1) = 2;
88  utility::Vector b(3,0);
89  b(2) = 1;
90 
91  statistics::EuclideanDistance eucl_dist;
92  suite.err() << "testing EuclideanDistance" << std::endl;
93  test_distance(eucl_dist, suite, 100);
94  double dist=eucl_dist(a.begin(),a.end(),b.begin());
95  if (!suite.equal_fix(dist, 2.23606797749978988178, 1e-16)) {
96    suite.err() << "Error in unweighted Euclidean distance " << std::endl;
97    suite.add(false);
98  }
99 
100  statistics::PearsonDistance pear_dist;
101  suite.err() << "testing PearsonDistance" << std::endl;
102  test_distance(pear_dist, suite, 1000);
103  dist=pear_dist(a.begin(),a.end(),b.begin());
104  if (!suite.equal(dist, 1.5)) {
105    suite.err() << "Error in unweighted Pearson distance " << std::endl;
106    suite.add(false);
107  }
108 
109 
110  // Testing weighted versions
111  utility::Matrix m(2,3,1);
112  m(0,1)=2;
113  m(1,0)=0;
114  m(1,1)=0;
115  utility::MatrixWeighted m_w(m);
116  m_w(0,0).weight()=0;
117  classifier::MatrixLookupWeighted mw(m_w);
118  classifier::DataLookupWeighted1D aw(mw,0,true);
119  classifier::DataLookupWeighted1D bw(mw,1,true);
120 
121  dist=eucl_dist(aw.begin(),aw.end(),bw.begin());
122 
123  if (!suite.equal_sqrt(dist, sqrt(6))) {
124    suite.err() << "Error in weighted Euclidean distance " << std::endl;
125    suite.add(false);
126  }
127 
128  dist=pear_dist(aw.begin(),aw.end(),bw.begin());
129 
130  if (!suite.equal(dist, 2)) {
131    suite.err() << "Error in weighted Pearson distance " << std::endl;
132    suite.add(false);
133  }
134 
135   
136  // Test with std::vectors
137  std::vector<double> sa(3,1);
138  sa[1] = 2;
139  std::vector<double> sb(3,0);
140  sb[2] = 1;
141 
142  double tolerance=1e-4;
143  dist=eucl_dist(sa.begin(),sa.end(),sb.begin()); 
144  if(!suite.equal_fix(dist, 2.23607,tolerance)) {
145    suite.err() << "Error in distance for std::vector " << std::endl;
146    suite.add(false);
147  }
148 
149  // Test for a std::list and a std::vector
150  std::list<double> la;
151  std::copy(sa.begin(),sa.end(),std::back_inserter<std::list<double> >(la));
152  dist=eucl_dist(la.begin(),la.end(),sb.begin());
153  if(!suite.equal_fix(dist, 2.23607, tolerance) ) {
154    suite.err() << "Error in distance for std::list " << std::endl;
155    suite.add(false);
156  }
157 
158
159  return suite.return_value();
160}
161
162
163void check_equality(double dist1, double dist2, test::Suite& suite, 
164                    const std::string& msg, unsigned long int N)
165{
166  if (!suite.equal(dist1, dist2, N)) {
167    suite.err() << "Error: " << msg << " failed.\n";
168    suite.add(false);
169  }
170}
171
172
173utility::Matrix data(void)
174{
175  utility::Matrix res(2,10);
176  for (size_t i = 0; i<res.columns(); ++i){
177    res(0,i) = i*i+1;
178    res(1,i) = 2*i+3;
179  }
180  return res;
181}
182
183utility::MatrixWeighted data_weighted(void)
184{
185  utility::Matrix x = data();
186  utility::Matrix w = weight();
187  utility::MatrixWeighted res(x.rows(), x.columns());
188  std::copy(x.begin(), x.end(), utility::data_iterator(res.begin()));
189  std::copy(w.begin(), w.end(), utility::weight_iterator(res.begin()));
190  return res;
191}
192
193template<class Distance>
194void test_distance(Distance dist, theplu::yat::test::Suite& suite,
195                   unsigned int long N)
196{
197  BOOST_CONCEPT_ASSERT((utility::DistanceConcept<Distance>));
198  test_duplicate(dist, suite, N);
199  test_rescaling(dist, suite, N);
200  test_unity_weights(dist, suite, N);
201  test_self_distance(dist, suite, N);
202  test_symmetry(dist, suite, N);
203  test_zero_weight(dist, suite, N);
204
205  // do not run compiler test
206  if (false) {
207    boost::forward_iterator_archetype<double> iter;
208    boost::forward_iterator_archetype<utility::DataWeight> witer;
209    dist(iter, iter, iter);
210    dist(iter, iter, witer);
211    dist(witer, witer, iter);
212    dist(witer, witer, witer);
213  }
214}
215
216template<class Distance>
217void test_duplicate(Distance dist, theplu::yat::test::Suite& suite, 
218                    unsigned long int N)
219{
220  utility::MatrixWeighted x(data_weighted());
221  utility::MatrixWeighted mw(x.rows(), 2*x.columns());
222  for (size_t i=0; i<x.rows(); ++i){
223    std::copy(x.begin_row(i), x.end_row(i), mw.begin_row(i));
224    std::copy(x.begin_row(i), x.end_row(i), mw.begin_row(i)+x.columns());
225  }
226  double dist1 = dist(mw.begin_row(0), mw.end_row(0), mw.begin_row(1));
227  for (size_t i=0; i<x.columns(); ++i)
228    mw(0,i).weight()=0.0;
229  double dist2 = dist(mw.begin_row(0), mw.end_row(0), mw.begin_row(1));
230  check_equality(dist1, dist2, suite, "duplicate property", N);
231}
232
233template<class Distance>
234void test_rescaling(Distance dist, theplu::yat::test::Suite& suite, 
235                    unsigned long int N)
236{
237  utility::MatrixWeighted wx=data_weighted();
238  double dist1 = dist(wx.begin_row(0), wx.end_row(0), wx.begin_row(1));
239  // rescale weights
240  for (size_t i=0; i<wx.rows(); ++i)
241    for (size_t j=0; j<wx.columns(); ++j)
242      wx(i,j).weight() *= 2.13;
243  double dist2 = dist(wx.begin_row(0), wx.end_row(0), wx.begin_row(1));
244  check_equality(dist1, dist2, suite, "rescaling", N);
245}
246
247template<class Distance>
248void test_unity_weights(Distance dist, theplu::yat::test::Suite& suite, 
249                        unsigned long int N)
250{
251  utility::Matrix x=data();
252  utility::MatrixWeighted mw(x);
253  double dist1 = dist(mw.begin_row(0), mw.end_row(0), mw.begin_row(1));
254  double dist2 = dist(x.begin_row(0), x.end_row(0), x.begin_row(1));
255  check_equality(dist1, dist2, suite, "unity weights", N);
256}
257
258template<class Distance>
259void test_self_distance(Distance dist, theplu::yat::test::Suite& suite, 
260                        unsigned long int N)
261{
262  utility::Matrix x = data();
263  double self = dist(x.begin(), x.end(), x.begin());
264  if (!suite.equal_fix(self,0, N*std::numeric_limits<double>().epsilon()) ) {
265    suite.err() << "error: self distance is " << self << "\n"
266                << "supposed to be zero.\n";
267    suite.add(false);
268  }
269}
270
271
272template<class Distance>
273void test_symmetry(Distance dist, theplu::yat::test::Suite& suite, 
274                   unsigned long int N)
275{
276  utility::Matrix x = data();
277  double distab = dist(x.begin_row(0), x.end_row(0), x.begin_row(1));
278  double distba = dist(x.begin_row(1), x.end_row(1), x.begin_row(0));
279  check_equality(distab, distba, suite, "symmetry test", N);
280}
281
282
283template<class Distance>
284void test_zero_weight(Distance dist, theplu::yat::test::Suite& suite, 
285                      unsigned long int N)
286{
287  utility::MatrixWeighted wx=data_weighted();
288  wx(0,0).weight() = 0.0;
289  double dist1 = dist(wx.begin_row(0), wx.end_row(0), wx.begin_row(1));
290  wx(0,0).weight() = 100*std::numeric_limits<double>().epsilon();
291  double dist2 = dist(wx.begin_row(0), wx.end_row(0), wx.begin_row(1));
292  check_equality(dist1, dist2, suite, "zero weight", N);
293}
294
295utility::Matrix weight(void)
296{
297  utility::Matrix res(2,10);
298  for (size_t i = 0; i<res.columns(); ++i){
299    res(0,i) = 1.0/(1+i);
300    res(1,i) = 1.0-0.1*i;
301  }
302  return res;
303}
304
Note: See TracBrowser for help on using the repository browser.