source: trunk/test/distance_test.cc @ 1704

Last change on this file since 1704 was 1704, checked in by Peter, 13 years ago

avoid using abs in tests and use test::Suite instead

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