Commit f8843e56 authored by Ludovic Courtès's avatar Ludovic Courtès

core: vertical_segment: Store data in an 'Eigen::MatrixXd'.

parent d172fa6d
......@@ -36,6 +36,8 @@
#include <Eigen/Core>
typedef Eigen::VectorXd vec;
typedef Eigen::Ref<vec> vecref;
typedef Eigen::Ref<const vec> const_vecref;
// Convenience functions.
static inline double norm(const vec& v)
......
......@@ -21,31 +21,43 @@
# include <endian.h>
#endif
//using namespace alta;
using namespace Eigen;
static bool cosine_correction(vec& v, unsigned int dimX, unsigned int dimY,
// A deleter for arrays, to work around the lack of array support in C++11's
// 'shared_ptr':
// <http://stackoverflow.com/questions/8947579/why-isnt-there-a-stdshared-ptrt-specialisation#8947700>.
static void delete_array(double *thing)
{
delete[] thing;
}
static bool cosine_correction(vecref v, unsigned int dimX, unsigned int dimY,
alta::params::input in_param)
{
using namespace alta;
assert(v.size() == dimX + dimY);
// Correction of the data by 1/cosine(theta_L)
double factor = 1.0;
double cart[6];
params::convert(&v[0], in_param, params::CARTESIAN, cart);
params::convert(&v(0), in_param, params::CARTESIAN, cart);
if(cart[5] > 0.0 && cart[2] > 0.0)
{
factor = 1.0/cart[5]*cart[2];
for(unsigned int i = 0; i < dimY; ++i)
{
v[i + dimX] /= factor;
std::cout << "i = " << i << " dimx = " << dimX
<< " + = " << i + dimX << " | " << v.size()
<< std::endl;
v(i + dimX) /= factor;
}
return true;
}
else return false;
}
typedef Eigen::Ref<const vec> vecref;
// Return true if V is between MIN and MAX.
static bool within_bounds(const vecref v,
const vec& min, const vec& max)
......@@ -64,11 +76,13 @@ enum ci_kind
// Read a confidence interval on the output parameters from INPUT into V.
static void read_confidence_interval(std::istream& input,
vec& v, ci_kind kind,
vecref v, ci_kind kind,
unsigned int dimX,
unsigned int dimY,
const alta::arguments& args)
{
assert(v.size() == dimX + 3 * dimY);
for(int i=0; i<dimY; ++i)
{
double min_dt = 0.0, max_dt = 0.0;
......@@ -77,8 +91,8 @@ static void read_confidence_interval(std::istream& input,
{
input >> min_dt ;
input >> max_dt ;
min_dt = min_dt-v[dimX+i];
max_dt = max_dt-v[dimX+i];
min_dt = min_dt-v(dimX + i);
max_dt = max_dt-v(dimX + i);
}
else if(i == 0 && kind == SYMMETRICAL_CONFIDENCE_INTERVAL)
{
......@@ -97,18 +111,18 @@ static void read_confidence_interval(std::istream& input,
if(args.is_defined("dt-relative"))
{
v[dimX + dimY+i] = v[dimX + i] * (1.0 + min_dt) ;
v[dimX + 2*dimY+i] = v[dimX + i] * (1.0 + max_dt) ;
v(dimX + dimY+i) = v(dimX + i) * (1.0 + min_dt) ;
v(dimX + 2*dimY+i) = v(dimX + i) * (1.0 + max_dt) ;
}
else if(args.is_defined("dt-max"))
{
v[dimX + dimY+i] = v[dimX + i] + std::max(v[dimX + i] * min_dt, min_dt);
v[dimX + 2*dimY+i] = v[dimX + i] + std::max(v[dimX + i] * max_dt, max_dt);
v(dimX + dimY+i) = v(dimX + i) + std::max(v(dimX + i) * min_dt, min_dt);
v(dimX + 2*dimY+i) = v(dimX + i) + std::max(v(dimX + i) * max_dt, max_dt);
}
else
{
v[dimX + dimY+i] = v[dimX + i] + min_dt ;
v[dimX + 2*dimY+i] = v[dimX + i] + max_dt ;
v(dimX + dimY+i) = v(dimX + i) + min_dt ;
v(dimX + 2*dimY+i) = v(dimX + i) + max_dt ;
}
// You can enforce the vertical segment to stay in the positive
......@@ -116,9 +130,9 @@ static void read_confidence_interval(std::istream& input,
// that the data point is also clamped to zero if negative.
if(args.is_defined("dt-positive"))
{
v[dimX + i] = std::max(v[dimX + i], 0.0);
v[dimX + dimY+i] = std::max(v[dimX + dimY+i], 0.0);
v[dimX + 2*dimY+i] = std::max(v[dimX + 2*dimY+i], 0.0);
v(dimX + i) = std::max(v(dimX + i), 0.0);
v(dimX + dimY+i) = std::max(v(dimX + dimY+i), 0.0);
v(dimX + 2*dimY+i) = std::max(v(dimX + 2*dimY+i), 0.0);
}
#ifdef DEBUG
......@@ -147,6 +161,7 @@ alta::data* alta::load_data_from_text(std::istream& input,
params::output out_param = params::parse_output(header.get_string("PARAM_OUT", "UNKNOWN_OUTPUT"));
std::pair<int, int> dim = header.get_pair<int>("DIM");
size_t row_count = dim.first + 3 * dim.second;
min = args.get_vec("min", dim.first, -std::numeric_limits<float>::max()) ;
max = args.get_vec("max", dim.first, std::numeric_limits<float>::max()) ;
......@@ -165,8 +180,7 @@ alta::data* alta::load_data_from_text(std::istream& input,
vs_value == 2 ? ASYMMETRICAL_CONFIDENCE_INTERVAL
: (vs_value == 1 ? SYMMETRICAL_CONFIDENCE_INTERVAL
: NO_CONFIDENCE_INTERVAL);
std::vector<vec> content;
std::vector<double> content;
// Now read the body.
while(input.good())
......@@ -182,14 +196,24 @@ alta::data* alta::load_data_from_text(std::istream& input,
}
else
{
auto start = content.size();
// 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)
for(int i=0; i < dim.first + dim.second; ++i)
{
linestream >> v[i] ;
double item;
linestream >> item;
content.push_back(item);
}
// Save room for the confidence interval.
for (int i = 0; i < 2 * dim.second; i++)
content.push_back(0.);
// If data is not in the interval of fit
// std::cout << " start = " << start << " rows = " << row_count
// << " size = " << content.size() << "\n";
Map<VectorXd> v(&content[start], row_count);
if (!(within_bounds(v.segment(0, dim.first), min, max)
&& within_bounds(v.segment(dim.first, dim.second),
ymin, ymax)))
......@@ -197,15 +221,14 @@ alta::data* alta::load_data_from_text(std::istream& input,
if(args.is_defined("data-correct-cosine"))
{
if (!cosine_correction(v, dim.first, dim.second, in_param))
if (!cosine_correction(v.segment(0, dim.first + dim.second),
dim.first, dim.second, in_param))
continue;
}
// Read the confidence interval data if available.
read_confidence_interval(linestream, v, kind,
dim.first, dim.second, args);
content.push_back(std::move(v));
}
}
......@@ -215,8 +238,15 @@ alta::data* alta::load_data_from_text(std::istream& input,
<< " -> R^" << dim.second << std::endl ;
std::cout << "<<INFO>> " << content.size() << " elements to fit" << std::endl ;
double *raw_content = new double[content.size()];
memcpy(raw_content, content.data(), content.size() * sizeof(double));
parameters param(dim.first, dim.second, in_param, out_param);
data* result = new vertical_segment(param, std::move(content));
size_t element_count = content.size() / row_count;
data* result = new vertical_segment(param, element_count,
std::shared_ptr<double>(raw_content,
delete_array));
if(args.is_defined("data-correct-cosine"))
result->save("/tmp/data-corrected.dat");
......@@ -276,6 +306,7 @@ void alta::save_data_as_binary(std::ostream &out, const alta::data& data)
for(int i=0; i < data.size(); ++i)
{
// FIXME: Currently we are not saving the confidence interval here.
vec sample = data.get(i);
const double *numbers = sample.data();
......@@ -311,26 +342,33 @@ alta::data* alta::load_data_from_binary(std::istream& in, const alta::arguments&
}
// TODO: Arrange to use mmap and make it zero-alloc and zero-copy.
std::vector<vec> content(sample_count);
for (int i = 0; i < sample_count; i++)
size_t rows = dim.first + 3 * dim.second;
double *content = new double[sample_count * rows];
for (std::streamsize i = 0; i < sample_count; i++)
{
vec row = vec::Zero(dim.first + dim.second);
std::streamsize expected = row.size() * sizeof(double);
double* start = &content[i * rows];
std::streamsize byte_count =
(dim.first + dim.second) * sizeof(*content);
for (std::streamsize total = 0;
total < expected && !in.eof();
for (std::streamsize total = 0;
total < byte_count && !in.eof();
total += in.gcount())
{
char* ptr = (char*)row.data();
in.read(ptr + total, expected - total);
}
content[i] = row;
{
in.read((char *) start + total, byte_count - total);
}
// XXX: Fill in the confidence interval values with zeros since we
// don't have those values.
content[i * rows + dim.first + dim.second] = 0.;
content[i * rows + dim.first + dim.second + 1] = 0.;
}
parameters param(dim.first, dim.second,
params::parse_input(header["PARAM_IN"]),
params::parse_output(header["PARAM_OUT"]));
return new alta::vertical_segment(param, std::move(content));
return new alta::vertical_segment(param, sample_count,
std::shared_ptr<double>(content,
delete_array));
}
......@@ -18,131 +18,138 @@
#include <algorithm>
#include <cmath>
#include <cassert>
#include <cstring>
using namespace alta;
using namespace Eigen;
//#define RELATIVE_ERROR
// Note: For some reason returning an rvalue here doesn't work, so let's hope
// RVO comes into play.
static vec data_min(unsigned int size, const std::vector<vec>& data)
static vec data_min(Ref<MatrixXd> data)
{
vec min(size);
vec min(data.rows());
for(int k = 0; k < size; ++k)
for(int k = 0; k < data.rows(); ++k)
{
min[k] = std::numeric_limits<double>::max();
}
for (auto&& item: data)
for(int i = 0; i < data.cols(); i++)
{
for (int k = 0; k < size; ++k)
auto col = data.col(i);
for (int k = 0; k < data.rows(); ++k)
{
min[k] = std::min(min[k], item[k]);
min[k] = std::min(min[k], col[k]);
}
}
return min;
}
static vec data_max(unsigned int size, const std::vector<vec>& data)
static vec data_max(Ref<MatrixXd> data)
{
vec max(size);
vec max(data.rows());
for(int k = 0; k < size; ++k)
for(int k = 0; k < data.rows(); ++k)
{
max[k] = -std::numeric_limits<double>::max();
}
for (auto&& item: data)
for(int i = 0; i < data.cols(); i++)
{
for (int k = 0; k < size; ++k)
auto col = data.col(i);
for (int k = 0; k < data.rows(); ++k)
{
max[k] = std::max(max[k], item[k]);
max[k] = std::max(max[k], col[k]);
}
}
return max;
}
// Return a matrix view of PTR showing only the 'dimX' first rows of that
// matrix.
static Ref<MatrixXd>
x_view(double *ptr, size_t cols, const parameters& params)
{
return Map<MatrixXd, 0, OuterStride<> >(ptr, params.dimX(), cols,
OuterStride<>(params.dimX()
+ 3 * params.dimY()));
}
vertical_segment::vertical_segment(const parameters& params,
std::vector<vec>&& input_data)
: data(params, input_data.size(),
data_min(params.dimX(), input_data),
data_max(params.dimX(), input_data)),
size_t size,
std::shared_ptr<double> input_data)
: data(params, size,
data_min(x_view(input_data.get(), size, params)),
data_max(x_view(input_data.get(), size, params))),
_data(input_data), _is_absolute(true), _dt(0.1)
{
}
vertical_segment::vertical_segment(const parameters& params, unsigned int size):
data(params, size), _is_absolute(true), _dt(0.1)
vertical_segment::vertical_segment(const parameters& params, unsigned int rows):
data(params, rows), _is_absolute(true), _dt(0.1)
{
initializeToZero(size);
_data =
std::shared_ptr<double>(new double[rows * column_number()]);
memset(_data.get(), '\0', sizeof(double) * rows * column_number());
}
void
vertical_segment::initializeToZero( unsigned int number_of_data_elements )
{
_data.clear();
unsigned int const size_of_one_element = _parameters.dimX() + 3*_parameters.dimY();
for( unsigned int i=0; i < number_of_data_elements; i++)
{
vec initial_element = vec::Zero( size_of_one_element );
_data.push_back( initial_element );
}
}
void vertical_segment::get(int i, vec& x, vec& yl, vec& yu) const
{
auto matrix = matrix_view();
#ifdef DEBUG
assert(i >= 0 && i < _data.size());
assert(i >= 0 && i < matrix.size());
#endif
x.resize(_parameters.dimX()); yl.resize(_parameters.dimY()) ; yu.resize(_parameters.dimY()) ;
for(int j=0; j<_parameters.dimX(); ++j)
{
x[j] = _data[i][j];
x[j] = matrix(i, j);
}
for(int j=0; j<_parameters.dimY(); ++j)
{
yl[j] = _data[i][_parameters.dimX() + 1*_parameters.dimY() + j];
yu[j] = _data[i][_parameters.dimX() + 2*_parameters.dimY() + j];
yl[j] = matrix(i, _parameters.dimX() + 1*_parameters.dimY() + j);
yu[j] = matrix(i, _parameters.dimX() + 2*_parameters.dimY() + j);
}
}
void vertical_segment::get(int i, vec& yl, vec& yu) const
{
yl.resize(_parameters.dimY()) ; yu.resize(_parameters.dimY()) ;
for(int j=0; j<_parameters.dimY(); ++j)
{
yl[j] = _data[i][_parameters.dimX() + _parameters.dimY() + j] ;
yu[j] = _data[i][_parameters.dimX() + 2*_parameters.dimY() + j] ;
}
auto matrix = matrix_view();
yl.resize(_parameters.dimY()) ; yu.resize(_parameters.dimY()) ;
for(int j=0; j<_parameters.dimY(); ++j)
{
yl[j] = matrix(i, _parameters.dimX() + _parameters.dimY() + j);
yu[j] = matrix(i, _parameters.dimX() + 2*_parameters.dimY() + j);
}
}
vec vertical_segment::get(int i) const
vec vertical_segment::get(int i) const
{
//SLOW !!!!! and useless
// call _data[i]
const int n = _parameters.dimX() + _parameters.dimY();
vec res = _data[i].head(n);
return res ;
// Omit the confidence interval data.
auto relevant_rows = _parameters.dimX() + _parameters.dimY();
auto matrix =
Map<MatrixXd, 0, OuterStride<> >(_data.get(), relevant_rows, size(),
OuterStride<>(column_number()));
return matrix.col(i);
}
void vertical_segment::set(int i, const vec& x)
{
// Check if the input data 'x' has the size of a vertical segment (i.e. dimX+3*dimY),
// if it only has the size of a single value, then create the segment.
if(x.size() == _parameters.dimX() + 3*_parameters.dimY()) {
_data[i] = x;
} else if(x.size() == _parameters.dimX() + _parameters.dimY()) {
_data[i] = vs(x);
if(x.size() == column_number()
|| x.size() == _parameters.dimX() + _parameters.dimY())
{
auto matrix = matrix_view();
auto row = matrix.row(i);
row.head(x.size()) = x;
} else {
std::cerr << "<<ERROR>> Passing an incorrect element to vertical_segment::set" << std::endl;
throw;
......
......@@ -81,7 +81,8 @@ class vertical_segment : public data
public: // methods
vertical_segment(const parameters& params,
std::vector<vec>&& data);
size_t size,
std::shared_ptr<double> data);
vertical_segment(const parameters& params, unsigned int size)
ALTA_DEPRECATED;
......@@ -106,11 +107,20 @@ class vertical_segment : public data
private: // method
protected: // method
//! \brief Return the number of columns in each row.
size_t column_number() const
{
return _parameters.dimX() + 3 * _parameters.dimY();
}
// Pre-allocate 'number_of_data_elements' elements for this data
// object. Note, the input and output dimension needs to be specified.
void initializeToZero( unsigned int number_of_data_elements );
// Return a matrix view of this data.
Eigen::Map<Eigen::MatrixXd> matrix_view() const
{
return Eigen::Map<Eigen::MatrixXd>(_data.get(), size(),
column_number());
}
protected: // method
//! \brief From a correct input configuration 'x' with size
//! dimX()+dimY(), generate a vertical ! segment satisfying this object's
......@@ -119,9 +129,8 @@ class vertical_segment : public data
protected: // data
// Store for each point of data, the upper
// and lower value
std::vector<vec> _data ;
// Store for each point of data, the upper and lower value.
std::shared_ptr<double> _data;
// Store the different arguments for the vertical segment: is it using
// relative or absolute intervals? What is the dt used ?
......
......@@ -199,16 +199,12 @@ class BrdfGrid : public vertical_segment {
// Preallocate the grid data
if(preallocate) {
initializeToZero(N);
// Set the abscissa data
vec x(parametrization().dimX() + parametrization().dimY());
for(int n=0; n<N; ++n) {
get_abscissa(n, x);
set(n, x);
}
} else {
_data.clear();
}
parameters p(nX, nY, in_param, out_param);
......
......@@ -51,8 +51,9 @@ class ASTM : public vertical_segment
{
public: //methods
ASTM(const parameters& params, std::vector<vec>&& input_data)
: vertical_segment(params, std::move(input_data))
ASTM(const parameters& params, size_t size,
std::shared_ptr<double> input_data)
: vertical_segment(params, size, input_data)
{ }
ASTM(const parameters& params, size_t size)
......@@ -151,12 +152,13 @@ ALTA_DLL_EXPORT data* load_data(std::istream& input, const arguments& args)
int size = header.get_int("NUM_POINTS", 0);
// Size of the data
std::vector<vec> data(size);
const int n = params.dimX() + params.dimY();
int i = 0;
size_t n = params.dimX() + params.dimY();
double* data = new double[size * n];
for (size_t i = 0; i < size * n; i += n)
{
assert(input.good());
while(input.good())
{
std::getline(input, line);
if(line.size() == 0 || line.rfind(',') == std::string::npos)
......@@ -167,13 +169,10 @@ ALTA_DLL_EXPORT data* load_data(std::istream& input, const arguments& args)
// Create a stream from the line data and extract it as
// a vec of dim parametrization().dimX() + parametrization().dimY().
std::stringstream stream(line);
vec x(n);
for(int i=0; i<n; ++i) {
stream >> x[i];
for(int j = 0; j < n; ++j) {
stream >> data[i + j];
}
data[i++] = x;
}
return new ASTM(params, std::move(data));
return new ASTM(params, n, std::shared_ptr<double>(data));
}
......@@ -59,27 +59,30 @@ bool rational_fitter_parallel::fit_data(const ptr<data>& dat, ptr<function>& fit
std::cerr << "<<WARNING>> automatic convertion of the data object to vertical_segment," << std::endl;
std::cerr << "<<WARNING>> we advise you to perform convertion with a separate command." << std::endl;
std::vector<vec> content(dat->size());
size_t elem_size =
dat->parametrization().dimX() + 3*dat->parametrization().dimY();
double* content = new double[dat->size() * elem_size];
for(int i=0; i<dat->size(); ++i)
{
const vec x = dat->get(i);
vec y(dat->parametrization().dimX() + 3*dat->parametrization().dimY());
for(int k=0; k<x.size() ; ++k) { y[k] = x[k]; }
for(int k=0; k<x.size(); ++k) {
content[i + k] = x[k];
}
for(int k=0; k<dat->parametrization().dimY(); ++k) {
y[k + dat->parametrization().dimX() + dat->parametrization().dimY()] =
content[i + k + dat->parametrization().dimX() + dat->parametrization().dimY()] =
(1.0 - args.get_float("dt", 0.1)) * x[k + dat->parametrization().dimX()];
}
for(int k=0; k<dat->parametrization().dimY(); ++k) {
y[k + dat->parametrization().dimX() + 2*dat->parametrization().dimY()] =
content[i + k + dat->parametrization().dimX() + 2*dat->parametrization().dimY()] =
(1.0 + args.get_float("dt", 0.1)) * x[k + dat->parametrization().dimX()];
}
content[i] = std::move(y);
}
ptr<vertical_segment> vs(new vertical_segment(dat->parametrization(),
std::move(content)));
dat->size(),
std::shared_ptr<double>(content)));
d = vs;
}
......
......@@ -257,28 +257,43 @@ static bool fit_data_with_args(ptr<fitter>& _fitter, const ptr<data>& _data,
*/
static ptr<data> data2data(const data* d_in, const parameters& target)
{
std::vector<vec> content(d_in->size());
for (auto i = 0; i < d_in->size(); ++i)
auto delete_array = [](double* array)
{
vec temp(target.dimX() + target.dimY());
delete[] array;
};
// For each sample we store the X and Y values, followed by the
// confidence interval on Y.
size_t sample_size = target.dimX() + 3 * target.dimY();
double* content = new double[d_in->size() * sample_size];
for (auto sample = 0; sample < d_in->size(); sample++)
{
// Copy the input vector
vec x = d_in->get(i);
vec x = d_in->get(sample);
params::convert(&x[0],
d_in->parametrization().input_parametrization(),
target.input_parametrization(),
&temp[0]);
&content[sample * sample_size]);
params::convert(&x[d_in->parametrization().dimX()],
d_in->parametrization().output_parametrization(),
d_in->parametrization().dimY(),
target.output_parametrization(),
target.dimY(),
&temp[target.dimX()]);
content[i] = std::move(temp);
&content[sample * sample_size + target.dimX()]);
// Set the confidence interval on Y to zero.
for (auto i = 0; i < 2 * target.dimY(); i++)
{
content[sample * sample_size + target.dimX() + target.dimY()
+ i] = 0.;
}
}
data* result = new vertical_segment(target, std::move(content));
data* result = new vertical_segment(target, d_in->size(),
std::shared_ptr<double>(content,
delete_array));
return ptr<data>(result);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment