function.h 14.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/* ALTA --- Analysis of Bidirectional Reflectance Distribution Functions

   Copyright (C) 2013 CNRS
   Copyright (C) 2013, 2014 Inria

   This file is part of ALTA.

   This Source Code Form is subject to the terms of the Mozilla Public
   License, v. 2.0.  If a copy of the MPL was not distributed with this
   file, You can obtain one at http://mozilla.org/MPL/2.0/.  */

12 13
#pragma once

14 15
#include <functional>
#include <string>
16
#include <fstream>
17

18
#include "common.h"
19
#include "args.h"
20
#include "params.h"
21
#include "data.h"
22

Laurent Belcour's avatar
Laurent Belcour committed
23
/*! \brief A representation of an analytical function.
24
 *  \ingroup core
Laurent Belcour's avatar
Laurent Belcour committed
25
 *
26
 *  \details
27
 *  function are functors with a domain of definition specified by a vector 
Laurent Belcour's avatar
Laurent Belcour committed
28
 *  interval \f$[\vec{min} .. \vec{max}]\f$ where \f$\vec{min}\f$ and 
29 30 31 32
 *  \f$\vec{max}\f$ have the size of the input domain.
 *
 *  Any function used by the fitting algorithm should overload publicly this
 *  interface.
Laurent Belcour's avatar
Laurent Belcour committed
33
 */
34
class function : public parametrized
35 36 37
{
	public: // methods

38 39 40 41 42
		/* NEEDED FUNCTIONS */

		//! \brief Destructor function needed when using shared_ptr
		virtual ~function() {}

43 44
		/* INTERFACE */

45
		// Overload the function operator
46
		virtual vec operator()(const vec& x) const { return this->value(x); } ;
Laurent Belcour's avatar
Laurent Belcour committed
47
		virtual vec value(const vec& x) const = 0 ;
48

49 50 51 52
		//! \brief Provide a first rough fit of the function. 
		//!
		//! \details
		//! Can be used to set the diffuse component of the function for
53
		//! example. The default behaviour is to load a function file.
54
		virtual void bootstrap(const ptr<data>, const arguments& args);
55

56 57 58 59
		/* IMPORT/EXPORT FUNCTIONS */

		//! Load function specific files
		virtual bool load(std::istream& in) = 0 ;
60

61 62
		//! \brief Save the current function to a specific file type, args 
		//! can be used to differenciate the type of export.
63 64
		//! \see rational_function.cpp for an example
		virtual void save(const std::string& filename, const arguments& args) const;
65

66 67 68 69
		//! \brief save the header of the output function file. The header 
		//! should store general information about the fit such as the 
		//! command line used the dimension of the fit. L2 and L_inf distance
		//! could be added here.
70
		virtual void save_header(std::ostream& out, const arguments& args) const ;
71

72 73 74 75
		//! \brief save function specific data. This has no use for ALTA 
		//! exportbut allows to factorize the code in the C++ or matlab 
		//! export by defining function calls that are common to all the 
		//! plugins.
76
		virtual void save_body(std::ostream& out, const arguments& args) const ;
77

78
		//! \brief save object specific information. For an ALTA export the
79 80
		//! coefficients will be exported. For a C++ or matlab export, the 
		//! call to the associated function will be done.
81
		virtual void save_call(std::ostream& out, const arguments& args) const ;
82 83


84
		/* METRIC FUNCTIONS */
85

86 87 88 89 90
		//! \brief L2 norm to data.
		//! \note This distance is only valid with respect to the data sampling.
		//! If the measurement points are not uniformly distributed, then the
		//! metric does not represent the real difference integrated over the
		//! hemisphere.
91
		double L2_distance(const ptr<data>& d) const ;
92 93

		//! \brief Linf norm to data.
94 95 96 97
		//! \note This distance is only valid with respect to the data sampling.
		//! If the measurement points are not uniformly distributed, then the
		//! metric does not represent the real difference integrated over the
		//! hemisphere.
98
		double Linf_distance(const ptr<data>& d) const ;
99

100 101
};

102
/*! \brief Non-linear function interface
103
 *  \ingroup core
104
 *
105
 * \details
106 107 108 109 110
 * Provide a way to obtain the dérivative of the function with respect to its
 * parameters. If the function \f$f(\vec{x})\f$ is defined for a vector of
 * parameters \f$\vec{a}\f$, the resulting vector is \f$df_i = {df \over 
 * da_i}\f$. 
 *
111
 * \note It is not necessary to have an analytical formulation
112 113
 * of the derivative but at least a numerical evaluation of it has to be
 * provided.
114
 */
115 116 117 118
class nonlinear_function: public function
{
	public: // methods

119 120 121 122 123 124
		//! \brief Provide a first rough fit of the function.
		//!
		//! \details
		//! The nonllinear_function overload the function bootstrap call to
		//! allows for loading the parameters vector directly from the command
		//! line: --bootstrap [p1, p2, ..., pn]
125
		virtual void bootstrap(const ptr<data>, const arguments& args);
126

127 128 129
		//! Number of parameters to this non-linear function
		virtual int nbParameters() const = 0;

130
		//! Get the vector of parameters for the function
131
		virtual vec parameters() const = 0;
132 133

		//! Update the vector of parameters for the function
134 135
		virtual void setParameters(const vec& p) = 0;

136 137 138 139 140 141 142 143 144 145
		//! \brief get the maximum value for all the parameters in a vector
		//! format. The maximum vector and the parameter vector have the same
		//! indexing.
		virtual vec getParametersMax() const;

		//! \brief get the minimum value for all the parameters in a vector
		//! format. The minimum vector and the parameter vector have the same
		//! indexing.
		virtual vec getParametersMin() const;

Laurent Belcour's avatar
Laurent Belcour committed
146
		//! \brief Obtain the derivatives of the function with respect to the
147
		//! parameters. 
Laurent Belcour's avatar
Laurent Belcour committed
148 149 150 151 152 153 154 155
		//!
		//! \details
		//! The \a x input of this function is the position in the 
		//! input space and  has size dimX(), the resulting vector has the 
		//! size of the parameters times the size of the output domain.
		//!
		//! The result vector should be orderer as res[i + dimY()*j], output
		//! dimension first, then parameters.
156
		virtual vec parametersJacobian(const vec& x) const = 0;
157 158

		//! \brief default non_linear import. Parse the parameters in order.
159
		virtual bool load(std::istream& in);
160

Laurent Belcour's avatar
Laurent Belcour committed
161 162
		//! \brief default non_linear export. It will dump the parameters in 
		//! order but won't assign names for the function nor parameters.
163
		virtual void save_call(std::ostream& out, const arguments& args) const;
164
};
165

166 167 168 169
/*! \brief A compound (sum) of multiple nonlinear functions. This allows to
 *  perform the fit of multiple lobes at once.
 *  \ingroup core
 */
170
class compound_function: public nonlinear_function
Laurent Belcour's avatar
Laurent Belcour committed
171 172
{
	public: // methods
173

Laurent Belcour's avatar
Laurent Belcour committed
174
		// Overload the function operator
175 176
		virtual vec operator()(const vec& x) const;
		virtual vec value(const vec& x) const;
Laurent Belcour's avatar
Laurent Belcour committed
177

178
		//! Provide a vector like interface
179 180 181
		//! This function allows to put a new nonlinear function \a f in the 
		//! compound object. This function will be processed for nonlinear
		//! optimisation only if \a fixed equals true.
182
		virtual void push_back(nonlinear_function* f, const arguments& f_args);
183 184

		//! \brief Access to the i-th function of the compound
185
		nonlinear_function* operator[](int i) const;
186 187

		//! \brief Access to the number of elements in the compound object.
188
		unsigned int size() const;
189

Laurent Belcour's avatar
Laurent Belcour committed
190
		//! Load function specific files
191
		virtual bool load(std::istream& in);
192

Laurent Belcour's avatar
Laurent Belcour committed
193
		//! \brief Provide a first rough fit of the function. 
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
		//! For compound object, you can define the first guess using the
		//! either the global function or using the individual command per
		//! function. <br />
		//!
		//! <u>Examples:</u><br />
		//! \verbatim
		//! --func [libfunc1.so, libfunc2.so] --bootstrap first_guess.brdf
		//! \endverbatim
		//! Will load the file <em>first_guess.brdf</em> as the initial value
		//! <br />
		//! \verbatim
		//! --func [libfunc1.so --boostrap [val1, val2], libfunc2.so --bootstrap first_guess1.brdf]
		//! \endverbatim
		//! Will load the vector of parameters <em>[val1, val2]</em> for the
		//! first function and the file <em>first_guess1.brdf</em> for the
		//! second one. <br />
		//!
		//! <u>Local/Global policy:</u></br />
		//! Local bootstrap can not overload the global bootstrap.
213
		virtual void bootstrap(const ::ptr<data> d, const arguments& args);
214

Laurent Belcour's avatar
Laurent Belcour committed
215
		//! Set the dimension of the input space of the function
216 217
		virtual void setDimX(int nX);

Laurent Belcour's avatar
Laurent Belcour committed
218
		//! Set the dimension of the output space of the function
219
		virtual void setDimY(int nY);
Laurent Belcour's avatar
Laurent Belcour committed
220 221

		// Acces to the domain of definition of the function
222 223
		virtual void setMin(const vec& min);
		virtual void setMax(const vec& max);
Laurent Belcour's avatar
Laurent Belcour committed
224 225

		//! Number of parameters to this non-linear function
226
		virtual int nbParameters() const;
Laurent Belcour's avatar
Laurent Belcour committed
227 228

		//! Get the vector of parameters for the function
229
		virtual vec parameters() const;
230 231
		
		//! Get the vector of min parameters for the function
232
		virtual vec getParametersMin() const;
233 234
		
		//! Get the vector of min parameters for the function
235
		virtual vec getParametersMax() const;
Laurent Belcour's avatar
Laurent Belcour committed
236 237

		//! Update the vector of parameters for the function
238
		virtual void setParameters(const vec& p);
Laurent Belcour's avatar
Laurent Belcour committed
239 240 241 242 243 244 245 246 247 248

		//! \brief Obtain the derivatives of the function with respect to the 
		//! parameters. 
		//
		// The x input of this function is the position in the input space and 
		// has size dimX(), the resulting vector has the size of the parameters
		// times the size of the output domain.
		//
		// The result vector should be orderer as res[i + dimY()*j], output
		// dimension first, then parameters.
249
		virtual vec parametersJacobian(const vec& x) const;
250

Laurent Belcour's avatar
Laurent Belcour committed
251 252
		//! \brief can set the input parametrization of a non-parametrized
		//! object. Print an error if it is already defined.
253
		virtual void setParametrization(params::input new_param);
254

Laurent Belcour's avatar
Laurent Belcour committed
255 256 257
		//! \brief can set the output parametrization of a non-parametrized
		//! function. Throw an exception if it tries to erase a previously
		//! defined one.
258
		virtual void setParametrization(params::output new_param);
Laurent Belcour's avatar
Laurent Belcour committed
259

260 261 262
		//! \brief save function specific data. This has no use for ALTA export
		//! but allows to factorize the code in the C++ or matlab export by
		//! defining function calls that are common to all the plugins.
263
		virtual void save_body(std::ostream& out, const arguments& args) const;
264 265 266 267

		//! \brief save object specific information. For an ALTA export the
		//! coefficients will be exported. For a C++ or matlab export, the call
		//! to the associated function will be done.
268
		virtual void save_call(std::ostream& out, const arguments& args) const;
269

270 271
	protected:
		std::vector<nonlinear_function*> fs;
272
		std::vector<arguments> fs_args;
273
		std::vector<bool> is_fixed;
274

Laurent Belcour's avatar
Laurent Belcour committed
275 276
};

277 278 279 280 281 282 283 284 285 286 287 288 289
/*! \brief A product of nonlinear functions. This class aims to simplify the
 *  fitting and progressive fitting of Fresnel effects that can be separated
 *  from the main lobe.
 *  \ingroup core
 */
class product_function : public nonlinear_function
{
	public: // methods

		//! \brief Constructor of the product function, affect the two function
		//! to already created nonlinear_function objects.
		product_function(nonlinear_function* g1, nonlinear_function* g2);

290

291 292 293 294 295 296 297 298 299
		/* ACCESS TO INDIVIDUAL ELEMENTS */

		//! \brief Access to the first member of the product
		nonlinear_function* first() const;

		//! \biref Access to the second member of the product
		nonlinear_function* second() const;


300 301
		/* EVALUATION FUNCTIONS */

302 303 304 305 306 307 308
		//! \brief Overload the function operator, directly call the value function.
		virtual vec operator()(const vec& x) const;

		//! \brief Return the product between the value of function f1 and function
		//! f2. The input parameter x should be in the parametrization of f1. This
		//! function will do the conversion before getting f2's value.
		virtual vec value(const vec& x) const;
309 310 311


		/* IMPORT/EXPORT FUNCTIONS */
312 313 314 315 316
		
		//! \brief Load the two functions in order f1, then f2. If one of the 
		//! function cannot be loaded, this function will continue. It will only
		//! return false if both functions cannot be loaded.
		virtual bool load(std::istream& in);
317 318 319 320 321 322 323 324 325 326

		//! \brief save function specific data. This has no use for ALTA export
		//! but allows to factorize the code in the C++ or matlab export by
		//! defining function calls that are common to all the plugins.
		virtual void save_body(std::ostream& out, const arguments& args) const;

		//! \brief save object specific information. For an ALTA export the
		//! coefficients will be exported. For a C++ or matlab export, the call
		//! to the associated function will be done.
		virtual void save_call(std::ostream& out, const arguments& args) const;
327
		
328

329
		//! \brief Provide a first rough fit of the function. 
330
		virtual void bootstrap(const ptr<data> d, const arguments& args);
331 332 333 334 335 336 337 338

		// Set the dimension of the input/output space of the function
		virtual void setDimX(int nX);
		virtual void setDimY(int nY);

		// Acces to the domain of definition of the function
		virtual void setMin(const vec& min);
		virtual void setMax(const vec& max);
Laurent Belcour's avatar
Laurent Belcour committed
339
		
340
		//! Provide the output parametrization of the object.
Laurent Belcour's avatar
Laurent Belcour committed
341
		virtual params::output output_parametrization() const;
342 343 344 345 346
		
		//! Set the input/output parametrization of a non-parametrized
		//! object. Print an error if it is already defined.
		virtual void setParametrization(params::input  new_param);
		virtual void setParametrization(params::output new_param);
347 348 349 350 351 352 353

		//! \brief Number of parameters to this non-linear function
		virtual int nbParameters() const;
		
		//! \biref Get the vector of parameters for the function
		virtual vec parameters() const;

Laurent Belcour's avatar
Laurent Belcour committed
354 355 356
		//! Update the vector of parameters for the function
		virtual void setParameters(const vec& p);

357 358 359 360
		// Get the vector of min/max parameters for the function
		virtual vec getParametersMax() const;
		virtual vec getParametersMin() const;

Laurent Belcour's avatar
Laurent Belcour committed
361 362 363 364
		//! \brief Obtain the derivatives of the function with respect to the 
		//! parameters.
		virtual vec parametersJacobian(const vec& x) const;

365 366 367 368 369 370
	private: // data

		// Function composing the product
		nonlinear_function *f1, *f2;
};

371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
class cosine_function : public nonlinear_function
{
	public:
		// Set the input parametrization to CARTESIAN to reduce the number
		// of transformations in a compound object.
		cosine_function()
		{
			setParametrization(params::CARTESIAN);
			setDimX(6);
		}

		// Overload the function operator
		virtual vec operator()(const vec& x) const 
		{
			return value(x);
		}
		virtual vec value(const vec& x) const
		{
			vec res(dimY());
			for(int i=0; i<dimY(); ++i) { res[i] = ((x[2] > 0.0) ? x[2] : 0.0) * ((x[5] > 0.0) ? x[5] : 0.0); }
			return res;
		}

		//! \brief Number of parameters to this non-linear function
		virtual int nbParameters() const
		{
			return 0;
		}

		//! Get the vector of parameters for the function
		vec parameters() const 
		{
			vec res(1);
			return res;
		}

		//! Update the vector of parameters for the function
		void setParameters(const vec&) 
		{
		}

		//! Obtain the derivatives of the function with respect to the 
		//! parameters. 
		vec parametersJacobian(const vec&) const 
		{
			vec jac(1);
			return jac;
		}
};