src/opt/GOptimizerPar.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *                GOptimizerPar.cpp - Optimizer parameter class            *
00003  * ----------------------------------------------------------------------- *
00004  *  copyright (C) 2013-2015 by Juergen Knoedlseder                         *
00005  * ----------------------------------------------------------------------- *
00006  *                                                                         *
00007  *  This program is free software: you can redistribute it and/or modify   *
00008  *  it under the terms of the GNU General Public License as published by   *
00009  *  the Free Software Foundation, either version 3 of the License, or      *
00010  *  (at your option) any later version.                                    *
00011  *                                                                         *
00012  *  This program is distributed in the hope that it will be useful,        *
00013  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
00014  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
00015  *  GNU General Public License for more details.                           *
00016  *                                                                         *
00017  *  You should have received a copy of the GNU General Public License      *
00018  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.  *
00019  *                                                                         *
00020  ***************************************************************************/
00021 /**
00022  * @file GOptimizerPar.cpp
00023  * @brief Optimizer parameter class implementation
00024  * @author Juergen Knoedlseder
00025  */
00026 
00027 /* __ Includes ___________________________________________________________ */
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 #include "GException.hpp"
00032 #include "GOptimizerPar.hpp"
00033 #include "GTools.hpp"
00034 
00035 /* __ Method name definitions ____________________________________________ */
00036 #define G_CONSTRUCT     "GOptimizerPar::GOptimizerPar(std::string&, double&,"\
00037                                                                   " double&)"
00038 #define G_FACTOR_VALUE                 "GOptimizerPar::factor_value(double&)"
00039 #define G_FACTOR_MIN                     "GOptimizerPar::factor_min(double&)"
00040 #define G_FACTOR_MAX                     "GOptimizerPar::factor_max(double&)"
00041 #define G_SCALE                               "GOptimizerPar::scale(double&)"
00042 
00043 /* __ Macros _____________________________________________________________ */
00044 
00045 /* __ Coding definitions _________________________________________________ */
00046 
00047 /* __ Debug definitions __________________________________________________ */
00048 
00049 
00050 /*==========================================================================
00051  =                                                                         =
00052  =                         Constructors/destructors                        =
00053  =                                                                         =
00054  ==========================================================================*/
00055 
00056 /***********************************************************************//**
00057  * @brief Void constructor
00058  ***************************************************************************/
00059 GOptimizerPar::GOptimizerPar(void)
00060 {
00061     // Initialise members
00062     init_members();
00063   
00064     // Return
00065     return;
00066 }
00067 
00068 
00069 /***********************************************************************//**
00070  * @brief Parameter constructor
00071  *
00072  * @param[in] name Parameter name.
00073  * @param[in] value Parameter value.
00074  *
00075  * Constructs a parameter from a parameter @p name and a parameter @p value.
00076  *
00077  * The parameter is auto-scaled, which for a @p value that differs from zero
00078  * sets the scale factor to @p value and the @p factor_value to unity. For a
00079  * @p value of zero, the scale factor will be set to unity and the 
00080  * @p factor_value will be set to @p value.
00081  ***************************************************************************/
00082 GOptimizerPar::GOptimizerPar(const std::string& name, const double& value)
00083 {
00084     // Initialise members
00085     init_members();
00086 
00087     // Set name attribute
00088     m_name = name;
00089 
00090     // Set auto-scaled factor and scale attributes
00091     if (value != 0.0) {
00092         m_factor_value = 1.0;
00093         m_scale        = value;
00094     }
00095     else {
00096         m_factor_value = value;
00097         m_scale        = 1.0;
00098     }
00099 
00100     // Return
00101     return;
00102 }
00103 
00104 
00105 /***********************************************************************//**
00106  * @brief Parameter constructor
00107  *
00108  * @param[in] name Parameter name.
00109  * @param[in] factor Parameter value factor.
00110  * @param[in] scale Parameter scaling (non-zero value).
00111  *
00112  * @exception GException::invalid_argument
00113  *            Sacle factor of 0 specified.
00114  *
00115  * Constructs a parameter from a parameter @p name, value @p factor
00116  * and @p scale factor. The @p scale factor needs to be a non-zero value.
00117  * If the @p scale factor is zero, an exception is thrown.
00118  ***************************************************************************/
00119 GOptimizerPar::GOptimizerPar(const std::string& name,
00120                              const double&      factor,
00121                              const double&      scale)
00122 {
00123     // Make sure that scale is not zero
00124     if (scale == 0.0) {
00125         std::string msg = "Specified a parameter scale factor of 0.\n"
00126                           "Parameters need a non-zero scale factor.";
00127         throw GException::invalid_argument(G_CONSTRUCT, msg);
00128     }
00129 
00130     // Initialise members
00131     init_members();
00132 
00133     // Set attributes
00134     m_name         = name;
00135     m_factor_value = factor;
00136     m_scale        = scale;
00137 
00138     // Return
00139     return;
00140 }
00141 
00142 
00143 /***********************************************************************//**
00144  * @brief Copy constructor
00145  *
00146  * @param[in] par Function parameter.
00147  ***************************************************************************/
00148 GOptimizerPar::GOptimizerPar(const GOptimizerPar& par)
00149 { 
00150     // Initialise members
00151     init_members();
00152 
00153     // Copy members
00154     copy_members(par);
00155 
00156     // Return
00157     return;
00158 }
00159 
00160 
00161 /***********************************************************************//**
00162  * @brief Destructor
00163  ***************************************************************************/
00164 GOptimizerPar::~GOptimizerPar(void)
00165 {
00166     // Free members
00167     free_members();
00168 
00169     // Return
00170     return;
00171 }
00172 
00173 
00174 /*==========================================================================
00175  =                                                                         =
00176  =                               Operators                                 =
00177  =                                                                         =
00178  ==========================================================================*/
00179 
00180 /***********************************************************************//**
00181  * @brief Assignment operator
00182  *
00183  * @param[in] par Function parameter.
00184  * @return Function parameter.
00185  ***************************************************************************/
00186 GOptimizerPar& GOptimizerPar::operator=(const GOptimizerPar& par)
00187 { 
00188     // Execute only if object is not identical
00189     if (this != &par) {
00190 
00191         // Free members
00192         free_members();
00193 
00194         // Initialise members
00195         init_members();
00196 
00197         // Copy members
00198         copy_members(par);
00199 
00200     } // endif: object was not identical
00201   
00202     // Return
00203     return *this;
00204 }
00205 
00206 
00207 /*==========================================================================
00208  =                                                                         =
00209  =                             Public methods                              =
00210  =                                                                         =
00211  ==========================================================================*/
00212 
00213 /***********************************************************************//**
00214  * @brief Clear parameter
00215  *
00216  * Resets parameter to a clean initial state.
00217  ***************************************************************************/
00218 void GOptimizerPar::clear(void)
00219 {
00220     // Free class members
00221     free_members();
00222 
00223     // Initialise members
00224     init_members();
00225 
00226     // Return
00227     return;
00228 }
00229 
00230 
00231 /***********************************************************************//**
00232  * @brief Clone parameter
00233  *
00234  * @return Pointer to deep copy of parameter.
00235  ***************************************************************************/
00236 GOptimizerPar* GOptimizerPar::clone(void) const
00237 {
00238     // Clone parameter
00239     return new GOptimizerPar(*this);
00240 }
00241 
00242 
00243 /***********************************************************************//**
00244  * @brief Set parameter value
00245  *
00246  * @param[in] value Parameter value.
00247  *
00248  * Sets the parameter value. The method stores the value factor which is
00249  * obtained by dividing the @p value by the scale factor.
00250  *
00251  * The method calls factor_value() for assigning the value factor, and this
00252  * method will verify that the value lies within the specified boundaries.
00253  ***************************************************************************/
00254 void GOptimizerPar::value(const double& value)
00255 {
00256     // Set value factor. The GOptimizerPar class makes sure that m_scale is
00257     // never 0, so no test is needed here
00258     factor_value(value / m_scale);
00259     
00260     // Return
00261     return;
00262 }
00263 
00264 
00265 /***********************************************************************//**
00266  * @brief Set parameter error
00267  *
00268  * @param[in] error Parameter error.
00269  *
00270  * Sets the parameter error. The method stores the error factor which is
00271  * obtained by dividing the @p error by the scale factor.
00272  ***************************************************************************/
00273 void GOptimizerPar::error(const double& error)
00274 {
00275     // Set error factor. The GOptimizerPar class makes sure that m_scale is
00276     // never 0, so no test is needed here
00277     factor_error(error / m_scale);
00278     
00279     // Return
00280     return;
00281 }
00282 
00283 
00284 /***********************************************************************//**
00285  * @brief Set parameter gradient
00286  *
00287  * @param[in] gradient Parameter gradient.
00288  *
00289  * Sets the parameter gradient. The method stores the gradient factor which
00290  * is obtained by multiplying @p gradient by the scale factor.
00291  ***************************************************************************/
00292 void GOptimizerPar::gradient(const double& gradient)
00293 {
00294     // Set gradient factor.
00295     factor_gradient(gradient * m_scale);
00296     
00297     // Return
00298     return;
00299 }
00300 
00301 
00302 /***********************************************************************//**
00303  * @brief Set minimum parameter boundary
00304  *
00305  * @param[in] min Parameter minimum.
00306  *
00307  * Sets the minimum parameter boundary. The method stores the minimum
00308  * boundary factor which is obtained by dividing @p min by the scale factor.
00309  ***************************************************************************/
00310 void GOptimizerPar::min(const double& min)
00311 {
00312     // Set minimum boundary factor. The GOptimizerPar class makes sure that
00313     // m_scale is never 0, so no test is needed here
00314     factor_min(min / m_scale);
00315     
00316     // Return
00317     return;
00318 }
00319 
00320 
00321 /***********************************************************************//**
00322  * @brief Set maximum parameter boundary
00323  *
00324  * @param[in] max Parameter maximum.
00325  *
00326  * Sets the maximum parameter boundary. The method stores the maximum
00327  * boundary factor which is obtained by dividing @p max by the scale factor.
00328  ***************************************************************************/
00329 void GOptimizerPar::max(const double& max)
00330 {
00331     // Set maximum boundary factor. The GOptimizerPar class makes sure that
00332     // m_scale is never 0, so no test is needed here
00333     factor_max(max / m_scale);
00334     
00335     // Return
00336     return;
00337 }
00338 
00339 
00340 /***********************************************************************//**
00341  * @brief Set minimum and maximum parameter boundaries
00342  *
00343  * @param[in] min Parameter minimum.
00344  * @param[in] max Parameter maximum.
00345  *
00346  * Sets the minimum and maximum parameter boundaries. The method calls the
00347  * min() and max() methods to set the boundaries.
00348  ***************************************************************************/
00349 void GOptimizerPar::range(const double& min, const double& max)
00350 {
00351     // Set minimum and maximum
00352     this->min(min);
00353     this->max(max);
00354     
00355     // Return
00356     return;
00357 }
00358 
00359 
00360 /***********************************************************************//**
00361  * @brief Set parameter value factor
00362  *
00363  * @param[in] value Value factor.
00364  *
00365  * @exception GException::invalid_argument
00366  *            Parameter @p value outside [min,max] boundaries.
00367  *
00368  * Sets the value factor of the parameter. The method makes sure that
00369  * none of the boundaries is violated. Otherwise, exceptions are thrown.
00370  ***************************************************************************/
00371 void GOptimizerPar::factor_value(const double& value)
00372 {
00373     // If there is a minimum boundary and if value is below this boundary
00374     // then throw an exception
00375     if (m_has_min && value < m_factor_min) {
00376         std::string msg = "Specified value factor "+gammalib::str(value)+
00377                           " is smaller than the minimum boundary "+
00378                           gammalib::str(m_factor_min)+".";
00379         throw GException::invalid_argument(G_FACTOR_VALUE, msg);
00380     }
00381 
00382     // If there is a maximum boundary and if value is above this boundary
00383     // then throw an exception
00384     if (m_has_max && value > m_factor_max) {
00385         std::string msg = "Specified value factor "+gammalib::str(value)+
00386                           " is larger than the maximum boundary "+
00387                           gammalib::str(m_factor_max)+".";
00388         throw GException::invalid_argument(G_FACTOR_VALUE, msg);
00389     }
00390 
00391     // Assign value
00392     m_factor_value = value;
00393     
00394     // Return
00395     return;
00396 }
00397 
00398 
00399 /***********************************************************************//**
00400  * @brief Set parameter minimum factor
00401  *
00402  * @param[in] min Minimum factor.
00403  *
00404  * @exception GException::invalid_argument
00405  *            Parameter @p min larger than value factor.
00406  *
00407  * Sets the minimum boundary factor of the parameter. The method makes
00408  * sure that the minimum is not larger than the actual value factor.
00409  * Otherwise, an exception is thrown.
00410  ***************************************************************************/
00411 void GOptimizerPar::factor_min(const double& min)
00412 {
00413     // Check if minimum is larger than value
00414     if (min > m_factor_value) {
00415         std::string msg = "Specified minimum factor "+gammalib::str(min)+
00416                           " is larger than the value factor "+
00417                           gammalib::str(m_factor_value)+".";
00418         throw GException::invalid_argument(G_FACTOR_VALUE, msg);
00419     }
00420 
00421     // Assign minimum factor
00422     m_factor_min = min;
00423     
00424     // Flag that minimum was set
00425     m_has_min = true;
00426     
00427     // Return
00428     return;
00429 }
00430 
00431 
00432 /***********************************************************************//**
00433  * @brief Set parameter maximum factor
00434  *
00435  * @param[in] max Maximum factor.
00436  *
00437  * @exception GException::invalid_argument
00438  *            Parameter @p max smaller than value factor.
00439  *
00440  * Sets the maximum boundary factor of the parameter. The method makes
00441  * sure that the maximum is not smaller than the actual value factor.
00442  * Otherwise, an exception is thrown.
00443  ***************************************************************************/
00444 void GOptimizerPar::factor_max(const double& max)
00445 {
00446     // Check if maximum is smaller than value
00447     if (max < m_factor_value) {
00448         std::string msg = "Specified maximum factor "+gammalib::str(max)+
00449                           " is smaller than the value factor "+
00450                           gammalib::str(m_factor_value)+".";
00451         throw GException::invalid_argument(G_FACTOR_VALUE, msg);
00452     }
00453 
00454     // Assign maximum
00455     m_factor_max = max;
00456     
00457     // Flag that maximum was set
00458     m_has_max = true;
00459     
00460     // Return
00461     return;
00462 }
00463 
00464 
00465 /***********************************************************************//**
00466  * @brief Set parameter minimum and maximum factors
00467  *
00468  * @param[in] min Minimum factor.
00469  * @param[in] max Maximum factor.
00470  *
00471  * Sets the minimum and maximum boundary factors. The method calls the
00472  * factor_min() and factor_max() methods which perform validity checking
00473  * of the arguments.
00474  ***************************************************************************/
00475 void GOptimizerPar::factor_range(const double& min, const double& max)
00476 {
00477     // Set minimum and maximum
00478     factor_min(min);
00479     factor_max(max);
00480     
00481     // Return
00482     return;
00483 }
00484 
00485 
00486 /***********************************************************************//**
00487  * @brief Set scale factor
00488  *
00489  * @param[in] scale Scale factor.
00490  *
00491  * @exception GException::invalid_argument
00492  *            Sacle factor of 0 specified.
00493  *
00494  * Sets the scale factor of the parameter. All parameter attributes are
00495  * rescaled accordingly.
00496  *
00497  * Special care is taken for value boundaries, that need swaping if the scale
00498  * factor changes its sign. In case of sign change the following logic applies:
00499  * - if minimum and maximum boundaries are set they are swapped
00500  * - if only a minimum boundary exists it will be replaced by a maximum boundary
00501  * - if only a maximum boundary exists it will be replaced by a minimum boundary
00502  *
00503  * An exception is thrown if a scale factor of 0 is specified.
00504  ***************************************************************************/
00505 void GOptimizerPar::scale(const double& scale)
00506 {
00507     // Make sure that scale is not zero
00508     if (scale == 0.0) {
00509         std::string msg = "Specified parameter scale factor of 0.\n"
00510                           "Parameters need a non-zero scale factor.";
00511         throw GException::invalid_argument(G_SCALE, msg);
00512     }
00513 
00514     // Set rescaling
00515     double rescale = m_scale/scale;
00516 
00517     // Set new scale factor
00518     m_scale = scale;
00519 
00520     // Set values, error, gradient, min and max
00521     m_factor_value    *= rescale;
00522     m_factor_error    *= rescale;
00523     m_factor_gradient *= rescale;
00524     if (m_has_min) {
00525         m_factor_min *= rescale;
00526     }
00527     if (m_has_max) {
00528         m_factor_max *= rescale;
00529     }
00530 
00531     // Takes care of boundaries in case of sign change
00532     if (rescale < 0.0) {
00533         if (m_has_min && m_has_max) {
00534             double swap  = m_factor_min;
00535             m_factor_min = m_factor_max;
00536             m_factor_max = swap;
00537         }
00538         else if (m_has_min) {
00539             m_factor_max = m_factor_min;
00540             m_has_max     = true;
00541             m_factor_min = 0.0;
00542             m_has_min     = false;
00543         }
00544         else if (m_has_max) {
00545             m_factor_min = m_factor_max;
00546             m_has_min     = true;
00547             m_factor_max = 0.0;
00548             m_has_max     = false;
00549         }
00550     }
00551     
00552     // Return
00553     return;
00554 }
00555 
00556 
00557 /***********************************************************************//**
00558  * @brief Autoscale parameter
00559  *
00560  * Sets the value factor to unity and the scale factor to the real value
00561  * of the parameter. The method will also adjust the error factor and
00562  * gradient factor, as well as the minimum and maximum factors if they
00563  * exist.
00564  *
00565  * Special care is taken for value boundaries, that need swaping if the scale
00566  * factor changes its sign. In case of sign change the following logic applies:
00567  * - if minimum and maximum boundaries are set they are swapped
00568  * - if only a minimum boundary exists it will be replaced by a maximum boundary
00569  * - if only a maximum boundary exists it will be replaced by a minimum boundary
00570  *
00571  * The method does nothing if the actual value factor is zero.
00572  ***************************************************************************/
00573 void GOptimizerPar::autoscale(void)
00574 {
00575     // Get value
00576     double value = this->value();
00577 
00578     // Continue only if the value is non-zero
00579     if (value != 0.0) {
00580 
00581         // Get the renormalization factor
00582         double renormalization = m_scale / value;
00583 
00584         // Set the new scale factor to the actual value
00585         m_scale = value;
00586 
00587         // Renormalize values, error, gradient, min and max
00588         m_factor_value    *= renormalization;
00589         m_factor_error    *= renormalization;
00590         m_factor_gradient /= renormalization;
00591         if (m_has_min) {
00592             m_factor_min *= renormalization;
00593         }
00594         if (m_has_max) {
00595             m_factor_max *= renormalization;
00596         }
00597 
00598         // Takes care of boundaries in case of sign change
00599         if (renormalization < 0.0) {
00600             if (m_has_min && m_has_max) {
00601                 double swap  = m_factor_min;
00602                 m_factor_min = m_factor_max;
00603                 m_factor_max = swap;
00604             }
00605             else if (m_has_min) {
00606                 m_factor_max = m_factor_min;
00607                 m_has_max     = true;
00608                 m_factor_min = 0.0;
00609                 m_has_min     = false;
00610             }
00611             else if (m_has_max) {
00612                 m_factor_min = m_factor_max;
00613                 m_has_min     = true;
00614                 m_factor_max = 0.0;
00615                 m_has_max     = false;
00616             }
00617         }
00618 
00619     } // endif: value was non-zero
00620 
00621     // Return
00622     return;
00623 }
00624 
00625 
00626 /***********************************************************************//**
00627  * @brief Print parameter information
00628  *
00629  * @param[in] chatter Chattiness (defaults to NORMAL).
00630  * @return String with parameter information.
00631  ***************************************************************************/
00632 std::string GOptimizerPar::print(const GChatter& chatter) const
00633 {
00634     // Initialise result string
00635     std::string result;
00636 
00637     // Continue only if chatter is not silent
00638     if (chatter != SILENT) {
00639 
00640         // Append parameter name
00641         result.append(gammalib::parformat(" "+name()));
00642 
00643         // Append value
00644         result.append(gammalib::str(value()));
00645 
00646         // For free parameters, append statistical uncertainty
00647         if (m_free) {
00648             result.append(" +/- "+gammalib::str(error()));
00649         }
00650 
00651         // Append parameter limites if they exist
00652         if (m_has_min && m_has_max) {
00653             result.append(" ["+gammalib::str(min()) + ","+gammalib::str(max())+"]");
00654         }
00655         else if (m_has_min) {
00656             result.append(" ["+gammalib::str(min()) + ",infty[");
00657         }
00658         else if (m_has_max) {
00659             result.append(" ]-infty,"+gammalib::str(max())+"]");
00660         }
00661 
00662         // Append parameter unit
00663         result.append(" "+m_unit);
00664 
00665         // Signal if parameter was free or fixed
00666         if (m_free) {
00667             result.append(" (free");
00668         }
00669         else {
00670             result.append(" (fixed");
00671         }
00672 
00673         // Append parameter scale
00674         result.append(",scale="+gammalib::str(m_scale));
00675 
00676         // Signal if parameter has analytic gradient
00677         if (m_has_grad) {
00678             result.append(",gradient)");
00679         }
00680         else {
00681             result.append(")");
00682         }
00683 
00684     } // endif: chatter was not silent
00685 
00686     // Return result
00687     return result;
00688 }
00689 
00690 
00691 /*==========================================================================
00692  =                                                                         =
00693  =                            Private methods                              =
00694  =                                                                         =
00695  ==========================================================================*/
00696 
00697 /***********************************************************************//**
00698  * @brief Initialise class members
00699  ***************************************************************************/
00700 void GOptimizerPar::init_members(void)
00701 {
00702     // Initialise members
00703     m_name            = "";
00704     m_unit            = "";
00705     m_factor_value    = 0.0;
00706     m_factor_error    = 0.0;
00707     m_factor_gradient = 0.0;
00708     m_factor_min      = 0.0;
00709     m_factor_max      = 0.0;
00710     m_scale           = 1.0;
00711     m_free            = true;
00712     m_has_min         = false;
00713     m_has_max         = false;
00714     m_has_grad        = false;
00715   
00716     // Return
00717     return;
00718 }
00719 
00720 
00721 /***********************************************************************//**
00722  * @brief Copy class members
00723  *
00724  * @param[in] par Model parameter.
00725  ***************************************************************************/
00726 void GOptimizerPar::copy_members(const GOptimizerPar& par)
00727 {
00728     // Copy members
00729     m_name            = par.m_name;
00730     m_unit            = par.m_unit;
00731     m_factor_value    = par.m_factor_value;
00732     m_factor_error    = par.m_factor_error;
00733     m_factor_gradient = par.m_factor_gradient;
00734     m_factor_min      = par.m_factor_min;
00735     m_factor_max      = par.m_factor_max;
00736     m_scale           = par.m_scale;
00737     m_free            = par.m_free;
00738     m_has_min         = par.m_has_min;
00739     m_has_max         = par.m_has_max;
00740     m_has_grad        = par.m_has_grad;
00741 
00742     // Return
00743     return;
00744 }
00745 
00746 
00747 /***********************************************************************//**
00748  * @brief Delete class members
00749  ***************************************************************************/
00750 void GOptimizerPar::free_members(void)
00751 {  
00752     // Return
00753     return;
00754 }

Generated on Tue Jan 24 12:37:24 2017 for GammaLib by  doxygen 1.4.7