CLHEP 2.4.6.4
C++ Class Library for High Energy Physics
Loading...
Searching...
No Matches
RandMultiGauss.cc
Go to the documentation of this file.
1// $Id: RandMultiGauss.cc,v 1.3 2003/08/13 20:00:13 garren Exp $
2// -*- C++ -*-
3//
4// -----------------------------------------------------------------------
5// HEP Random
6// --- RandMultiGauss ---
7// class implementation file
8// -----------------------------------------------------------------------
9
10// =======================================================================
11// Mark Fischler - Created: 17th September 1998
12// =======================================================================
13
14// Some theory about how to get the Multivariate Gaussian from a bunch
15// of Gaussian deviates. For the purpose of this discussion, take mu = 0.
16//
17// We want an n-vector x with distribution (See table 28.1 of Review of PP)
18//
19// exp ( .5 * x.T() * S.inverse() * x )
20// f(x;S) = ------------------------------------
21// sqrt ( (2*pi)^n * S.det() )
22//
23// Suppose S = U * D * U.T() with U orthogonal ( U*U.T() = 1 ) and D diagonal.
24// Consider a random n-vector y such that each element y(i)is distributed as a
25// Gaussian with sigma = sqrt(D(i,i)). Then the distribution of y is the
26// product of n Gaussains which can be written as
27//
28// exp ( .5 * y.T() * D.inverse() * y )
29// f(y;D) = ------------------------------------
30// sqrt ( (2*pi)^n * D.det() )
31//
32// Now take an n-vector x = U * y (or y = U.T() * x ). Then substituting,
33//
34// exp ( .5 * x * U * D.inverse() U.T() * x )
35// f(x;D,U) = ------------------------------------------
36// sqrt ( (2*pi)^n * D.det() )
37//
38// and this simplifies to the desired f(x;S) when we note that
39// D.det() = S.det() and U * D.inverse() * U.T() = S.inverse()
40//
41// So the strategy is to diagonalize S (finding U and D), form y with each
42// element a Gaussian random with sigma of sqrt(D(i,i)), and form x = U*y.
43// (It turns out that the D information needed is the sigmas.)
44// Since for moderate or large n the work needed to diagonalize S can be much
45// greater than the work to generate n Gaussian variates, we save the U and
46// sigmas for both the default S and the latest S value provided.
47
48#include "CLHEP/RandomObjects/RandMultiGauss.h"
49#include "CLHEP/RandomObjects/defs.h"
50#include <cmath> // for log()
51#include <iostream>
52
53namespace CLHEP {
54
55// ------------
56// Constructors
57// ------------
58
60 const HepVector & mu,
61 const HepSymMatrix & S )
62 : localEngine(&anEngine),
63 deleteEngine(false),
64 set(false),
65 nextGaussian(0.0)
66{
67 if (S.num_row() != mu.num_row()) {
68 std::cerr << "In constructor of RandMultiGauss distribution: \n" <<
69 " Dimension of mu (" << mu.num_row() <<
70 ") does not match dimension of S (" << S.num_row() << ")\n";
71 std::cerr << "---Exiting to System\n";
72 exit(1);
73 }
74 defaultMu = mu;
75 defaultSigmas = HepVector(S.num_row());
76 prepareUsigmas (S, defaultU, defaultSigmas);
77}
78
80 const HepVector & mu,
81 const HepSymMatrix & S )
82 : localEngine(anEngine),
83 deleteEngine(true),
84 set(false),
85 nextGaussian(0.0)
86{
87 if (S.num_row() != mu.num_row()) {
88 std::cerr << "In constructor of RandMultiGauss distribution: \n" <<
89 " Dimension of mu (" << mu.num_row() <<
90 ") does not match dimension of S (" << S.num_row() << ")\n";
91 std::cerr << "---Exiting to System\n";
92 exit(1);
93 }
94 defaultMu = mu;
95 defaultSigmas = HepVector(S.num_row());
96 prepareUsigmas (S, defaultU, defaultSigmas);
97}
98
100 : localEngine(&anEngine),
101 deleteEngine(false),
102 set(false),
103 nextGaussian(0.0)
104{
105 defaultMu = HepVector(2,0);
106 defaultU = HepMatrix(2,1);
107 defaultSigmas = HepVector(2);
108 defaultSigmas(1) = 1.;
109 defaultSigmas(2) = 1.;
110}
111
113 : localEngine(anEngine),
114 deleteEngine(true),
115 set(false),
116 nextGaussian(0.0)
117{
118 defaultMu = HepVector(2,0);
119 defaultU = HepMatrix(2,1);
120 defaultSigmas = HepVector(2);
121 defaultSigmas(1) = 1.;
122 defaultSigmas(2) = 1.;
123}
124
126 if ( deleteEngine ) delete localEngine;
127}
128
129// ----------------------------
130// prepareUsigmas()
131// ----------------------------
132
133void RandMultiGauss::prepareUsigmas( const HepSymMatrix & S,
134 HepMatrix & U,
135 HepVector & sigmas ) {
136
137 HepSymMatrix tempS ( S ); // Since diagonalize does not take a const s
138 // we have to copy S.
139
140 U = diagonalize ( &tempS ); // S = U Sdiag U.T()
141 HepSymMatrix D = S.similarityT(U); // D = U.T() S U = Sdiag
142 for (int i = 1; i <= S.num_row(); i++) {
143 double s2 = D(i,i);
144 if ( s2 > 0 ) {
145 sigmas(i) = sqrt ( s2 );
146 } else {
147 std::cerr << "In RandMultiGauss distribution: \n" <<
148 " Matrix S is not positive definite. Eigenvalues are:\n";
149 for (int ixx = 1; ixx <= S.num_row(); ixx++) {
150 std::cerr << " " << D(ixx,ixx) << std::endl;
151 }
152 std::cerr << "---Exiting to System\n";
153 exit(1);
154 }
155 }
156} // prepareUsigmas
157
158// -----------
159// deviates()
160// -----------
161
162HepVector RandMultiGauss::deviates ( const HepMatrix & U,
163 const HepVector & sigmas,
164 HepRandomEngine * engine,
165 bool& available,
166 double& next)
167{
168 // Returns vector of gaussian randoms based on sigmas, rotated by U,
169 // with means of 0.
170
171 int n = sigmas.num_row();
172 HepVector v(n); // The vector to be returned
173
174 double r,v1,v2,fac;
175
176 int i = 1;
177 if (available) {
178 v(1) = next;
179 i = 2;
180 available = false;
181 }
182
183 while ( i <= n ) {
184 do {
185 v1 = 2.0 * engine->flat() - 1.0;
186 v2 = 2.0 * engine->flat() - 1.0;
187 r = v1*v1 + v2*v2;
188 } while ( r > 1.0 );
189 fac = sqrt(-2.0*log(r)/r);
190 v(i++) = v1*fac;
191 if ( i <= n ) {
192 v(i++) = v2*fac;
193 } else {
194 next = v2*fac;
195 available = true;
196 }
197 }
198
199 for ( i = 1; i <= n; i++ ) {
200 v(i) *= sigmas(i);
201 }
202
203 return U*v;
204
205} // deviates()
206
207// ---------------
208// fire signatures
209// ---------------
210
212 // Returns a pair of unit normals, using the S and mu set in constructor,
213 // utilizing the engine belonging to this instance of RandMultiGauss.
214
215 return defaultMu + deviates ( defaultU, defaultSigmas,
216 localEngine, set, nextGaussian );
217
218} // fire();
219
220
222
223 HepMatrix U;
224 HepVector sigmas(mu.num_row());
225
226 if (mu.num_row() == S.num_row()) {
227 prepareUsigmas ( S, U, sigmas );
228 return mu + deviates ( U, sigmas, localEngine, set, nextGaussian );
229 } else {
230 std::cerr << "In firing RandMultiGauss distribution with explicit mu and S: \n"
231 << " Dimension of mu (" << mu.num_row() <<
232 ") does not match dimension of S (" << S.num_row() << ")\n";
233 std::cerr << "---Exiting to System\n";
234 exit(1);
235 }
236 return mu; // This line cannot be reached. But without returning
237 // some HepVector here, KCC 3.3 complains.
238
239} // fire(mu, S);
240
241
242// --------------------
243// fireArray signatures
244// --------------------
245
246void RandMultiGauss::fireArray( const int size, HepVector* array ) {
247
248 int i;
249 for (i = 0; i < size; ++i) {
250 array[i] = defaultMu + deviates ( defaultU, defaultSigmas,
251 localEngine, set, nextGaussian );
252 }
253
254} // fireArray ( size, vect )
255
256
257void RandMultiGauss::fireArray( const int size, HepVector* array,
258 const HepVector& mu, const HepSymMatrix& S ) {
259
260 // For efficiency, we diagonalize S once and generate all the vectors based
261 // on that U and sigmas.
262
263 HepMatrix U;
264 HepVector sigmas(mu.num_row());
265 HepVector mu_ (mu);
266
267 if (mu.num_row() == S.num_row()) {
268 prepareUsigmas ( S, U, sigmas );
269 } else {
270 std::cerr <<
271 "In fireArray for RandMultiGauss distribution with explicit mu and S: \n"
272 << " Dimension of mu (" << mu.num_row() <<
273 ") does not match dimension of S (" << S.num_row() << ")\n";
274 std::cerr << "---Exiting to System\n";
275 exit(1);
276 }
277
278 int i;
279 for (i=0; i<size; ++i) {
280 array[i] = mu_ + deviates(U, sigmas, localEngine, set, nextGaussian);
281 }
282
283} // fireArray ( size, vect, mu, S )
284
285// ----------
286// operator()
287// ----------
288
290 return fire();
291}
292
293HepVector RandMultiGauss::operator()
294 ( const HepVector& mu, const HepSymMatrix& S ) {
295 return fire(mu,S);
296}
297
298
299} // namespace CLHEP
int num_row() const
HepSymMatrix similarityT(const HepMatrix &hm1) const
Definition: SymMatrix.cc:813
virtual int num_row() const
Definition: Vector.cc:116
void fireArray(const int size, HepVector *array)
RandMultiGauss(HepRandomEngine &anEngine, const HepVector &mu, const HepSymMatrix &S)
#define exit(x)
HepMatrix diagonalize(HepSymMatrix *s)
Definition: excDblThrow.cc:17