test/ncc.cc

Code
Comments
Other
Rev Date Author Line
504 01 Feb 06 markus 1 // $Id$
504 01 Feb 06 markus 2
675 10 Oct 06 jari 3 /*
2119 12 Dec 09 peter 4   Copyright (C) 2006 Jari Häkkinen, Markus Ringnér
4359 23 Aug 23 peter 5   Copyright (C) 2007 Peter Johansson, Markus Ringnér
4359 23 Aug 23 peter 6   Copyright (C) 2008 Jari Häkkinen, Peter Johansson, Markus Ringnér
4359 23 Aug 23 peter 7   Copyright (C) 2010, 2012 Peter Johansson
504 01 Feb 06 markus 8
1437 25 Aug 08 peter 9   This file is part of the yat library, http://dev.thep.lu.se/yat
675 10 Oct 06 jari 10
675 10 Oct 06 jari 11   The yat library is free software; you can redistribute it and/or
675 10 Oct 06 jari 12   modify it under the terms of the GNU General Public License as
1486 09 Sep 08 jari 13   published by the Free Software Foundation; either version 3 of the
675 10 Oct 06 jari 14   License, or (at your option) any later version.
675 10 Oct 06 jari 15
675 10 Oct 06 jari 16   The yat library is distributed in the hope that it will be useful,
675 10 Oct 06 jari 17   but WITHOUT ANY WARRANTY; without even the implied warranty of
675 10 Oct 06 jari 18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
675 10 Oct 06 jari 19   General Public License for more details.
675 10 Oct 06 jari 20
675 10 Oct 06 jari 21   You should have received a copy of the GNU General Public License
1487 10 Sep 08 jari 22   along with yat. If not, see <http://www.gnu.org/licenses/>.
675 10 Oct 06 jari 23 */
675 10 Oct 06 jari 24
2881 18 Nov 12 peter 25 #include <config.h>
2881 18 Nov 12 peter 26
1241 16 Mar 08 peter 27 #include "Suite.h"
1241 16 Mar 08 peter 28
675 10 Oct 06 jari 29 #include "yat/classifier/MatrixLookup.h"
675 10 Oct 06 jari 30 #include "yat/classifier/MatrixLookupWeighted.h"
675 10 Oct 06 jari 31 #include "yat/classifier/NCC.h"
675 10 Oct 06 jari 32 #include "yat/classifier/Target.h"
1587 17 Oct 08 peter 33 #include "yat/utility/DataIterator.h"
1587 17 Oct 08 peter 34 #include "yat/utility/DataWeight.h"
1121 22 Feb 08 peter 35 #include "yat/utility/Matrix.h"
1587 17 Oct 08 peter 36 #include "yat/utility/MatrixWeighted.h"
1052 07 Feb 08 peter 37 #include "yat/statistics/EuclideanDistance.h"
1052 07 Feb 08 peter 38 #include "yat/statistics/PearsonDistance.h"
675 10 Oct 06 jari 39 #include "yat/utility/utility.h"
675 10 Oct 06 jari 40
504 01 Feb 06 markus 41 #include <cassert>
504 01 Feb 06 markus 42 #include <fstream>
504 01 Feb 06 markus 43 #include <iostream>
931 05 Oct 07 markus 44 #include <stdexcept>
504 01 Feb 06 markus 45 #include <sstream>
504 01 Feb 06 markus 46 #include <string>
504 01 Feb 06 markus 47 #include <limits>
504 01 Feb 06 markus 48 #include <cmath>
504 01 Feb 06 markus 49
680 11 Oct 06 jari 50 using namespace theplu::yat;
504 01 Feb 06 markus 51
1483 09 Sep 08 peter 52 void predict_nan_data_unweighted_data(test::Suite& suite);
2338 16 Oct 10 peter 53 void compile_test(test::Suite& suite);
1483 09 Sep 08 peter 54
1241 16 Mar 08 peter 55 int main(int argc,char* argv[])
4200 19 Aug 22 peter 56 {
1241 16 Mar 08 peter 57   test::Suite suite(argc, argv);
1241 16 Mar 08 peter 58   suite.err() << "testing ncc" << std::endl;
504 01 Feb 06 markus 59
1483 09 Sep 08 peter 60   predict_nan_data_unweighted_data(suite);
1483 09 Sep 08 peter 61
1013 01 Feb 08 markus 62   /////////////////////////////////////////////
4200 19 Aug 22 peter 63   // First test of constructor and training
1013 01 Feb 08 markus 64   /////////////////////////////////////////////
931 05 Oct 07 markus 65   classifier::MatrixLookup ml(4,4);
916 30 Sep 07 peter 66   std::vector<std::string> vec(4, "pos");
916 30 Sep 07 peter 67   vec[3]="bjds";
916 30 Sep 07 peter 68   classifier::Target target(vec);
1157 26 Feb 08 markus 69    classifier::NCC<statistics::EuclideanDistance> ncctmp;
1241 16 Mar 08 peter 70   suite.err() << "training...\n";
1157 26 Feb 08 markus 71   ncctmp.train(ml,target);
1241 16 Mar 08 peter 72   suite.err() << "done\n";
1013 01 Feb 08 markus 73
1013 01 Feb 08 markus 74   /////////////////////////////////////////////
1013 01 Feb 08 markus 75   // A test of predictions using unweighted data
1013 01 Feb 08 markus 76   /////////////////////////////////////////////
1241 16 Mar 08 peter 77   suite.err() << "test of predictions using unweighted test data\n";
1121 22 Feb 08 peter 78   utility::Matrix data1(3,4);
1013 01 Feb 08 markus 79   for(size_t i=0;i<3;i++) {
1013 01 Feb 08 markus 80     data1(i,0)=3-i;
1013 01 Feb 08 markus 81     data1(i,1)=5-i;
1013 01 Feb 08 markus 82     data1(i,2)=i+1;
1013 01 Feb 08 markus 83     data1(i,3)=i+3;
1013 01 Feb 08 markus 84   }
1013 01 Feb 08 markus 85   std::vector<std::string> vec1(4, "pos");
1013 01 Feb 08 markus 86   vec1[0]="neg";
1013 01 Feb 08 markus 87   vec1[1]="neg";
1013 01 Feb 08 markus 88
1013 01 Feb 08 markus 89   classifier::MatrixLookup ml1(data1);
1013 01 Feb 08 markus 90   classifier::Target target1(vec1);
1013 01 Feb 08 markus 91
1157 26 Feb 08 markus 92   classifier::NCC<statistics::EuclideanDistance> ncc1;
1157 26 Feb 08 markus 93   ncc1.train(ml1,target1);
1121 22 Feb 08 peter 94   utility::Matrix prediction1;
1013 01 Feb 08 markus 95   ncc1.predict(ml1,prediction1);
1121 22 Feb 08 peter 96   utility::Matrix result1(2,4);
1013 01 Feb 08 markus 97   result1(0,0)=result1(0,1)=result1(1,2)=result1(1,3)=sqrt(3.0);
1013 01 Feb 08 markus 98   result1(0,2)=result1(0,3)=result1(1,0)=result1(1,1)=sqrt(11.0);
1241 16 Mar 08 peter 99   if (!suite.equal_range(prediction1.begin(), prediction1.end(),
1241 16 Mar 08 peter 100                          result1.begin())) {
1241 16 Mar 08 peter 101     suite.add(false);
1241 16 Mar 08 peter 102     suite.err() << "Difference to expected prediction too large\n";
1013 01 Feb 08 markus 103   }
1013 01 Feb 08 markus 104
1013 01 Feb 08 markus 105   //////////////////////////////////////////////////////////////////////////
1013 01 Feb 08 markus 106   // A test of predictions using unweighted training and weighted test data
1013 01 Feb 08 markus 107   //////////////////////////////////////////////////////////////////////////
1241 16 Mar 08 peter 108   suite.err() << "test of predictions using unweighted training and weighted test data\n";
1587 17 Oct 08 peter 109   utility::MatrixWeighted xw11(3,4);
1587 17 Oct 08 peter 110   xw11(0,0)=xw11(1,1)=xw11(2,2)=xw11(1,3)=utility::DataWeight(0,0);
1587 17 Oct 08 peter 111   std::copy(data1.begin(), data1.end(), utility::data_iterator(xw11.begin()));
1587 17 Oct 08 peter 112   classifier::MatrixLookupWeighted mlw1(xw11);
1587 17 Oct 08 peter 113   //classifier::MatrixLookupWeighted mlw1(data1,weights1);
4200 19 Aug 22 peter 114   ncc1.predict(mlw1,prediction1);
1013 01 Feb 08 markus 115   result1(0,2)=result1(0,3)=result1(1,0)=result1(1,1)=sqrt(15.0);
1241 16 Mar 08 peter 116   if (!suite.equal_range(prediction1.begin(), prediction1.end(),
1241 16 Mar 08 peter 117                          result1.begin())) {
1241 16 Mar 08 peter 118     suite.add(false);
1241 16 Mar 08 peter 119     suite.err() << "Difference to expected prediction too large\n";
1013 01 Feb 08 markus 120   }
1013 01 Feb 08 markus 121
1076 12 Feb 08 markus 122   //////////////////////////////////////////////////////////////////////////
1076 12 Feb 08 markus 123   // A test of predictions using weighted training resulting in NaN's
1076 12 Feb 08 markus 124   // in centroids and unweighted test data
1076 12 Feb 08 markus 125   //////////////////////////////////////////////////////////////////////////
1241 16 Mar 08 peter 126   suite.err() << "test of predictions using nan centroids and unweighted test data\n";
1587 17 Oct 08 peter 127   utility::MatrixWeighted xw12(3,4);
1587 17 Oct 08 peter 128   xw12(1,0)=xw12(1,1)=utility::DataWeight(0,0);
1587 17 Oct 08 peter 129   std::copy(data1.begin(), data1.end(), utility::data_iterator(xw12.begin()));
1587 17 Oct 08 peter 130   classifier::MatrixLookupWeighted mlw2(xw12);
1587 17 Oct 08 peter 131   //classifier::MatrixLookupWeighted mlw2(data1,weights2);
1157 26 Feb 08 markus 132   classifier::NCC<statistics::EuclideanDistance> ncc2;
1157 26 Feb 08 markus 133   ncc2.train(mlw2,target1);
4200 19 Aug 22 peter 134   ncc2.predict(ml1,prediction1);
1076 12 Feb 08 markus 135   result1(0,0)=result1(0,1)=result1(1,2)=result1(1,3)=sqrt(3.0);
1076 12 Feb 08 markus 136   result1(1,0)=result1(1,1)=sqrt(11.0);
1076 12 Feb 08 markus 137   result1(0,2)=result1(0,3)=sqrt(15.0);
4200 19 Aug 22 peter 138   if(!std::isnan(ncc2.centroids()(1,0)))
1241 16 Mar 08 peter 139     suite.add(false);
1241 16 Mar 08 peter 140   if (!suite.equal_range(prediction1.begin(), prediction1.end(),
1241 16 Mar 08 peter 141                          result1.begin())) {
1241 16 Mar 08 peter 142     suite.add(false);
1241 16 Mar 08 peter 143     suite.err() << "Difference to expected prediction too large\n";
1076 12 Feb 08 markus 144   }
1013 01 Feb 08 markus 145
1013 01 Feb 08 markus 146   //////////////////////////////////////////////////////////////////////////
1142 25 Feb 08 markus 147   // A test of predictions when a centroid has nan for all variables that a
1142 25 Feb 08 markus 148   // test sample has non-zero weights for.
1142 25 Feb 08 markus 149   //////////////////////////////////////////////////////////////////////////
1241 16 Mar 08 peter 150   suite.err() << "test of predictions using nan centroids and weighted test data\n";
1241 16 Mar 08 peter 151   suite.err() << "... using EuclideanDistance" << std::endl;
1587 17 Oct 08 peter 152   xw11(0,0).weight() = xw11(2,0).weight()=0;
1157 26 Feb 08 markus 153   classifier::NCC<statistics::EuclideanDistance> ncc3;
1157 26 Feb 08 markus 154   ncc3.train(mlw2,target1);
4200 19 Aug 22 peter 155   ncc3.predict(mlw1,prediction1);
1142 25 Feb 08 markus 156   if(!std::isnan(ncc3.centroids()(1,0))) {
1241 16 Mar 08 peter 157     suite.add(false);
1241 16 Mar 08 peter 158     suite.err() << "Training failed: expected nan in centroid" << std::endl;
1142 25 Feb 08 markus 159   }
1142 25 Feb 08 markus 160   if(!(std::isnan(prediction1(0,0)) &&
1241 16 Mar 08 peter 161        suite.equal(prediction1(1,0),sqrt(3.0)) &&
1241 16 Mar 08 peter 162        suite.equal(prediction1(0,1),sqrt(3.0)) &&
1241 16 Mar 08 peter 163        suite.equal(prediction1(1,1),sqrt(15.0)) &&
4200 19 Aug 22 peter 164        suite.equal(prediction1(0,2),sqrt(27.0)) )) {
1241 16 Mar 08 peter 165     suite.add(false);
1587 17 Oct 08 peter 166     if (!std::isnan(prediction1(0,0)))
1587 17 Oct 08 peter 167       suite.err() << "prediction1(0,0): " << prediction1(0,0) << "  "
1587 17 Oct 08 peter 168                   << "expected NaN\n";
1241 16 Mar 08 peter 169     suite.err() << "Test failed: predictions incorrect" << std::endl;
1142 25 Feb 08 markus 170   }
1241 16 Mar 08 peter 171   suite.err() << "... using PearsonDistance" << std::endl;;
1157 26 Feb 08 markus 172   classifier::NCC<statistics::PearsonDistance> ncc4;
1157 26 Feb 08 markus 173   ncc4.train(mlw2,target1);
4200 19 Aug 22 peter 174   ncc4.predict(mlw1,prediction1);
1142 25 Feb 08 markus 175   if(!std::isnan(ncc4.centroids()(1,0))) {
1241 16 Mar 08 peter 176     suite.add(false);
1241 16 Mar 08 peter 177     suite.err() << "Training failed: expected nan in centroid" << std::endl;
1142 25 Feb 08 markus 178   }
1142 25 Feb 08 markus 179   if(!(std::isnan(prediction1(0,0)) &&
1142 25 Feb 08 markus 180        std::isnan(prediction1(0,2)) &&
1142 25 Feb 08 markus 181        std::isnan(prediction1(1,0)) &&
1241 16 Mar 08 peter 182        suite.equal(prediction1(0,1), 0) &&
1241 16 Mar 08 peter 183        suite.equal(prediction1(1,2), 0) &&
4200 19 Aug 22 peter 184        suite.equal(prediction1(1,3), 0) &&
1241 16 Mar 08 peter 185        suite.equal(prediction1(0,3), 2.0) &&
1241 16 Mar 08 peter 186        suite.equal(prediction1(1,1), 2.0) )) {
4200 19 Aug 22 peter 187     suite.add(false);
1241 16 Mar 08 peter 188     suite.err() << "Test failed: predictions incorrect" << std::endl;
1142 25 Feb 08 markus 189   }
1142 25 Feb 08 markus 190
1143 25 Feb 08 markus 191   ////////////////////////////////////////////////////////////////
1143 25 Feb 08 markus 192   // A test of when a class has no training samples, should give nan
4200 19 Aug 22 peter 193   // in predictions.
1143 25 Feb 08 markus 194   ////////////////////////////////////////////////////////////////
1143 25 Feb 08 markus 195   //Keep only the second class in the training samples
1143 25 Feb 08 markus 196   std::vector<size_t> ind(2,2);
1143 25 Feb 08 markus 197   ind[1]=3;
1143 25 Feb 08 markus 198   classifier::Target target2(target1,utility::Index(ind));
1587 17 Oct 08 peter 199   classifier::MatrixLookupWeighted mlw3(xw12,
1484 09 Sep 08 peter 200                                         utility::Index(data1.rows()),
1484 09 Sep 08 peter 201                                         utility::Index(ind));
1157 26 Feb 08 markus 202   classifier::NCC<statistics::PearsonDistance> ncc5;
1157 26 Feb 08 markus 203   ncc5.train(mlw3,target2);
4200 19 Aug 22 peter 204   ncc5.predict(mlw1,prediction1);
4200 19 Aug 22 peter 205   if (!(std::isnan(prediction1(0,0)) && std::isnan(prediction1(0,1)) &&
1143 25 Feb 08 markus 206         std::isnan(prediction1(0,2)) && std::isnan(prediction1(0,3)) &&
1143 25 Feb 08 markus 207         std::isnan(prediction1(1,0)) &&
1241 16 Mar 08 peter 208         suite.equal(prediction1(1,1), 2.0) &&
1241 16 Mar 08 peter 209         suite.equal(prediction1(1,2),0) &&
1241 16 Mar 08 peter 210         suite.equal(prediction1(1,3),0) )) {
1241 16 Mar 08 peter 211     suite.err() << "Difference to expected prediction too large\n";
1241 16 Mar 08 peter 212     suite.add(false);
1143 25 Feb 08 markus 213   }
1142 25 Feb 08 markus 214
1142 25 Feb 08 markus 215   //////////////////////////////////////////////////////////////////////////
1013 01 Feb 08 markus 216   // A test of predictions using Sorlie data
1013 01 Feb 08 markus 217   //////////////////////////////////////////////////////////////////////////
1241 16 Mar 08 peter 218   suite.err() << "test with Sorlie data\n";
1251 03 Apr 08 peter 219   std::ifstream is(test::filename("data/sorlie_centroid_data.txt").c_str());
1587 17 Oct 08 peter 220   utility::MatrixWeighted data_weight(is,'\t');
504 01 Feb 06 markus 221   is.close();
504 01 Feb 06 markus 222
1251 03 Apr 08 peter 223   is.open(test::filename("data/sorlie_centroid_classes.txt").c_str());
504 01 Feb 06 markus 224   classifier::Target targets(is);
504 01 Feb 06 markus 225   is.close();
504 01 Feb 06 markus 226
1587 17 Oct 08 peter 227   classifier::MatrixLookupWeighted dataviewweighted(data_weight);
1157 26 Feb 08 markus 228    classifier::NCC<statistics::PearsonDistance> ncc;
1241 16 Mar 08 peter 229   suite.err() << "training...\n";
1157 26 Feb 08 markus 230   ncc.train(dataviewweighted,targets);
504 01 Feb 06 markus 231
632 05 Sep 06 markus 232   // Comparing the centroids to stored result
1251 03 Apr 08 peter 233   is.open(test::filename("data/sorlie_centroids.txt").c_str());
1121 22 Feb 08 peter 234   utility::Matrix centroids(is);
632 05 Sep 06 markus 235   is.close();
632 05 Sep 06 markus 236
632 05 Sep 06 markus 237   if(centroids.rows() != ncc.centroids().rows() ||
632 05 Sep 06 markus 238      centroids.columns() != ncc.centroids().columns()) {
1241 16 Mar 08 peter 239     suite.err() << "Error in the dimensionality of centroids\n";
4200 19 Aug 22 peter 240     suite.err() << "Nof rows: " << centroids.rows() << " expected: "
632 05 Sep 06 markus 241            << ncc.centroids().rows() << std::endl;
4200 19 Aug 22 peter 242     suite.err() << "Nof columns: " << centroids.columns() << " expected: "
632 05 Sep 06 markus 243            << ncc.centroids().columns() << std::endl;
632 05 Sep 06 markus 244   }
632 05 Sep 06 markus 245
1668 20 Dec 08 peter 246   if (!suite.equal_range_fix(centroids.begin(), centroids.end(),
1668 20 Dec 08 peter 247                              ncc.centroids().begin(), 1e-11)) {
1241 16 Mar 08 peter 248     suite.add(false);
1241 16 Mar 08 peter 249     suite.err() << "Difference to stored centroids too large\n";
632 05 Sep 06 markus 250   }
632 05 Sep 06 markus 251
1241 16 Mar 08 peter 252   suite.err() << "...predicting...\n";
1121 22 Feb 08 peter 253   utility::Matrix prediction;
634 05 Sep 06 markus 254   ncc.predict(dataviewweighted,prediction);
4200 19 Aug 22 peter 255
632 05 Sep 06 markus 256   // Comparing the prediction to stored result
1251 03 Apr 08 peter 257   is.open(test::filename("data/sorlie_centroid_predictions.txt").c_str());
1121 22 Feb 08 peter 258   utility::Matrix result(is,'\t');
504 01 Feb 06 markus 259   is.close();
504 01 Feb 06 markus 260
1668 20 Dec 08 peter 261   if (!suite.equal_range_fix(result.begin(), result.end(),
1668 20 Dec 08 peter 262                              prediction.begin(), 1e-11)) {
1241 16 Mar 08 peter 263     suite.add(false);
1241 16 Mar 08 peter 264     suite.err() << "Difference to stored prediction too large\n";
504 01 Feb 06 markus 265   }
2338 16 Oct 10 peter 266   compile_test(suite);
931 05 Oct 07 markus 267
1241 16 Mar 08 peter 268   return suite.return_value();
504 01 Feb 06 markus 269 }
1483 09 Sep 08 peter 270
2338 16 Oct 10 peter 271
2338 16 Oct 10 peter 272 void compile_test(test::Suite& suite)
2338 16 Oct 10 peter 273 {
2338 16 Oct 10 peter 274   if (false) {
2338 16 Oct 10 peter 275     boost::detail::dummy_constructor dummy;
2338 16 Oct 10 peter 276     test::distance_archetype distance(dummy);
2338 16 Oct 10 peter 277     classifier::NCC<test::distance_archetype> ncc(distance);
2338 16 Oct 10 peter 278   }
2338 16 Oct 10 peter 279 }
2338 16 Oct 10 peter 280
2338 16 Oct 10 peter 281
1483 09 Sep 08 peter 282 void predict_nan_data_unweighted_data(test::Suite& suite)
1483 09 Sep 08 peter 283 {
1483 09 Sep 08 peter 284   //////////////////////////////////////////////////////////////////////////
1483 09 Sep 08 peter 285   // A test of predictions using weighted training resulting in NaN's
1483 09 Sep 08 peter 286   // in centroids and unweighted test data
1483 09 Sep 08 peter 287   //////////////////////////////////////////////////////////////////////////
1483 09 Sep 08 peter 288   suite.err() << "test of predictions using nan centroids and unweighted test data\n";
1483 09 Sep 08 peter 289   utility::Matrix data1(3,4);
1483 09 Sep 08 peter 290   for(size_t i=0;i<3;i++) {
1483 09 Sep 08 peter 291     data1(i,0)=3-i;
1483 09 Sep 08 peter 292     data1(i,1)=5-i;
1483 09 Sep 08 peter 293     data1(i,2)=i+1;
1483 09 Sep 08 peter 294     data1(i,3)=i+3;
1483 09 Sep 08 peter 295   }
1587 17 Oct 08 peter 296   utility::MatrixWeighted xw(data1);
1483 09 Sep 08 peter 297   std::vector<std::string> vec1(4, "pos");
1483 09 Sep 08 peter 298   vec1[0]="neg";
1483 09 Sep 08 peter 299   vec1[1]="neg";
1483 09 Sep 08 peter 300
1483 09 Sep 08 peter 301   classifier::MatrixLookup ml1(data1);
1483 09 Sep 08 peter 302   classifier::Target target1(vec1);
1483 09 Sep 08 peter 303   utility::Matrix prediction1;
1483 09 Sep 08 peter 304   utility::Matrix result1(2,4);
1483 09 Sep 08 peter 305
1587 17 Oct 08 peter 306   xw(1,0).weight()=xw(1,1).weight()=0.0;
1483 09 Sep 08 peter 307
4200 19 Aug 22 peter 308
1587 17 Oct 08 peter 309   classifier::MatrixLookupWeighted mlw2(xw);
1483 09 Sep 08 peter 310   classifier::NCC<statistics::EuclideanDistance> ncc2;
1483 09 Sep 08 peter 311   ncc2.train(mlw2,target1);
4200 19 Aug 22 peter 312   ncc2.predict(ml1,prediction1);
1483 09 Sep 08 peter 313   result1(0,0)=result1(0,1)=result1(1,2)=result1(1,3)=sqrt(3.0);
1483 09 Sep 08 peter 314   result1(1,0)=result1(1,1)=sqrt(11.0);
1483 09 Sep 08 peter 315   result1(0,2)=result1(0,3)=sqrt(15.0);
4200 19 Aug 22 peter 316   if(!std::isnan(ncc2.centroids()(1,0)))
1483 09 Sep 08 peter 317     suite.add(false);
1483 09 Sep 08 peter 318   if (!suite.equal_range(prediction1.begin(), prediction1.end(),
1483 09 Sep 08 peter 319                          result1.begin())) {
1483 09 Sep 08 peter 320     suite.add(false);
1483 09 Sep 08 peter 321     suite.err() << "Difference to expected prediction too large\n";
1483 09 Sep 08 peter 322   }
1483 09 Sep 08 peter 323 }