1 /* _______________________________________________________________________
2
3 PECOS: Parallel Environment for Creation Of Stochastics
4 Copyright (c) 2011, Sandia National Laboratories.
5 This software is distributed under the GNU Lesser General Public License.
6 For more information, see the README file in the top Pecos directory.
7 _______________________________________________________________________ */
8
9 //- Class: TriangularRandomVariable
10 //- Description: Encapsulates random variable data and utilities
11 //- Owner: Mike Eldred
12 //- Revised by:
13 //- Version:
14
15 #ifndef TRIANGULAR_RANDOM_VARIABLE_HPP
16 #define TRIANGULAR_RANDOM_VARIABLE_HPP
17
18 #include "UniformRandomVariable.hpp"
19
20 namespace Pecos {
21
22
23 /// Derived random variable class for triangular random variables.
24
25 /** Manages mode and inherits bounds. See Haldar and Mahadevan, p. 99. */
26
27 class TriangularRandomVariable: public UniformRandomVariable
28 {
29 public:
30
31 //
32 //- Heading: Constructors and destructor
33 //
34
35 /// default constructor
36 TriangularRandomVariable();
37 /// alternate constructor
38 TriangularRandomVariable(Real lwr, Real mode, Real upr);
39 /// destructor
40 ~TriangularRandomVariable();
41
42 //
43 //- Heading: Virtual function redefinitions
44 //
45
46 Real cdf(Real x) const;
47 Real ccdf(Real x) const;
48 Real inverse_cdf(Real p_cdf) const;
49 Real inverse_ccdf(Real p_ccdf) const;
50
51 Real pdf(Real x) const;
52 Real pdf_gradient(Real x) const;
53 Real pdf_hessian(Real x) const;
54
55 void pull_parameter(short dist_param, Real& val) const;
56 void push_parameter(short dist_param, Real val);
57
58 void copy_parameters(const RandomVariable& rv);
59
60 Real mean() const;
61 Real median() const;
62 Real mode() const;
63 Real standard_deviation() const;
64 Real variance() const;
65
66 Real dx_ds(short dist_param, short u_type, Real x, Real z) const;
67 Real dz_ds_factor(short u_type, Real x, Real z) const;
68
69 //
70 //- Heading: Member functions
71 //
72
73 void update(Real lwr, Real mode, Real upr);
74
75 //
76 //- Heading: Static member functions (global utilities)
77 //
78
79 static Real pdf(Real x, Real lwr, Real mode, Real upr);
80 static Real cdf(Real x, Real lwr, Real mode, Real upr);
81
82 static void moments_from_params(Real lwr, Real mode, Real upr,
83 Real& mean, Real& std_dev);
84
85 protected:
86
87 //
88 //- Heading: Member functions
89 //
90
91 /// create a new triangDist instance
92 void update_boost();
93 /// create a new triangDist instance if parameter set is valid
94 void update_boost_conditionally();
95
96 //
97 //- Heading: Data
98 //
99
100 /// mode of triangular random variable
101 Real triangularMode;
102
103 /// pointer to the Boost trainagulardistribution instance
104 std::unique_ptr<triangular_dist> triangDist;
105 };
106
107
TriangularRandomVariable()108 inline TriangularRandomVariable::TriangularRandomVariable():
109 UniformRandomVariable(), triangularMode(0.),
110 triangDist(new triangular_dist(lowerBnd, triangularMode, upperBnd))
111 { ranVarType = TRIANGULAR; }
112
113
114 inline TriangularRandomVariable::
TriangularRandomVariable(Real lwr,Real mode,Real upr)115 TriangularRandomVariable(Real lwr, Real mode, Real upr):
116 UniformRandomVariable(lwr, upr), triangularMode(mode),
117 triangDist(new triangular_dist(lwr, mode, upr))
118 { ranVarType = TRIANGULAR; }
119
120
~TriangularRandomVariable()121 inline TriangularRandomVariable::~TriangularRandomVariable()
122 { }
123
124
pdf(Real x,Real lwr,Real mode,Real upr)125 inline Real TriangularRandomVariable::pdf(Real x, Real lwr, Real mode, Real upr)
126 {
127 triangular_dist tri1(lwr, mode, upr);
128 return bmth::pdf(tri1, x);
129
130 //return (x < mode) ? 2.*(x-lwr)/(upr-lwr)/(mode-lwr) :
131 // 2.*(upr-x)/(upr-lwr)/(upr-mode);
132 }
133
134
cdf(Real x,Real lwr,Real mode,Real upr)135 inline Real TriangularRandomVariable::cdf(Real x, Real lwr, Real mode, Real upr)
136 {
137 triangular_dist tri1(lwr, mode, upr);
138 return bmth::cdf(tri1, x);
139
140 //return (x < mode) ? std::pow(x-lwr,2.)/(upr-lwr)/(mode-lwr) :
141 // ((mode-lwr) - (x+mode-2*upr)*(x-mode)/(upr-mode))/(upr-lwr);
142 }
143
144
cdf(Real x) const145 inline Real TriangularRandomVariable::cdf(Real x) const
146 { return bmth::cdf(*triangDist, x); }
147
148
ccdf(Real x) const149 inline Real TriangularRandomVariable::ccdf(Real x) const
150 { return bmth::cdf(complement(*triangDist, x)); }
151
152
inverse_cdf(Real p_cdf) const153 inline Real TriangularRandomVariable::inverse_cdf(Real p_cdf) const
154 {
155 return bmth::quantile(*triangDist, p_cdf);
156
157 /*
158 // assume x < mode and then check
159 Real range = upperBnd - lowerBnd,
160 x = lowerBnd + std::sqrt(p*range*(triangularMode-lowerBnd));
161 Real x_pdf = 2.*(x-lowerBnd)/range/(triangularMode-lowerBnd),
162 m_pdf = 2./range;
163 // check pdf value to ensure that proper equation used
164 if ( x_pdf > m_pdf )
165 x = upperBnd - std::sqrt((1.-p)*range*(upperBnd-triangularMode));
166 return x;
167 */
168 }
169
170
inverse_ccdf(Real p_ccdf) const171 inline Real TriangularRandomVariable::inverse_ccdf(Real p_ccdf) const
172 { return bmth::quantile(complement(*triangDist, p_ccdf)); }
173
174
175 // x < M x > M
176 // F(x): (x-L)^2/(U-L)/(M-L) (M-L)/(U-L) - (x+M-2U)(x-M)/(U-L)/(U-M)
177 // f(x): 2(x-L)/(U-L)/(M-L) 2(U-x)/(U-L)/(U-M)
178 // f'(x): 2/(U-L)/(M-L) -2/(U-L)/(U-M)
179 // Note: at x=M, F(x) and f(x) are continuous but f'(x) is not
pdf(Real x) const180 inline Real TriangularRandomVariable::pdf(Real x) const
181 { return bmth::pdf(*triangDist, x); }
182
183
pdf_gradient(Real x) const184 inline Real TriangularRandomVariable::pdf_gradient(Real x) const
185 {
186 Real range = upperBnd - lowerBnd;
187 if (x < triangularMode)
188 return 2. / ( range * (triangularMode - lowerBnd) );
189 else if (x > triangularMode)
190 return -2. / ( range * (upperBnd - triangularMode) );
191 else // x == triangularMode
192 return 0.; // f'(x) is undefined: use 0.
193 }
194
195
pdf_hessian(Real x) const196 inline Real TriangularRandomVariable::pdf_hessian(Real x) const
197 { return 0.; }
198
199
200 inline void TriangularRandomVariable::
pull_parameter(short dist_param,Real & val) const201 pull_parameter(short dist_param, Real& val) const
202 {
203 switch (dist_param) {
204 case T_MODE: val = triangularMode; break;
205 case T_LWR_BND: val = lowerBnd; break;
206 case T_UPR_BND: val = upperBnd; break;
207 default:
208 PCerr << "Error: update failure for distribution parameter " << dist_param
209 << " in TriangularRandomVariable::pull_parameter(Real)." << std::endl;
210 abort_handler(-1); break;
211 }
212 }
213
214
push_parameter(short dist_param,Real val)215 inline void TriangularRandomVariable::push_parameter(short dist_param, Real val)
216 {
217 switch (dist_param) {
218 case T_MODE: triangularMode = val; break;
219 case T_LWR_BND: lowerBnd = val; break;
220 case T_UPR_BND: upperBnd = val; break;
221 default:
222 PCerr << "Error: update failure for distribution parameter " << dist_param
223 << " in TriangularRandomVariable::push_parameter(Real)." << std::endl;
224 abort_handler(-1); break;
225 }
226 update_boost_conditionally();// create new triangDist instance if valid params
227 }
228
229
copy_parameters(const RandomVariable & rv)230 inline void TriangularRandomVariable::copy_parameters(const RandomVariable& rv)
231 {
232 rv.pull_parameter(T_MODE, triangularMode);
233 //UniformRandomVariable::copy_parameters(rv); // different enums used
234 rv.pull_parameter(T_LWR_BND, lowerBnd);
235 rv.pull_parameter(T_UPR_BND, upperBnd);
236 update_boost(); // create a new triangDist instance
237 }
238
239
mean() const240 inline Real TriangularRandomVariable::mean() const
241 { return bmth::mean(*triangDist); }
242
243
median() const244 inline Real TriangularRandomVariable::median() const
245 { return bmth::median(*triangDist); }
246
247
mode() const248 inline Real TriangularRandomVariable::mode() const
249 { return bmth::mode(*triangDist); }
250
251
standard_deviation() const252 inline Real TriangularRandomVariable::standard_deviation() const
253 { return bmth::standard_deviation(*triangDist); }
254
255
variance() const256 inline Real TriangularRandomVariable::variance() const
257 { return bmth::variance(*triangDist); }
258
259
260 /** dx/ds is derived by differentiating NatafTransformation::trans_Z_to_X()
261 with respect to distribution parameter s. dz/ds is zero if uncorrelated,
262 while dz_ds_factor() manages contributions in the correlated case. */
263 inline Real TriangularRandomVariable::
dx_ds(short dist_param,short u_type,Real x,Real z) const264 dx_ds(short dist_param, short u_type, Real x, Real z) const
265 {
266 bool u_type_err = false, dist_error = false; Real sdf;
267 if (x < triangularMode)
268 switch (u_type) {
269 case STD_NORMAL: sdf = NormalRandomVariable::std_cdf(z); break;
270 case STD_UNIFORM: sdf = UniformRandomVariable::std_cdf(z); break;
271 //case TRIANGULAR: break;
272 default: u_type_err = true; break;
273 }
274 else
275 switch (u_type) {
276 case STD_NORMAL: sdf = NormalRandomVariable::std_ccdf(z); break;
277 case STD_UNIFORM: sdf = UniformRandomVariable::std_ccdf(z); break;
278 //case TRIANGULAR: break;
279 default: u_type_err = true; break;
280 }
281 if (u_type_err) {
282 PCerr << "Error: unsupported u-space type " << u_type
283 << " in TriangularRandomVariable::dx_ds()." << std::endl;
284 abort_handler(-1);
285 }
286
287 if (x < triangularMode) {
288 Real denom = 2.*(x-lowerBnd);
289 switch (dist_param) {
290 case T_MODE: return sdf*(upperBnd-lowerBnd)/denom; break;
291 case T_LWR_BND:
292 return 1.+sdf*(2.*lowerBnd-upperBnd-triangularMode)/denom; break;
293 case T_UPR_BND: return sdf*(triangularMode-lowerBnd)/denom; break;
294 // Triangular Mean - TO DO
295 // Triangular Std Deviation - TO DO
296 default: dist_error = true; break;
297 }
298 }
299 else {
300 Real denom = 2.*(upperBnd-x);
301 switch (dist_param) {
302 case T_MODE: return sdf*(upperBnd-lowerBnd)/denom; break;
303 case T_LWR_BND: return (upperBnd-triangularMode)*sdf/denom; break;
304 case T_UPR_BND:
305 return 1.-sdf*(2.*upperBnd-lowerBnd-triangularMode)/denom; break;
306 // Triangular Mean - TO DO
307 // Triangular Std Deviation - TO DO
308 default: dist_error = true; break;
309 }
310 }
311 if (dist_error) {
312 PCerr << "Error: mapping failure for distribution parameter " << dist_param
313 << " in TriangularRandomVariable::dx_ds()." << std::endl;
314 abort_handler(-1); return 0.;
315 }
316 }
317
318
319 /** dx/ds is derived by differentiating NatafTransformation::trans_Z_to_X()
320 with respect to distribution parameter s. For the uncorrelated case,
321 u and z are constants. For the correlated case, u is a constant, but
322 z(s) = L(s) u due to Nataf dependence on s and dz/ds = dL/ds u. */
323 inline Real TriangularRandomVariable::
dz_ds_factor(short u_type,Real x,Real z) const324 dz_ds_factor(short u_type, Real x, Real z) const
325 {
326 Real pdf;
327 switch (u_type) {
328 case STD_NORMAL: pdf = NormalRandomVariable::std_pdf(z); break;
329 case STD_UNIFORM: pdf = UniformRandomVariable::std_pdf(z); break;
330 //case TRIANGULAR: break;
331 default:
332 PCerr << "Error: unsupported u-space type " << u_type
333 << " in TriangularRandomVariable::dz_ds_factor()." << std::endl;
334 abort_handler(-1); break;
335 }
336
337 return (x < triangularMode) ?
338 (upperBnd-lowerBnd)*(triangularMode-lowerBnd)*pdf/(2.*(x-lowerBnd)) :
339 (upperBnd-triangularMode)*(upperBnd-lowerBnd)*pdf/(2.*(upperBnd-x));
340 }
341
342
update_boost()343 inline void TriangularRandomVariable::update_boost()
344 {
345 triangDist.reset(new triangular_dist(lowerBnd, triangularMode, upperBnd));
346 }
347
348
update_boost_conditionally()349 inline void TriangularRandomVariable::update_boost_conditionally()
350 {
351 // old is now invalid
352 if (triangDist) triangDist.reset();
353 // new may not be valid as of yet
354 if (lowerBnd <= triangularMode && triangularMode <= upperBnd)
355 triangDist.reset(new triangular_dist(lowerBnd, triangularMode, upperBnd));
356 // else wait for pending param updates
357 }
358
359
update(Real lwr,Real mode,Real upr)360 inline void TriangularRandomVariable::update(Real lwr, Real mode, Real upr)
361 {
362 if (!triangDist ||
363 lowerBnd != lwr || triangularMode != mode || upperBnd != upr)
364 { lowerBnd = lwr; triangularMode = mode; upperBnd = upr; update_boost(); }
365 }
366
367
368 inline void TriangularRandomVariable::
moments_from_params(Real lwr,Real mode,Real upr,Real & mean,Real & std_dev)369 moments_from_params(Real lwr, Real mode, Real upr, Real& mean, Real& std_dev)
370 {
371 mean = (lwr + mode + upr)/3.;
372 std_dev
373 = std::sqrt((lwr*(lwr - mode) + mode*(mode - upr) + upr*(upr - lwr))/18.);
374 }
375
376 } // namespace Pecos
377
378 #endif
379