cgal/Bounding_volumes/archive/test_extensive/stability/stability.h

320 lines
8.2 KiB
C++

// (Refer to file stability.cpp or stability-exact.cpp for more information.)
#ifndef MINIBALL_STABILITY
#define MINIBALL_STABILITY
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <fstream>
#include <CGAL/Min_sphere_of_spheres_d.h>
// A functor to convert doubles to some other type T:
template<typename T>
struct fromDouble {
typedef T Result;
const T operator()(const double x) {
return static_cast<T>(x);
}
};
// A class to build an iterator from a functor and an iterator.
// Assumes that Functor::Result is the return type of
// Functor::operator().
template<typename Iterator,typename Functor>
class FunctorIterator {
private:
Iterator it;
Functor f;
public:
typedef typename Functor::Result Result;
FunctorIterator(Iterator it) : it(it) {}
FunctorIterator(Iterator it,const Functor& f) : it(it), f(f) {}
const Result operator*() {
return f(*it);
}
FunctorIterator& operator++() {
++it;
return *this;
}
FunctorIterator operator++(int) {
FunctorIterator old(*this);
++(*this);
return old;
}
bool operator!=(const FunctorIterator& i) {
return it != i.it;
}
};
// We start with the definition of a sphere class parametrized by
// the number type and the dimension:
template<typename Number,int d>
class Ball {
private: // representation:
Number c[d];
Number r;
public: // construction:
// Construct a ball with radius r and center coordinates
// from the range [first,first+d).
template<typename InputIterator>
Ball(InputIterator first,const Number& r) : r(r) {
assert(r >= 0);
std::copy(first,first+d,c);
}
public: // access:
// Returns the radius.
const Number& radius() const {
return r;
}
// Returns an iterator to the first coordinate of the center.
const Number *center() const {
return c;
}
// Returns the i-th coordinate for 0<=i<d.
const Number& operator[](int i) const {
assert(0<=i && i<d);
return c[i];
}
};
// The following is a traits class to make the Miniball package work
// with balls of the type Ball<d> defined above:
template<int d,
typename StorageNumberType,
typename NumberType,
typename Sqrt>
struct BallTraits {
// constants:
static const int D = d;
// types:
typedef Ball<StorageNumberType,d> Sphere;
typedef NumberType FT;
typedef CGAL::Default_algorithm Algorithm;
typedef Sqrt Use_square_roots;
typedef FunctorIterator< const StorageNumberType *,
fromDouble<NumberType> > Cartesian_const_iterator;
// routines:
inline static Cartesian_const_iterator
center_cartesian_begin(const Sphere& b) {
return Cartesian_const_iterator(b.center());
}
inline static FT radius(const Sphere& b) {
return static_cast<NumberType>(b.radius());
}
};
// A portable random number generator class:
class Uniform {
private:
int lastNo;
public:
Uniform() : lastNo(230575L) {}
double next() {
const int a = 16807L, m = 2147483647L, q = 127773L, r = 2836L;
int gamma = a * (lastNo % q) - r * (lastNo / q);
if (gamma > 0)
lastNo = gamma;
else
lastNo = gamma + m;
return static_cast<double>(lastNo)/m;
}
};
enum Perturbation {
None=0, Tiny=1, Small=2, Medium=3, Large=4
};
// The following routine reads a set of balls in R^d from a certain
// file, embeds them into R^D and perturbs their coordinates by a
// certain amount of pseudo-random noise. Finally, each ball is
// duplicated copies times. The resulting set of balls is returned in
// the variable balls.
template<int d,int D,typename Number>
void readConfiguration(const std::string& name, // name of the configuration
Perturbation perturb, // amount of perturbation
double magnitude, // magnitude of perturbation
int copies, // number of copies
std::vector< Ball<Number,D> >& balls) {
// clear set and open data file:
balls.clear();
std::ifstream data(name.c_str());
// determine amount of permutation:
Uniform rng;
const double amounts[5] = { 0, 1e-50, 1e-30, 1e-10, 1e-3 };
double amount = magnitude * amounts[static_cast<int>(perturb)];
// read number of input balls:
int n;
data >> n;
for (int i=0; i<n; ++i) {
// read coordinate and radius of the i-th ball:
Number r,c[d];
for (int j=0; j<d; ++j)
data >> c[j];
data >> r;
// insert duplicates:
for (int k=0; k<copies; ++k) {
// embed and perturb:
Number ce[D];
for (int j=0; j<d; ++j)
ce[j] = c[j] + (rng.next()-0.5)*amount;
for (int j=d; j<D; ++j)
ce[j] = (rng.next()-0.5)*amount;
// add to set:
balls.push_back(Ball<Number,D>(ce,r));
}
}
}
// Converts a string to some type T.
template <typename T>
T strTo(const std::string& str) {
std::stringstream strm(str);
T t;
strm >> t;
return t;
}
// Converts a value to a string.
template <typename T>
std::string toStr(const T& t) {
std::stringstream strm;
strm << t;
return strm.str();
}
struct RunFlag {};
struct BuildFlag {};
template<int d,int D>
void atomicTest(const int,const std::string&,Perturbation,
const std::vector< Ball<double,D> >& S,RunFlag);
template<int d,int D>
void atomicTest(const int,const std::string&,Perturbation,
const std::vector< Ball<double,D> >& S,BuildFlag);
// (See routine basicTest() below.)
int from = 0, to = 1000, curr = -1;
template<int d,int D,typename Flag>
void basicTest(const std::string& name,double magnitude,
Perturbation perturb,int copies) {
// decide whether to do the test or not:
++curr;
if (curr < from || curr > to)
return;
// construct the set of balls:
std::vector< Ball<double,D> > S;
readConfiguration<d,D>(name,perturb,magnitude,copies,S);
// perform test:
std::cout << std::endl << " Perturbation: ";
switch (perturb) {
case None:
std::cout << "none" << std::endl;
break;
case Tiny:
std::cout << "10^-50" << std::endl;
break;
case Small:
std::cout << "10^-30" << std::endl;
break;
case Medium:
std::cout << "10^-10" << std::endl;
break;
case Large:
std::cout << "10^-3" << std::endl;
break;
}
atomicTest<d,D>(curr,name,perturb,S,Flag());
}
template <int d,typename Flag>
void test(const std::string& f,double magnitude) {
using std::cout;
using std::endl;
cout << f << endl;
cout << " Set (d): ";
basicTest<d,d,Flag>(f,magnitude,None,1);
basicTest<d,d,Flag>(f,magnitude,Tiny,1);
basicTest<d,d,Flag>(f,magnitude,Small,1);
basicTest<d,d,Flag>(f,magnitude,Medium,1);
basicTest<d,d,Flag>(f,magnitude,Large,1);
cout << endl;
cout << " Multiset (d): ";
basicTest<d,d,Flag>(f,magnitude,None,10);
basicTest<d,d,Flag>(f,magnitude,Tiny,10);
basicTest<d,d,Flag>(f,magnitude,Small,10);
basicTest<d,d,Flag>(f,magnitude,Medium,10);
basicTest<d,d,Flag>(f,magnitude,Large,10);
cout << endl;
cout << " Set (D): ";
basicTest<d,2*d,Flag>(f,magnitude,None,1);
basicTest<d,2*d,Flag>(f,magnitude,Tiny,1);
basicTest<d,2*d,Flag>(f,magnitude,Small,1);
basicTest<d,2*d,Flag>(f,magnitude,Medium,1);
basicTest<d,2*d,Flag>(f,magnitude,Large,1);
cout << endl;
cout << " Multiset (D): ";
basicTest<d,2*d,Flag>(f,magnitude,None,10);
basicTest<d,2*d,Flag>(f,magnitude,Tiny,10);
basicTest<d,2*d,Flag>(f,magnitude,Small,10);
basicTest<d,2*d,Flag>(f,magnitude,Medium,10);
basicTest<d,2*d,Flag>(f,magnitude,Large,10);
cout << endl;
cout << endl;
}
template<typename Flag>
void mainTest() {
test<2,Flag>("data/cocircular_points_small_radius_2.data",1e8);
test<2,Flag>("data/cocircular_points_large_radius_2.data",1e9);
test<3,Flag>("data/almost_cospherical_points_3.data",1);
test<10,Flag>("data/almost_cospherical_points_10.data",1);
test<3,Flag>("data/longitude_latitude_model_3.data",1);
test<3,Flag>("data/random_points_3.data",1);
test<5,Flag>("data/random_points_5.data",1);
test<10,Flag>("data/random_points_10.data",1);
test<10,Flag>("data/simplex_10.data",1);
test<15,Flag>("data/simplex_15.data",1);
test<10,Flag>("data/cube_10.data",1);
test<12,Flag>("data/cube_12.data",1);
test<2,Flag>("data/balls_on_boundary_2.data",1);
test<3,Flag>("data/balls_on_boundary_3.data",1);
}
#endif // MINIBALL_STABILITY