Commit 5ae8457a authored by Ludovic Courtès's avatar Ludovic Courtès

core: 'data' aggregates 'parameters' instead of inheriting from it.

Suggested by Romain Pacanowski.
parent 9173d803
/* ALTA --- Analysis of Bidirectional Reflectance Distribution Functions
Copyright (C) 2013, 2014, 2015 Inria
Copyright (C) 2013, 2014, 2015, 2016 Inria
This file is part of ALTA.
......@@ -17,41 +17,58 @@ using namespace alta;
void data::save(const std::string& filename) const
{
std::ofstream file;
std::ofstream file;
file.exceptions(std::ios_base::failbit);
file.open(filename.c_str(), std::ios_base::trunc);
file.exceptions(std::ios_base::goodbit);
file.exceptions(std::ios_base::failbit);
file.open(filename.c_str(), std::ios_base::trunc);
file.exceptions(std::ios_base::goodbit);
alta::save_data_as_text(file, *this);
file.close();
file.close();
}
bool data::equals(const data& data, double epsilon)
{
if (size() != data.size()
|| dimX() != data.dimX() || dimY() != data.dimY()
|| input_parametrization() != data.input_parametrization()
|| output_parametrization() != data.output_parametrization())
return false;
for(int i = 0; i < data.size(); i++)
{
vec other = data.get(i);
vec self = get(i);
if (self.size() != other.size()) // should not happen
return false;
for (int j = 0; j < self.size(); j++)
{
double diff = std::abs(self[j] - other[j]);
if (diff > epsilon)
return false;
}
}
return true;
if (size() != data.size()
|| _parameters.dimX() != data.parametrization().dimX()
|| _parameters.dimY() != data.parametrization().dimY()
|| (_parameters.input_parametrization()
!= data.parametrization().input_parametrization())
|| (_parameters.output_parametrization()
!= data.parametrization().output_parametrization()))
return false;
for(int i = 0; i < data.size(); i++)
{
vec other = data.get(i);
vec self = get(i);
if (self.size() != other.size()) // should not happen
return false;
for (int j = 0; j < self.size(); j++)
{
double diff = std::abs(self[j] - other[j]);
if (diff > epsilon)
return false;
}
}
return true;
}
void data::setMin(const vec& min)
{
#ifdef DEBUG
assert(min.size() == _nX) ;
#endif
_min = min ;
}
void data::setMax(const vec& max)
{
#ifdef DEBUG
assert(max.size() == _nX) ;
#endif
_max = max ;
}
......@@ -34,36 +34,28 @@ namespace alta {
/*! \brief A data object. Allows to load data from files.
* \ingroup core
*/
class data : public parametrized
class data
{
public: // methods
public: // methods
data() : parametrized()
{}
data() {}
data( unsigned int dim_X, unsigned int dim_Y)
: parametrized( dim_X, dim_Y )
{
}
data(unsigned int dim_X, unsigned int dim_Y)
: _parameters(dim_X, dim_Y)
{}
data(params::input in_param, params::output out_param)
: parametrized( in_param, out_param)
{
// Virtual destructor
virtual ~data() {}
}
// Load data from a file
virtual void load(const std::string& filename) = 0 ;
virtual void load(const std::string& filename, const arguments& args) = 0 ;
// Virtual destructor
virtual ~data() {}
// Save the data to a file
virtual void save(const std::string& filename) const;
// Load data from a file
virtual void load(const std::string& filename) = 0 ;
virtual void load(const std::string& filename, const arguments& args) = 0 ;
// Save the data to a file
virtual void save(const std::string& filename) const;
// Acces to data
virtual vec get(int i) const = 0 ;
// Acces to data
virtual vec get(int i) const = 0 ;
//! \brief Provide an evaluation of the data using interpolation. If
//! the data object does not provide an interpolation mechanism, it
......@@ -74,24 +66,51 @@ class data : public parametrized
//! match the total dimension: dimX + dimY.
virtual vec value(const vec& in) const = 0;
//! \brief Put the sample inside the data
virtual void set(const vec& x) = 0;
virtual void set(int i, const vec& x) = 0;
//! \brief Put the sample inside the data
virtual void set(const vec& x) = 0;
virtual void set(int i, const vec& x) = 0;
// Get data size, e.g. the number of samples to fit
virtual int size() const = 0 ;
// Get data size, e.g. the number of samples to fit
virtual int size() const = 0 ;
//! \brief Return true if this object is equal to DATA ±ε.
virtual bool equals(const data& data,
double epsilon =
//! \brief Return true if this object is equal to DATA ±ε.
virtual bool equals(const data& data,
double epsilon =
std::pow(1.0, -int(std::numeric_limits<double>::digits10 - 1)));
friend void load_data_from_binary(std::istream& in, const alta::arguments& header,
alta::data& data);
friend void load_data_from_binary(std::istream& in, const alta::arguments& header,
alta::data& data);
const parameters& parametrization() const {
return _parameters;
}
void setParametrization(const parameters& p) {
_parameters = p;
}
/* Maximum values of the data */
//! \brief Set the minimum value the input can take
void setMin(const vec& min) ;
//! \brief Set the maximum value the input can take
void setMax(const vec& max) ;
//! \brief Get the minimum value the input can take
// FIXME: Return a reference.
vec min() const { return _min; };
//! \brief Get the maximum value the input can take
vec max() const { return _max; };
protected: // data
protected: // data
parameters _parameters;
vec _min, _max;
} ;
/*! \brief Change the parametrization of data to fit the parametrization of the
......@@ -103,88 +122,88 @@ class data : public parametrized
*/
class data_params : public data
{
public: // structures
//! \brief when changing from a parametrization to another, you might
//! lose some dimensions. This list enumerate the different operators
//! that can be applied on the raw data to be clusterized.
//! \note by default we use <em>none</em>, but if the input space
//! dimension is reduced, the program will halt.
enum clustering
{
MEAN,
MEDIAN,
NONE
};
public: // methods
//! \brief contructor requires the definition of a base class that
//! has a parametrization, and a new parametrization.
data_params(const ptr<data> d, params::input new_param,
data_params::clustering method = data_params::NONE) :
_clustering_method(method)
{
setParametrization(new_param);
setParametrization(d->output_parametrization());
_nX = params::dimension(new_param);
_nY = d->dimY();
std::cout << "<<INFO>> Reparametrization of the data" << std::endl;
//TODO
//clustering<data>(d, _nY, d->parametrization(), new_param, _data);
std::cout << "<<INFO>> clustering left " << _data.size() << "/" << d->size() << " elements" << std::endl;
save(std::string("cluster.gnuplot"));
}
virtual vec value(const vec&) const
{
NOT_IMPLEMENTED();
}
// Load data from a file
virtual void load(const std::string&)
{
std::cerr << "<<ERROR>> this data type cannot load data" << std::endl;
throw;
}
virtual void load(const std::string&, const arguments&)
{
std::cerr << "<<ERROR>> this data type cannot load data" << std::endl;
throw;
}
// Acces to data
virtual vec get(int i) const
{
return _data[i];
}
//! \todo This should crash at execution.
virtual void set(const vec& x)
{
this->set(x);
}
virtual void set(int i, const vec& x)
{
this->set(i, x);
}
// Get data size, e.g. the number of samples to fit
virtual int size() const
{
return _data.size();
}
protected: // data
data_params::clustering _clustering_method;
std::vector<vec> _data;
public: // structures
//! \brief when changing from a parametrization to another, you might
//! lose some dimensions. This list enumerate the different operators
//! that can be applied on the raw data to be clusterized.
//! \note by default we use <em>none</em>, but if the input space
//! dimension is reduced, the program will halt.
enum clustering
{
MEAN,
MEDIAN,
NONE
};
public: // methods
//! \brief contructor requires the definition of a base class that
//! has a parametrization, and a new parametrization.
data_params(const ptr<data> d, params::input new_param,
data_params::clustering method = data_params::NONE) :
_clustering_method(method)
{
_parameters.setParametrization(new_param);
_parameters.setParametrization(d->parametrization().output_parametrization());
_parameters.setDimX(params::dimension(new_param));
_parameters.setDimY(d->parametrization().dimY());
std::cout << "<<INFO>> Reparametrization of the data" << std::endl;
//TODO
//clustering<data>(d, _nY, d->parametrization(), new_param, _data);
std::cout << "<<INFO>> clustering left " << _data.size() << "/" << d->size() << " elements" << std::endl;
save(std::string("cluster.gnuplot"));
}
virtual vec value(const vec&) const
{
NOT_IMPLEMENTED();
}
// Load data from a file
virtual void load(const std::string&)
{
std::cerr << "<<ERROR>> this data type cannot load data" << std::endl;
throw;
}
virtual void load(const std::string&, const arguments&)
{
std::cerr << "<<ERROR>> this data type cannot load data" << std::endl;
throw;
}
// Acces to data
virtual vec get(int i) const
{
return _data[i];
}
//! \todo This should crash at execution.
virtual void set(const vec& x)
{
this->set(x);
}
virtual void set(int i, const vec& x)
{
this->set(i, x);
}
// Get data size, e.g. the number of samples to fit
virtual int size() const
{
return _data.size();
}
protected: // data
data_params::clustering _clustering_method;
std::vector<vec> _data;
};
}
......
......@@ -31,275 +31,292 @@ void alta::load_data_from_text(std::istream& input,
// file.
static alta::arguments args;
vec min, max ;
vec ymin, ymax;
vec min, max ;
vec ymin, ymax;
result._nX = 0 ; result._nY = 0 ;
if(! header.is_defined("DIM")) {
std::cerr << "<<ERROR>> Undefined dimensions ! ";
std::cerr << "Please add DIM [int] [int] into the file header." << std::endl;
throw;
}
if(! header.is_defined("DIM")) {
std::cerr << "<<ERROR>> Undefined dimensions ! ";
std::cerr << "Please add DIM [int] [int] into the file header." << std::endl;
throw;
}
params::input in_param = params::parse_input(header.get_string("PARAM_IN", "UNKNOWN_INPUT"));
params::output out_param = params::parse_output(header.get_string("PARAM_OUT", "UNKNOWN_OUTPUT"));
params::input in_param = params::parse_input(header.get_string("PARAM_IN", "UNKNOWN_INPUT"));
params::output out_param = params::parse_output(header.get_string("PARAM_OUT", "UNKNOWN_OUTPUT"));
result.setParametrizations(in_param, out_param);
std::pair<int, int> dim = header.get_pair<int>("DIM");
std::pair<int, int> dim = header.get_pair<int>("DIM");
result.setDimX(dim.first);
result.setDimY(dim.second);
min = args.get_vec("min", result._nX, -std::numeric_limits<float>::max()) ;
max = args.get_vec("max", result._nX, std::numeric_limits<float>::max()) ;
min = args.get_vec("min", dim.first, -std::numeric_limits<float>::max()) ;
max = args.get_vec("max", dim.first, std::numeric_limits<float>::max()) ;
#ifdef DEBUG
std::cout << "<<DEBUG>> data will remove outside of " << min << " -> " << max << " x-interval" << std::endl;
std::cout << "<<DEBUG>> data will remove outside of " << min << " -> " << max << " x-interval" << std::endl;
#endif
ymin = args.get_vec("ymin", result._nY, -std::numeric_limits<float>::max()) ;
ymax = args.get_vec("ymax", result._nY, std::numeric_limits<float>::max()) ;
ymin = args.get_vec("ymin", dim.second, -std::numeric_limits<float>::max()) ;
ymax = args.get_vec("ymax", dim.second, std::numeric_limits<float>::max()) ;
#ifdef DEBUG
std::cout << "<<DEBUG>> data will remove outside of " << ymin << " -> " << ymax << " y-interval" << std::endl;
std::cout << "<<DEBUG>> data will remove outside of " << ymin << " -> " << ymax << " y-interval" << std::endl;
#endif
for(int k=0; k<result.dimX(); ++k)
{
result._min[k] = std::numeric_limits<double>::max() ;
result._max[k] = -std::numeric_limits<double>::max() ;
}
int vs_value = header.get_int("VS");
// Now read the body.
while(input.good())
{
std::string line ;
std::getline(input, line) ;
std::stringstream linestream(line) ;
// Discard comments and empty lines.
if(line.empty() || linestream.peek() == '#')
{
continue ;
}
else
{
// Read the data point x and y coordinates
vec v = vec::Zero(result.dimX() + 3*result.dimY()) ;
for(int i=0; i<result.dimX()+result.dimY(); ++i)
{
linestream >> v[i] ;
}
// If data is not in the interval of fit
bool is_in = true ;
for(int i=0; i<result.dimX(); ++i)
{
if(v[i] < min[i] || v[i] > max[i])
{
is_in = false ;
}
}
for(int i=0; i<result.dimY(); ++i)
{
if(v[result.dimX()+i] < ymin[i] || v[result.dimX()+i] > ymax[i])
{
is_in = false ;
}
}
if(!is_in)
{
continue ;
}
// /*
// Correction of the data by 1/cosine(theta_L)
double factor = 1.0;
if(args.is_defined("data-correct-cosine"))
{
double cart[6];
params::convert(&v[0], result.input_parametrization(), params::CARTESIAN, cart);
if(cart[5] > 0.0 && cart[2] > 0.0)
{
factor = 1.0/cart[5]*cart[2];
for(int i=0; i<result.dimY(); ++i)
{
v[i + result.dimX()] /= factor;
}
}
else
{
continue;
}
}
// End of correction
// */
// Check if the data containt a vertical segment around the mean
// value.
for(int i=0; i<result.dimY(); ++i)
{
double min_dt = 0.0;
double max_dt = 0.0;
if(i == 0 && vs_value == 2)
{
linestream >> min_dt ;
linestream >> max_dt ;
min_dt = min_dt-v[result.dimX()+i];
max_dt = max_dt-v[result.dimX()+i];
}
else if(i == 0 && vs_value == 1)
{
double dt ;
linestream >> dt ;
min_dt = -dt;
max_dt = dt;
}
else
{
double dt = args.get_float("dt", 0.1f);
min_dt = -dt;
max_dt = dt;
}
if(args.is_defined("dt-relative"))
{
v[result.dimX() + result.dimY()+i] = v[result.dimX() + i] * (1.0 + min_dt) ;
v[result.dimX() + 2*result.dimY()+i] = v[result.dimX() + i] * (1.0 + max_dt) ;
}
else if(args.is_defined("dt-max"))
{
v[result.dimX() + result.dimY()+i] = v[result.dimX() + i] + std::max(v[result.dimX() + i] * min_dt, min_dt);
v[result.dimX() + 2*result.dimY()+i] = v[result.dimX() + i] + std::max(v[result.dimX() + i] * max_dt, max_dt);
}
else
{
v[result.dimX() + result.dimY()+i] = v[result.dimX() + i] + min_dt ;
v[result.dimX() + 2*result.dimY()+i] = v[result.dimX() + i] + max_dt ;
}
// You can enforce the vertical segment to stay in the positive
// region using the --data-positive command line argument. Note
// that the data point is also clamped to zero if negative.
if(args.is_defined("dt-positive"))
{
v[result.dimX() + i] = std::max(v[result.dimX() + i], 0.0);
v[result.dimX() + result.dimY()+i] = std::max(v[result.dimX() + result.dimY()+i], 0.0);
v[result.dimX() + 2*result.dimY()+i] = std::max(v[result.dimX() + 2*result.dimY()+i], 0.0);
}
result._min.resize(dim.first);
result._max.resize(dim.first);
for(int k=0; k<dim.first; ++k)
{
result._min[k] = std::numeric_limits<double>::max();
result._max[k] = -std::numeric_limits<double>::max();
}
int vs_value = header.get_int("VS");
// Now read the body.
while(input.good())
{
std::string line ;
std::getline(input, line) ;
std::stringstream linestream(line) ;
// Discard comments and empty lines.
if(line.empty() || linestream.peek() == '#')
{
continue ;
}
else
{
// Read the data point x and y coordinates
vec v = vec::Zero(dim.first + 3*dim.second) ;
for(int i=0; i<dim.first+dim.second; ++i)
{
linestream >> v[i] ;
}
// If data is not in the interval of fit
bool is_in = true ;
for(int i=0; i<dim.first; ++i)