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 }