Isis 3 Programmer Reference
MaximumLikelihoodWFunctions.cpp
1
7/* SPDX-License-Identifier: CC0-1.0 */
8
9#include "MaximumLikelihoodWFunctions.h"
10
11#include <QDataStream>
12#include <QString>
13
14#include <math.h>
15#include <stdio.h>
16
17#include "IException.h"
18#include "IString.h"
19
20namespace Isis {
26 this->setModel(Huber);
27 } // choose Model and define the tweaking constant
28
29
30
39 // choose Model and define the tweaking constant
40 this->setModel(modelSelection);
41 }
42
43
44
57 double tweakingConstant) {
58 // choose Model and define the tweaking constant
59 setModel(modelSelection, tweakingConstant);
60 }
61
63 const MaximumLikelihoodWFunctions &other)
64 : m_model(other.m_model),
65 m_tweakingConstant(other.m_tweakingConstant) {
66 }
67
68
69 MaximumLikelihoodWFunctions::~MaximumLikelihoodWFunctions() {
70 } // empty destructor
71
72
73 MaximumLikelihoodWFunctions &MaximumLikelihoodWFunctions::operator=(
74 const MaximumLikelihoodWFunctions &other) {
75 m_model = other.m_model;
76 m_tweakingConstant = other.m_tweakingConstant;
77 return *this;
78 }
79
88 // choose Model and use default tweaking constant
89 m_model = modelSelection;
91 }
92
93
94
99 // default tweaking constants for the various likelihood models
100 switch (m_model) {
101 case Huber:
102 m_tweakingConstant = 1.345; // "95% asymptotic efficiecy on the standard normal distribution"
103 // is obtained with this constant,
104 // see Zhang's "Parameter Estimation"
105 break;
106 case HuberModified:
107 m_tweakingConstant = 1.2107;// "95% asymptotic efficiecy on the standard normal distribution"
108 // is obtained with this constant,
109 // see Zhang's "Parameter Estimation"
110 break;
111 case Welsch:
112 m_tweakingConstant = 2.9846;// "95% asymptotic efficiecy on the standard normal distribution"
113 // is obtained with this constant,
114 // see Zhang's "Parameter Estimation"
115 break;
116 case Chen:
117 m_tweakingConstant = 1; // This is the constant used by Chen in his paper,
118 // no specific reason why is stated
119 break;
120 default:
121 m_tweakingConstant = 1; // default, though at the time of writing this class,
122 // this value should never actually be used
123 }
124 }
125
126
127
139 void MaximumLikelihoodWFunctions::setModel(Model modelSelection, double tweakingConstant) {
140 // choose Model and define the tweaking constant
141 m_model = modelSelection;
143 }
144
145
146
157 // leave model type unaltered and change tweaking constant
158 if (tweakingConstant <= 0.0) {
159 IString msg = "Maximum likelihood estimation tweaking constants must be > 0.0";
160 throw IException(IException::Programmer, msg, _FILEINFO_);
161 }
163 }
164
165
166
173
174
175
186 double MaximumLikelihoodWFunctions::weightScaler(double residualZScore) {
187 // this is likely the least usefull of the scaler functions but it is provided for completness.
188 // This directly provides the scaler for the weight (instead of the radical weight), thus it
189 // provides sqrtWeightScaler^2
190 switch(m_model) {
191 case Huber:
192 return this->huber(residualZScore);
193 case HuberModified:
194 return this->huberModified(residualZScore);
195 case Welsch:
196 return this->welsch(residualZScore);
197 case Chen:
198 return this->chen(residualZScore);
199 default:
200 return 1.0; // default to prevent nonsense from being returned,
201 // but the program should never reach this line
202 }
203 }
204
205
206
217 double MaximumLikelihoodWFunctions::sqrtWeightScaler(double residualZScore) {
218 // it is often convient to use square roots of weights when building normals, this function
219 // provides the scaler for the square root of the weight directly
220 double scaler = this->weightScaler(residualZScore);
221 if (scaler <= 0.0) {
222 return 0.0; // <0 should never happen, but 0.0 may be quite frequent
223 // (thus this saves some time)
224 }
225 return sqrt(scaler);
226 }
227
228
229
240 double MaximumLikelihoodWFunctions::huber(double residualZScore) {
241 // huber weight function
242 if ( fabs(residualZScore) < m_tweakingConstant) {
243 return 1.0;
244 }
245 else {
246 return m_tweakingConstant/fabs(residualZScore);
247 }
248 }
249
250
251
262 double MaximumLikelihoodWFunctions::huberModified(double residualZScore) {
263 // huber modified weight function
264 if ( fabs(residualZScore)/m_tweakingConstant < Isis::HALFPI) {
265 return m_tweakingConstant*(sin(residualZScore/m_tweakingConstant)/residualZScore);
266 }
267 else {
268 return m_tweakingConstant / fabs(residualZScore);
269 }
270 }
271
272
273
284 double MaximumLikelihoodWFunctions::welsch(double residualZScore) {
285 // welsch weight function
286 double weightFactor = residualZScore / m_tweakingConstant;
287 return exp(-(weightFactor)*(weightFactor));
288 }
289
290
291
302 double MaximumLikelihoodWFunctions::chen(double residualZScore) {
303 // chen weight function
304 if ( fabs(residualZScore) <= m_tweakingConstant) {
305 double weightFactor = m_tweakingConstant * m_tweakingConstant
306 - residualZScore * residualZScore;
307 return 6 * weightFactor * weightFactor; // use of weight factor variable reduces number of
308 // operations from 7 to 4
309 }
310 else {
311 return 0.0;
312 }
313 }
314
315
316
325 // returns which quantile of the sqaured residuals is recommended to use as the tweaking
326 // constants, this varies as a function of the model being employed desired quantiles for
327 // various models, these parameters are estimated based on inspection of the fucntions and
328 // should be tested and revised with experience
329 switch(m_model) {
330 case Huber:
331 return 0.5; // In this model m_tweakingConstant determines the point at which residuals stop having
332 // increased influence on the solution, so after the median all the measures will
333 // have the same effect on the solution regardless of magnitude
334 case HuberModified:
335 return 0.4; // In this model after residualZScore >= m_tweakingConstant*Isis::HALFPI the residuals have the same
336 // influence on the solution,
337 case Welsch:
338 return 0.7; // at about double m_tweakingConstant the residuals have very little influence
339 case Chen:
340 return 0.98; // after r > m_tweakingConstant residuals have no influence
341 default:
342 return 0.5; // default, though at the time of writing this should never actually be used
343 }
344 }
345
346
347
356 if (model == MaximumLikelihoodWFunctions::Huber) return "Huber";
357 else if (model == MaximumLikelihoodWFunctions::HuberModified) return "HuberModified";
358 else if (model == MaximumLikelihoodWFunctions::Welsch) return "Welsch";
359 else if (model == MaximumLikelihoodWFunctions::Chen) return "Chen";
361 "Unknown estimation model enum [" + toString(model) + "].",
362 _FILEINFO_);
363 }
364
365
366
367 MaximumLikelihoodWFunctions::Model MaximumLikelihoodWFunctions::stringToModel(QString modelName) {
368 if (modelName.compare("HUBER", Qt::CaseInsensitive) == 0) {
369 return Huber;
370 }
371 else if (modelName.compare("HUBER_MODIFIED", Qt::CaseInsensitive) == 0 ||
372 modelName.compare("HUBERMODIFIED", Qt::CaseInsensitive) == 0 ||
373 modelName.compare("HUBER MODIFIED", Qt::CaseInsensitive) == 0) {
374 return HuberModified;
375 }
376 else if (modelName.compare("WELSCH", Qt::CaseInsensitive) == 0) {
377 return Welsch;
378 }
379 else if (modelName.compare("CHEN", Qt::CaseInsensitive) == 0) {
380 return Chen;
381 }
382 else {
383 throw IException(IException::Programmer,
384 "Unknown maximum likelihood model name " + modelName + ".",
385 _FILEINFO_);
386 }
387 }
388
389
390
400 if (m_model == Huber || m_model == HuberModified) return "N/A";
401 else if (m_model == Welsch) return toString(m_tweakingConstant * 1.5);
402 else if (m_model == Chen) return toString(m_tweakingConstant);
403 else throw IException(IException::Programmer, "Estimation model has not been set.", _FILEINFO_);
404 }
405
406
407
416
417
418
419 QDataStream &MaximumLikelihoodWFunctions::write(QDataStream &stream) const {
420 stream << (qint32)m_model
422 return stream;
423 }
424
425
426
427 QDataStream &MaximumLikelihoodWFunctions::read(QDataStream &stream) {
428 qint32 model;
429 stream >> model >> m_tweakingConstant;
431 return stream;
432 }
433
434
435
436 QDataStream &operator<<(QDataStream &stream, const MaximumLikelihoodWFunctions &mlwf) {
437 return mlwf.write(stream);
438 }
439
440
441
442 QDataStream &operator>>(QDataStream &stream, MaximumLikelihoodWFunctions &mlwf) {
443 return mlwf.read(stream);
444 }
445
446
447
448 QDataStream &operator<<(QDataStream &stream, const MaximumLikelihoodWFunctions::Model &modelEnum) {
449 stream << (qint32)modelEnum;
450 return stream;
451 }
452
453
454
455 QDataStream &operator>>(QDataStream &stream, MaximumLikelihoodWFunctions::Model &modelEnum) {
456 qint32 modelInteger;
457 stream >> modelInteger;
458 modelEnum = (MaximumLikelihoodWFunctions::Model)modelInteger;
459 return stream;
460 }
461
462}// end namespace Isis
Isis exception class.
Definition IException.h:91
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
Adds specific functionality to C++ strings.
Definition IString.h:165
Class provides maximum likelihood estimation functions for robust parameter estimation,...
MaximumLikelihoodWFunctions()
Sets up a maximumlikelihood estimation function with Huber model and default tweaking constant.
Model m_model
The enumerated value for the maximum likelihood estimation model to be used.
static QString modelToString(Model model)
Static method to return a string represtentation for a given MaximumLikelihoodWFunctions::Model enum.
void setModel(Model modelSelection)
Allows the maximum likelihood model to be changed together and the default tweaking constant to be se...
Model model() const
Accessor method to return the MaximumLikelihoodWFunctions::Model enumeration.
QString weightedResidualCutoff()
Method to return a string represtentation of the weighted residual cutoff (if it exists) for the Maxi...
double huber(double residualZScore)
Huber maximum likelihood estimation function evaluation.
double welsch(double residualZScore)
Modified Huber maximum likelihood estimation function evaluation.
Model
The supported maximum likelihood estimation models.
@ Welsch
The Welsch method aggresively discounts measures with large resiudals.
@ Chen
The Chen method was found in "Robust Regression with Projection Based M-estimators" Chen,...
@ HuberModified
A modification to Huber's method propsed by William J.J.
@ Huber
According to Zhang (Parameter Estimation: A Tutorial with application to conic fitting) "[Huber's] es...
double huberModified(double residualZScore)
Modified Huber maximum likelihood estimation function evaluation.
double tweakingConstantQuantile()
Suggest a quantile of the probility distribution of the residuals to use as the tweaking constants ba...
double m_tweakingConstant
The tweaking constant for the maximum likelihood models.
void setTweakingConstantDefault()
Sets default tweaking constants based on the maximum likelihood estimation model being used.
double sqrtWeightScaler(double residualZScore)
This provides the scaler to the sqrt of the weight, which is very useful for building normal equation...
double weightScaler(double residualZScore)
This provides the scalar for the weight (not the scaler for the square root of the weight,...
double chen(double residualZScore)
Modified Huber maximum likelihood estimation function evaluation.
void setTweakingConstant(double tweakingConstant)
Allows the tweaking constant to be changed without changing the maximum likelihood function.
double tweakingConstant() const
Returns the current tweaking constant.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition IString.cpp:211
const double HALFPI
The mathematical constant PI/2.
Definition Constants.h:41
std::istream & operator>>(std::istream &is, CSVReader &csv)
Input read operator for input stream sources.
QDebug operator<<(QDebug debug, const Hillshade &hillshade)
Print this class out to a QDebug object.