/* This file is part of MAUS: http:// micewww.pp.rl.ac.uk:8080/projects/maus
*
* MAUS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MAUS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAUS. If not, see .
*/
/* Author: Chris Rogers
*/
#include
#include
#include
#include "gtest/gtest.h"
#include "CLHEP/Matrix/Matrix.h"
#include "Config/ModuleConverter.hh"
#include "Utils/Squeak.hh"
#include "Interface/Differentiator.hh"
#include "Interface/Interpolator.hh"
#include "Maths/Matrix.hh"
#include "Maths/PolynomialMap.hh"
#include "Maths/Vector.hh"
// NOTE: tests PolynomialMap, Differentiator and
// PolynomialInterpolator classes.
// Three classes that are very closely related anyway...
using MAUS::PolynomialMap;
using MAUS::Matrix;
using MAUS::Vector;
class PolynomialMapTest : public ::testing::Test {
public:
PolynomialMapTest()
: polynomial_map_(NULL), cloned_map_(NULL), extracted_coeff_map_(NULL) {}
bool verify_mapping(const PolynomialMap* polynomial_map,
double point[], double answer[]) {
bool testpass = true;
Vector valueMV(3, 0);
Vector pointMV(2, 0);
for (int i = 1; i <= 2; i++) pointMV(i) = point[i-1];
MAUS::Squeak::mout(MAUS::Squeak::debug) << "PolyVectorFTest" << std::endl;
polynomial_map->F(pointMV, valueMV);
MAUS::Squeak::mout(MAUS::Squeak::debug) << "PolyVectorFTest" << std::endl;
for (int i = 0; i < 3; i++) {
testpass &= fabs(valueMV(i+1) - answer[i]) < 1e-9;
}
for (int i = 0; i < 3; i++) {
MAUS::Squeak::mout(MAUS::Squeak::debug) << valueMV(i+1) << " ";
}
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Hep F(*, *) " << testpass << std::endl;
std::vector valueVec(3, -2);
std::vector pointVec(2, 0);
for (int i = 0; i < 2; i++) pointVec[i] = point[i];
polynomial_map->F(&pointVec[0], &valueVec[0]);
for (int i = 0; i < 3; i++) {
testpass &= fabs(valueVec[i] - answer[i]) < 1e-9;
}
for (int i = 0; i < 3; i++) {
MAUS::Squeak::mout(MAUS::Squeak::debug) << valueVec[i] << " ";
}
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Vec F(*, *) " << testpass << std::endl;
return testpass;
}
// size of point is 3
static void weight_function(const double * point, double * weight) {
int hit_count = 0;
for (int index = 0; index < 3; ++index) {
if (point[index] == 92.) {
++hit_count;
}
}
if (hit_count == 3) {
*weight = 0.0;
} else {
*weight = 1.0;
}
}
protected:
virtual void SetUp() {
CLHEP::HepMatrix coeffHep(3, 6);
for (size_t i = 0; i < 6; i++) {
coeffHep[0][i] = i+1;
}
for (size_t i = 0; i < 6; i++) {
coeffHep[1][i] = i*i;
}
for (size_t i = 0; i < 6; i++) {
coeffHep[2][i] = -static_cast(i)-1;
}
Matrix coefficient_matrix(coeffHep);
polynomial_map_ = new PolynomialMap(2, coefficient_matrix);
cloned_map_ = polynomial_map_->Clone();
std::vector coeffs
= polynomial_map_->GetCoefficientsAsVector();
extracted_coeff_map_ = new PolynomialMap(coeffs);
}
virtual void TearDown() {
delete polynomial_map_;
delete cloned_map_;
delete extracted_coeff_map_;
}
PolynomialMap const * polynomial_map_;
PolynomialMap const * cloned_map_;
PolynomialMap const * extracted_coeff_map_;
};
TEST_F(PolynomialMapTest, Constructor) {
ASSERT_EQ(polynomial_map_->PointDimension(), (size_t) 2);
ASSERT_EQ(polynomial_map_->ValueDimension(), (size_t) 3);
ASSERT_EQ(extracted_coeff_map_->PointDimension(), (size_t) 2);
ASSERT_EQ(extracted_coeff_map_->ValueDimension(), (size_t) 3);
}
TEST_F(PolynomialMapTest, Clone) {
delete polynomial_map_;
polynomial_map_ = NULL;
ASSERT_EQ(cloned_map_->PointDimension(), (size_t) 2);
ASSERT_EQ(cloned_map_->ValueDimension(), (size_t) 3);
}
TEST_F(PolynomialMapTest, MapEvaluation) {
double point1[2] = {0, 0};
double answer1[3] = {1, 0, -1};
ASSERT_TRUE(verify_mapping(cloned_map_, point1, answer1));
ASSERT_TRUE(verify_mapping(extracted_coeff_map_, point1, answer1));
double point2[2] = {3, -2}; // {1, 3, -2, 9, -6, 4}
double answer2[3] = {31, 80, -31};
ASSERT_TRUE(verify_mapping(cloned_map_, point2, answer2));
ASSERT_TRUE(verify_mapping(extracted_coeff_map_, point2, answer2));
for (int i = 0; i < 5; i++) {
MAUS::Squeak::mout(MAUS::Squeak::debug)
<< "nPCoeffs(3, " << i << ") "
<< PolynomialMap::NumberOfPolynomialCoefficients(3, i) << std::endl;
}
// FIXME(plane1@iit.edu): No actual test here. Just some debug output.
for (int i = 0; i < 20; i++) {
std::vector indexP = PolynomialMap::IndexByPower(i, 3);
std::vector indexV = PolynomialMap::IndexByVector(i, 3);
MAUS::Squeak::mout(MAUS::Squeak::debug) << std::setw(5) << i << " *|* ";
for (size_t j = 0; j < indexP.size(); j++) {
MAUS::Squeak::mout(MAUS::Squeak::debug) << std::setw(5) << indexP[j] << " ";
}
MAUS::Squeak::mout(MAUS::Squeak::debug) << " *|* ";
for (size_t j = 0; j < indexV.size(); j++) {
MAUS::Squeak::mout(MAUS::Squeak::debug) << std::setw(5) << indexV[j] << " ";
}
MAUS::Squeak::mout(MAUS::Squeak::debug) << std::endl;
}
}
TEST_F(PolynomialMapTest, IterableEquality) {
std::vector a;
std::vector b;
ASSERT_TRUE(PolynomialMap::IterableEquality(
a, b, a.begin(), a.end(), b.begin(), b.end()));
a.push_back(-2);
ASSERT_FALSE(PolynomialMap::IterableEquality(
a, b, a.begin(), a.end(), b.begin(), b.end()));
b.push_back(-2);
ASSERT_TRUE(PolynomialMap::IterableEquality(
a, b, a.begin(), a.end(), b.begin(), b.end()));
b.push_back(-2);
ASSERT_FALSE(PolynomialMap::IterableEquality(
a, b, a.begin(), a.end(), b.begin(), b.end()));
}
TEST_F(PolynomialMapTest, PointBox) {
double deltaA[] = {2., 3., 4., 5.};
std::vector delta(deltaA, deltaA+4);
std::vector > ps = PolynomialMap::PointBox(delta, 6);
for (size_t i = 0; i < ps.size(); i++) {
bool on_edge = false;
for (size_t j = 0; j < ps[i].size(); j++) {
// at least one of ps[i] must be == +- delta for it to be on edge
on_edge = on_edge || fabs(delta[j]-fabs(ps[i][j])) < 1e-9;
}
if (!on_edge) {
for (size_t j = 0; j < ps[i].size(); j++) {
MAUS::Squeak::mout(MAUS::Squeak::debug) << ps[i][j] << " ";
}
}
ASSERT_TRUE(on_edge);
}
}
TEST_F(PolynomialMapTest, GetAvgChi2OfDifference) {
double mat_data[] = {1, 2, 7, 13, 5, 0,
4, 3, 11, 3, 7, 9,
1, 2, 7, 13, 8, 2};
Matrix mat(3, 6, mat_data);
PolynomialMap pvec(2, mat);
std::vector< std::vector > in;
std::vector< std::vector > out;
std::vector< std::vector > out_neg;
// empty in vector
bool testpass = true;
try {
pvec.GetAvgChi2OfDifference(in, out);
testpass = false;
} catch (MAUS::Exceptions::Exception exc) {}
ASSERT_TRUE(testpass);
for (int i = 0; i < 10; i++) {
in.push_back(std::vector(2, i));
in.back()[1] = i*2;
out .push_back(std::vector(3, 0));
out_neg.push_back(std::vector(3, 0));
pvec.F(&in.back()[0], &out.back()[0]);
for (int i = 0; i < 3; i++) {
out_neg.back()[i] = -out.back()[i];
}
}
double avg_chi2 = pvec.GetAvgChi2OfDifference(in, out);
ASSERT_TRUE(fabs(avg_chi2) < 1e-6);
avg_chi2 = pvec.GetAvgChi2OfDifference(in, out_neg);
ASSERT_TRUE(fabs(avg_chi2/1e14 - 4.90542) < 1e-3); // Hope that is right
// in/out size mismatch
in.pop_back();
testpass = true;
try {
pvec.GetAvgChi2OfDifference(in, out);
testpass = false;
} catch (MAUS::Exceptions::Exception exc) {}
ASSERT_TRUE(testpass);
// in[i] size != point dimension
out.pop_back();
in[0].pop_back();
testpass = true;
try {
pvec.GetAvgChi2OfDifference(in, out);
testpass = false;
} catch (MAUS::Exceptions::Exception exc) {}
ASSERT_TRUE(testpass);
// out[i] size != value dimension
in.push_back(std::vector(2, 0.0));
in[0].push_back(0.0);
out[0].pop_back();
testpass = true;
try {
pvec.GetAvgChi2OfDifference(in, out);
testpass = false;
} catch (MAUS::Exceptions::Exception exc) {}
ASSERT_TRUE(testpass);
}
TEST_F(PolynomialMapTest, Means) {
std::vector > values;
values.push_back(std::vector());
for (size_t i = 1; i <= 3; i++) values.back().push_back(i);
values.push_back(std::vector());
for (size_t i = 1; i <= 3; i++) {
values.back().push_back(-static_cast(i));
}
values.push_back(std::vector());
for (size_t i = 1; i <= 3; i++) values.back().push_back(i*i);
std::vector weights1(3, 1.);
std::vector weights2(3, 1.);
weights2[2] = 0.;
Vector v1 = PolynomialMap::Means(values, std::vector());
Vector v2 = PolynomialMap::Means(values, weights1);
Vector v3 = PolynomialMap::Means(values, weights2);
for (size_t i = 1; i <= 3; i++) {
EXPECT_TRUE(fabs(v1(i)-static_cast(i*i)/3.) < 1e-6);
EXPECT_TRUE(fabs(v2(i)-static_cast(i*i)/3.) < 1e-6);
EXPECT_TRUE(fabs(v3(i)) < 1e-6);
}
}
TEST_F(PolynomialMapTest, Covariances) {
std::vector > values;
values.push_back(std::vector());
for (size_t i = 0; i < 3; i++) values.back().push_back(1);
values.push_back(std::vector());
for (size_t i = 0; i < 3; i++) values.back().push_back(1);
values.push_back(std::vector());
for (size_t i = 0; i < 3; i++) values.back().push_back(-1);
values.push_back(std::vector());
for (size_t i = 0; i < 3; i++) values.back().push_back(-1);
// empty weights -> PolynomialMap defaults to weights being all 1.
std::vector weights0;
// empty means -> PolynomialMap defaults to means calculated from values
Vector means0;
std::vector weights1(4, 1.);
Vector means1(3, 0.);
std::vector weights2(4, 1.);
weights2[0] = 0.;
weights2[1] = 0.;
Vector means2(3, -1.);
Matrix m1 = PolynomialMap::Covariances(values, weights0, means0);
Matrix m2 = PolynomialMap::Covariances(values, weights1, means1);
Matrix m3 = PolynomialMap::Covariances(values, weights2, means2);
EXPECT_TRUE(fabs(determinant(m1-Matrix(3, 3, 1.))) < 1e-6);
EXPECT_TRUE(fabs(determinant(m2-Matrix(3, 3, 1.))) < 1e-6);
EXPECT_TRUE(fabs(determinant(m3)) < 1e-6);
}
TEST_F(PolynomialMapTest, LeastSquaresFittingErrorHandling) {
// Check that the error matrix term does *something* (anything) and handles
// correctly bad input (throws)
// Maths is checked in python tests... as it requires high stats
MAUS::Squeak::mout(MAUS::Squeak::debug) << "PolynomialLeastSquaresTest" << std::endl;
int nX = 4;
int nY = 4;
int nZ = 4;
Matrix mat(3, 4, 0.);
mat(1, 1) = 1.;
mat(2, 1) = 4.;
mat(3, 1) = 1.;
mat(1, 2) = 2.;
mat(2, 2) = 3.;
mat(3, 2) = 2.;
mat(1, 3) = 7.;
mat(2, 3) = 11.;
mat(3, 3) = 7.;
mat(1, 4) = 13.;
mat(2, 4) = 3.;
mat(3, 4) = 13.;
VectorMap* weightFunction = NULL;
PolynomialMap* vecF = new PolynomialMap(3, mat);
std::vector< std::vector > points(nX*nY*nZ, std::vector(3));
std::vector< std::vector > values(nX*nY*nZ, std::vector(3));
std::vector weights(nX*nY*nZ, 1);
size_t n_coeffs = vecF->NumberOfPolynomialCoefficients();
Matrix errs1a(n_coeffs, n_coeffs, 0.);
Matrix errs1b(n_coeffs, n_coeffs, 1.);
for (int i = 0; i < nX; i++)
for (int j = 0; j < nY; j++)
for (int k = 0; k < nZ; k++) {
int a = k+j*nZ + i*nY*nZ;
points[a][0] = i/static_cast(nX)*105.;
points[a][1] = j/static_cast(nY)*201.;
points[a][2] = k/static_cast(nZ)*105.;
vecF->F(&points[a][0], &values[a][0]);
}
delete vecF;
// null weightFunction just tests branching to
// PolynomialLeastSquaresFit(points, values, 1)
bool testpass = true;
PolynomialMap* pVec1a = PolynomialMap::PolynomialLeastSquaresFit(
points, values, 1, weightFunction, errs1a);
PolynomialMap* pVec1b = PolynomialMap::PolynomialLeastSquaresFit(
points, values, 1, weightFunction, errs1b);
Matrix coeff1a = pVec1a->GetCoefficientsAsMatrix();
Matrix coeff1b = pVec1b->GetCoefficientsAsMatrix();
for (size_t i = 1; i <= coeff1a.number_of_rows(); i++)
for (size_t j = 1; j <= coeff1b.number_of_columns(); j++) {
if (fabs(coeff1a(i, j) - mat(i, j)) > 1e-6)
testpass = false;
if (fabs(coeff1b(i, j) - mat(i, j)) < 1e-6)
testpass = false;
}
delete pVec1b;
delete pVec1a;
EXPECT_TRUE(testpass);
Matrix errs2(n_coeffs, n_coeffs-1, 0.);
EXPECT_THROW(PolynomialMap::PolynomialLeastSquaresFit(
points, values, 1, weightFunction, errs2), MAUS::Exceptions::Exception);
Matrix errs3(n_coeffs-1, n_coeffs, 0.);
EXPECT_THROW(PolynomialMap::PolynomialLeastSquaresFit(
points, values, 1, weightFunction, errs3), MAUS::Exceptions::Exception);
}
TEST_F(PolynomialMapTest, LeastSquaresFitting) {
MAUS::Squeak::mout(MAUS::Squeak::debug) << "PolynomialLeastSquaresTest" << std::endl;
int nX = 4;
int nY = 4;
int nZ = 4;
CLHEP::HepMatrix mat(3, 4, 0);
mat[0][0] = 1.;
mat[1][0] = 4.;
mat[2][0] = 1.;
mat[0][1] = 2.;
mat[1][1] = 3.;
mat[2][1] = 2.;
mat[0][2] = 7.;
mat[1][2] = 11.;
mat[2][2] = 7.;
mat[0][3] = 13.;
mat[1][3] = 3.;
mat[2][3] = 13.;
VectorMap* weightFunction = NULL;
PolynomialMap* vecF = new PolynomialMap(3, Matrix(mat));
std::vector< std::vector > points(nX*nY*nZ, std::vector(3));
std::vector< std::vector > values(nX*nY*nZ, std::vector(3));
std::vector weights(nX*nY*nZ, 1);
for (int i = 0; i < nX; i++)
for (int j = 0; j < nY; j++)
for (int k = 0; k < nZ; k++) {
int a = k+j*nZ + i*nY*nZ;
points[a][0] = i/static_cast(nX)*105.;
points[a][1] = j/static_cast(nY)*201.;
points[a][2] = k/static_cast(nZ)*105.;
vecF->F(&points[a][0], &values[a][0]);
}
delete vecF;
// null weightFunction just tests branching to
// PolynomialLeastSquaresFit(points, values, 1)
PolynomialMap* pVec
= PolynomialMap::PolynomialLeastSquaresFit(
points, values, 1, weightFunction);
// polynomial order should be 1
EXPECT_EQ(pVec->PolynomialOrder(), static_cast(1));
// with polynomial order 1, the number of poly. coeff. is just the number of
// variables plus one for the constant term
EXPECT_EQ(pVec->NumberOfPolynomialCoefficients(), static_cast(4));
CLHEP::HepMatrix recCoeff
= MAUS::CLHEP::HepMatrix(pVec->GetCoefficientsAsMatrix());
bool testpass = true;
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Input" << mat << "Output" << recCoeff
<< std::endl;
for (int i = 0; i < recCoeff.num_row(); i++)
for (int j = 0; j < recCoeff.num_col(); j++)
if (fabs(recCoeff[i][j] - mat[i][j]) > 1e-6) testpass = false;
delete pVec;
EXPECT_TRUE(testpass);
testpass = true;
// now add an outlier with 0 weight - try weighted fit
points.push_back(std::vector(3, 92.));
values.push_back(std::vector(3, 17.));
weights.push_back(0.);
pVec = PolynomialMap::PolynomialLeastSquaresFit(points, values,
1, weights);
// polynomial order should be 1
EXPECT_EQ(pVec->PolynomialOrder(), static_cast(1));
// with polynomial order 1, the number of poly. coeff. is just the number of
// variables plus one for the constant term
EXPECT_EQ(pVec->NumberOfPolynomialCoefficients(), static_cast(4));
recCoeff = MAUS::CLHEP::HepMatrix(pVec->GetCoefficientsAsMatrix());
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Weighted Input" << mat << "Weighted Output"
<< recCoeff << std::endl;
for (int i = 0; i < recCoeff.num_row(); i++)
for (int j = 0; j < recCoeff.num_col(); j++)
if (fabs(recCoeff[i][j] - mat[i][j]) > 1e-6) testpass = false;
delete pVec;
EXPECT_TRUE(testpass);
// same test as above but using VectorMap instead of std::vector
// for the weights
weightFunction
= new Function(&weight_function, points.size(), points.size());
testpass = true;
pVec = NULL;
pVec = PolynomialMap::PolynomialLeastSquaresFit(points, values,
1, weightFunction);
// polynomial order should be 1
EXPECT_EQ(pVec->PolynomialOrder(), static_cast(1));
// with polynomial order 1, the number of poly. coeff. is just the number of
// variables plus one for the constant term
EXPECT_EQ(pVec->NumberOfPolynomialCoefficients(), static_cast(4));
recCoeff = MAUS::CLHEP::HepMatrix(pVec->GetCoefficientsAsMatrix());
for (int i = 0; i < recCoeff.num_row(); i++)
for (int j = 0; j < recCoeff.num_col(); j++)
if (fabs(recCoeff[i][j] - mat[i][j]) > 1e-6) testpass = false;
if (pVec != NULL) {
delete pVec;
}
delete weightFunction;
EXPECT_TRUE(testpass);
testpass = true;
// now take some of the input values, try for a constrained fit
PolynomialMap Constraint(2, Matrix(mat.sub(1, 2, 1, 3)));
std::vector coeffs
= Constraint.GetCoefficientsAsVector();
for (int i = 0; i < 2; i++)
coeffs.erase(coeffs.begin());
PolynomialMap* constraintPVec = new PolynomialMap(coeffs);
pVec = PolynomialMap::ConstrainedPolynomialLeastSquaresFit(
points, values, 1, constraintPVec->GetCoefficientsAsVector(), weights);
// polynomial order should be 1
EXPECT_EQ(pVec->PolynomialOrder(), static_cast(1));
// with polynomial order 1, the number of poly. coeff. is just the number of
// variables plus one for the constant term
EXPECT_EQ(pVec->NumberOfPolynomialCoefficients(), static_cast(4));
recCoeff = MAUS::CLHEP::HepMatrix(pVec->GetCoefficientsAsMatrix());
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Constrained Input\n" << *constraintPVec
<< "Constrained Output\n" << *pVec << std::endl;
for (int i = 0; i < recCoeff.num_row(); i++)
for (int j = 0; j < recCoeff.num_col(); j++)
if (fabs(recCoeff[i][j] - mat[i][j]) > 1e-6) testpass = false;
delete pVec;
EXPECT_TRUE(testpass);
// bad points size
testpass = true;
try {
const std::vector< std::vector > bad_points;
PolynomialMap::ConstrainedPolynomialLeastSquaresFit(
bad_points, values,
1, constraintPVec->GetCoefficientsAsVector(), weights);
testpass = false;
} catch (MAUS::Exceptions::Exception exc) {}
ASSERT_TRUE(testpass);
// bad values size
testpass = true;
try {
const std::vector< std::vector > bad_values;
PolynomialMap::ConstrainedPolynomialLeastSquaresFit(
points, bad_values,
1, constraintPVec->GetCoefficientsAsVector(), weights);
testpass = false;
} catch (MAUS::Exceptions::Exception exc) {}
ASSERT_TRUE(testpass);
testpass = true;
// should return a copy of
double mat2[] = {1., 2., 7., 13., 200., 500., 800., 1100., 1400., 1700.,
1., 3., 8., 14., 300., 600., 900., 1200., 1500., 1800.,
1., 4., 9., 15., 400., 700., 1000., 1300., 1600., 1900.};
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Chi2SweepingLeastSquaresFit" << std::endl;
PolynomialMap* testF
= new PolynomialMap(3, Matrix(3, 10, mat2));
std::vector delta(3);
delta[0] = 1e-50;
delta[1] = 1e-50;
delta[2] = 1e-50;
// check we can make a polynomial vector at all
pVec = PolynomialMap::Chi2SweepingLeastSquaresFit(
*testF, 5, std::vector< PolynomialMap::PolynomialCoefficient >(),
1e-40, delta, 10., 100);
if (pVec == NULL) {
testpass = false;
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Failed to make PolynomialMap when "
<< "PolynomialMap expected " << pVec
<< std::endl;
} else {
Matrix o1 = pVec ->GetCoefficientsAsMatrix();
Matrix o2 = testF->GetCoefficientsAsMatrix();
testpass &= o1.number_of_rows() == o2.number_of_rows()
&& o1.number_of_columns() == o2.number_of_columns();
for (size_t i = 1; i <= o2.number_of_rows(); i++)
for (size_t j = 1; j <= o2.number_of_columns(); j++)
testpass &= fabs(o1(i, j) - o2(i, j)) < 1e-2;
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Input should be same as output\nInput\n"
<< *testF
<< "Output\n" << *pVec << " testpass "
<< testpass << std::endl;
}
if (pVec != NULL) delete pVec;
EXPECT_TRUE(testpass);
testpass = true;
// check we can get a decent fit at lower order to a higher order polynomial
delta[0] = 1e-50;
delta[1] = 1e-50;
delta[2] = 1e-50;
pVec = PolynomialMap::Chi2SweepingLeastSquaresFit(
*testF, 1, std::vector< PolynomialMap::PolynomialCoefficient >(),
1e-40, delta, 10., 100);
if (pVec == NULL) {
testpass = false;
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Failed to make PolynomialMap when "
<< "PolynomialMap expected " << pVec
<< std::endl;
} else {
// polynomial order should be 1
EXPECT_EQ(pVec->PolynomialOrder(), static_cast(1));
// with polynomial order 1, the number of poly. coeff. is just the number of
// variables plus one for the constant term
EXPECT_EQ(pVec->NumberOfPolynomialCoefficients(), static_cast(4));
Matrix o1 = pVec ->GetCoefficientsAsMatrix();
Matrix o2 = testF->GetCoefficientsAsMatrix();
testpass &= o1.number_of_rows() == o2.number_of_rows()
&& o1.number_of_columns() == 4;
for (size_t i = 1; i <= o1.number_of_rows(); i++)
for (size_t j = 1; j <= o1.number_of_columns(); j++)
testpass &= fabs(o1(i, j) - o2(i, j)) < 1e-6;
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Input should be same as output\nInput\n"
<< *testF << "Output\n" << *pVec
<< " testpass " << testpass << std::endl;
}
EXPECT_TRUE(testpass);
testpass = true;
// test that I return NULL if I can't converge; for these parameters
// floating point precision should mean that I don't converge.
delta[0] = 1e6;
delta[1] = 1e6;
delta[2] = 1e6;
pVec = PolynomialMap::Chi2SweepingLeastSquaresFit(
*testF, 5, std::vector< PolynomialMap::PolynomialCoefficient >(),
1e-60, delta, 10., 100);
if (pVec != NULL)
testpass = false;
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Should be NULL " << pVec << " testpass "
<< testpass << std::endl;
EXPECT_TRUE(testpass);
testpass = true;
// the point of mat3 is that it introduces an effective unit into each
// dimension; so x_0 has units like 1., x_1 has units like 1e6 and x_2 has
// units like 1e3 validity region (delta at output) should reflect the units
double deltaMaxA[] = {1e12, 1e12, 1e12, 1e12};
std::vector deltaMax(deltaMaxA, deltaMaxA+3);
double mat3[] = {
1., 2., 7., 13.e3, 200., 500.e6, 800.e3, 1100.e12, 1400.e9, 1700.e6,
1., 3., 8.e6, 14.e3, 300., 600.e6, 900.e3, 1200.e12, 1500.e9, 1800.e6,
1., 4., 9.e6, 15.e3, 400., 700.e6, 1000.e3, 1300.e12, 1600.e9, 1900.e6};
PolynomialMap* testF2
= new PolynomialMap(3, Matrix(3, 10, mat3));
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Chi2SweepingLeastSquaresFitVariableWalls"
<< std::endl;
// delta.push_back(0.);
delta[0] = 1e-50;
delta[1] = 1e-50;
delta[2] = 1e-50;
pVec = PolynomialMap::Chi2SweepingLeastSquaresFitVariableWalls(
*testF2, 2, std::vector< PolynomialMap::PolynomialCoefficient >(),
1e-20, delta, 10., 100, deltaMax);
// polynomial order should be 2
EXPECT_EQ(pVec->PolynomialOrder(), static_cast(2));
// with point size 3 and polynomial order 2,
// the number of poly. coeff. is (3+2)!/(3!2!) = 10
EXPECT_EQ(pVec->NumberOfPolynomialCoefficients(), static_cast(10));
MAUS::Squeak::mout(MAUS::Squeak::debug) << "delta variable walls: ";
for (size_t i = 0; i < delta.size(); i++) {
MAUS::Squeak::mout(MAUS::Squeak::debug) << delta[i] << " ";
}
MAUS::Squeak::mout(MAUS::Squeak::debug) << std::endl;
delta[0] = 1e-50;
delta[1] = 1e-50;
delta[2] = 1e-50;
PolynomialMap* pVec2 = PolynomialMap::Chi2SweepingLeastSquaresFit(
*testF2, 2, std::vector< PolynomialMap::PolynomialCoefficient >(),
1e-20, delta, 10., 100);
MAUS::Squeak::mout(MAUS::Squeak::debug) << "delta fixed walls: ";
for (size_t i = 0; i < delta.size(); i++) {
MAUS::Squeak::mout(MAUS::Squeak::debug) << delta[i] << " ";
}
MAUS::Squeak::mout(MAUS::Squeak::debug) << std::endl;
if (pVec == NULL) {
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Error - "
<< "Chi2SweepingLeastSquaresFitVariableWalls "
<< "returns " << pVec << std::endl;
testpass = false;
} else {
// polynomial order should be 2
EXPECT_EQ(pVec2->PolynomialOrder(), static_cast(2));
// with point size 3 and polynomial order 2,
// the number of poly. coeff. is (3+2)!/(3!2!) = 10
EXPECT_EQ(pVec2->NumberOfPolynomialCoefficients(), static_cast(10));
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Input should be same as output\nInput\n"
<< *testF2
<< "Output\n" << *pVec
<< "For comparison, using normal algorithm\n"
<< *pVec2 << std::endl;
Matrix o1 = pVec ->GetCoefficientsAsMatrix();
Matrix o2 = testF2->GetCoefficientsAsMatrix();
testpass &= o1.number_of_rows() == o2.number_of_rows()
&& o1.number_of_columns() == o2.number_of_columns();
for (size_t i = 1;
i <= o1.number_of_rows() && i <= o2.number_of_rows();
i++) {
for (size_t j = 1;
j <= o1.number_of_columns() && j <= o2.number_of_columns();
j++) {
testpass
&= fabs(o1(i, j) - o2(i, j))/fabs(o1(i, j) + o2(i, j)) < 1.e-3
|| fabs(o1(i, j) + o2(i, j)) < 1e-9;
}
}
}
if (pVec != NULL) delete pVec;
MAUS::Squeak::mout(MAUS::Squeak::debug) << "testpass " << testpass << std::endl;
EXPECT_TRUE(testpass);
testpass = true;
// test that I return NULL if I can't converge; for these parameters floating
// point precision should mean that I don't converge.
delta[0] = 1e6;
delta[1] = 1e6;
delta[2] = 1e6;
pVec = PolynomialMap::Chi2SweepingLeastSquaresFitVariableWalls(
*testF2, 5, std::vector< PolynomialMap::PolynomialCoefficient >(),
1e-60, delta, 10., 100, deltaMax);
if (pVec != NULL)
testpass = false;
MAUS::Squeak::mout(MAUS::Squeak::debug) << "Should be NULL " << pVec << std::endl;
delete testF;
MAUS::Squeak::mout(MAUS::Squeak::debug) << "PolynomialLeastSquaresTest " << *testF2
<< testpass << std::endl;
EXPECT_TRUE(testpass);
}
TEST_F(PolynomialMapTest, SpaceTransform) {
int myints[] = {1, 2};
std::vector inVariablesByVector(
myints, myints + sizeof(myints) / sizeof(int));
PolynomialMap::PolynomialCoefficient coefficient
= PolynomialMap::PolynomialCoefficient(inVariablesByVector, 0, 1.1);
int space_in_array[] = {0, 2, 3, 5, 6};
std::vector space_in(
space_in_array, space_in_array + sizeof(space_in_array) / sizeof(int));
int space_out_array[] = {4, 7, 1, 2, 3, 0};
std::vector space_out(
space_out_array, space_out_array + sizeof(space_out_array) / sizeof(int));
coefficient.SpaceTransform(space_in, space_out);
std::vector transformedInVariables = coefficient.InVariables();
EXPECT_EQ(3, transformedInVariables[0]);
EXPECT_EQ(4, transformedInVariables[1]);
EXPECT_EQ(5, coefficient.OutVariable());
EXPECT_EQ(1.1, coefficient.Coefficient());
// in variable not in space mapping
bool testpass = true;
try {
coefficient.SpaceTransform(space_in, space_out);
testpass = false;
} catch (MAUS::Exceptions::Exception exc) {}
ASSERT_TRUE(testpass);
// out variable not in space mapping
space_in[3] = 7;
space_in[4] = 1;
testpass = true;
try {
coefficient.SpaceTransform(space_in, space_out);
testpass = false;
} catch (MAUS::Exceptions::Exception exc) {}
ASSERT_TRUE(testpass);
}
/*
TEST_F(PolynomialMapTest, MakePolynomialVector) {
const double point_data[2] = {1.0, 2.0};
Vector point(point_data, 2);
Vector polynomial_vector;
test.polynomial_map_->MakePolynomialVector(point, polynomial_vector);
for (size_t index = 0; index < 2; ++index) {
EXPECT_NEAR(point[index], point_data[index], 1.e-6);
}
}
*/
TEST_F(PolynomialMapTest, SetCoefficients) {
Matrix coefficient_matrix(3, 6, 0.); // initialize all elements to zero
PolynomialMap test_map(2, coefficient_matrix);
const double coefficients[18] = {
1., 2., 3., 4., 5., 6.,
0., 1., 4., 9., 16., 25.,
-1., -2., -3., -4., -5., -6.,
};
coefficient_matrix = Matrix(3, 6, coefficients);
test_map.SetCoefficients(coefficient_matrix);
const Matrix test_coefficient_matrix
= test_map.GetCoefficientsAsMatrix();
const Matrix master_coefficient_matrix
= polynomial_map_->GetCoefficientsAsMatrix();
for (size_t row = 0; row < 3; ++row) {
for (size_t column = 0; column < 6; ++column) {
EXPECT_NEAR(test_coefficient_matrix(row+1, column+1),
master_coefficient_matrix(row+1, column+1),
1.e-6);
}
}
}
TEST_F(PolynomialMapTest, UnmakePolynomialVector) {
const double point_data[2] = {1.0, 2.0};
Vector point(point_data, 2);
Vector polynomial_vector;
polynomial_map_->MakePolynomialVector(point, polynomial_vector);
polynomial_map_->UnmakePolynomialVector(polynomial_vector, point);
for (size_t index = 0; index < 2; ++index) {
EXPECT_NEAR(point[index], point_data[index], 1.e-6);
}
Vector empty_point;
polynomial_map_->UnmakePolynomialVector(polynomial_vector, empty_point);
for (size_t index = 0; index < 2; ++index) {
EXPECT_NEAR(empty_point[index], point_data[index], 1.e-6);
}
Vector wrong_size_point(4);
bool testpass = true;
try {
polynomial_map_->UnmakePolynomialVector(polynomial_vector, wrong_size_point);
testpass = false;
} catch (MAUS::Exceptions::Exception exc) {}
ASSERT_TRUE(testpass);
double polynomial_vector_data[polynomial_vector.size()];
polynomial_map_->MakePolynomialVector(point_data, polynomial_vector_data);
double point_test[2];
polynomial_map_->UnmakePolynomialVector(polynomial_vector_data, point_test);
for (size_t index = 0; index < 2; ++index) {
EXPECT_NEAR(point_test[index], point_data[index], 1.e-6);
}
}
TEST_F(PolynomialMapTest, generate_polynomial_2) {
const double y0[3] = {1., 0., -1.};
const double y1[3] = {7., 10., -7.};
for (size_t value_var_index = 0; value_var_index < 3; ++value_var_index) {
Vector polynomial = generate_polynomial_2D(*polynomial_map_,
0, // point var index
value_var_index,
0., // point var min
1., // point var max
1.); // point var delta
const double y[2] = {y0[value_var_index], y1[value_var_index]};
for (size_t index = 0; index < 2; ++index) {
EXPECT_NEAR(y[index], polynomial[index], 1.e-6);
}
}
}
TEST_F(PolynomialMapTest, RecentredNotSupported) {
bool testpass = true;
try {
double * point = NULL;
polynomial_map_->Recentred(point);
testpass = false;
} catch (MAUS::Exceptions::Exception exc) {}
ASSERT_TRUE(testpass);
}
TEST_F(PolynomialMapTest, InverseNotSupported) {
bool testpass = true;
try {
polynomial_map_->Inverse();
testpass = false;
} catch (MAUS::Exceptions::Exception exc) {}
ASSERT_TRUE(testpass);
}