1 // SWIG file Distribution.i
2 
3 %{
4 #include "openturns/Distribution.hxx"
5 #include "openturns/PythonDistribution.hxx"
6 %}
7 
8 %include Distribution_doc.i
9 
10 %include UncertaintyModelCopulaCollection.i
11 
12 OTTypedInterfaceObjectHelper(Distribution)
13 OTTypedCollectionInterfaceObjectHelper(Distribution)
14 
15 %ignore OT::Distribution::pow;
16 %ignore OT::Distribution::setWeight;
17 %ignore OT::Distribution::getWeight;
18 
19 %include openturns/Distribution.hxx
20 
21 namespace OT {
22 
23 %extend Distribution {
24 
Distribution(const Distribution & other)25 Distribution(const Distribution & other)
26 {
27   return new OT::Distribution(other);
28 }
29 
Distribution(PyObject * pyObj)30 Distribution(PyObject * pyObj)
31 {
32   return new OT::Distribution( new OT::PythonDistribution( pyObj ) );
33 }
34 
__add__(Scalar s)35 Distribution __add__ (Scalar s)
36 {
37  return *self + s;
38 }
39 
__radd__(Scalar s)40 Distribution __radd__ (Scalar s)
41 {
42  return *self + s;
43 }
44 
__sub__(Scalar s)45 Distribution __sub__(Scalar s)
46 {
47  return *self - s;
48 }
49 
__rsub__(Scalar s)50 Distribution __rsub__(Scalar s)
51 {
52   return (*self * (-1.0)) + s;
53 }
54 
__mul__(Scalar s)55 Distribution __mul__(Scalar s)
56 {
57  return (*self) * s;
58 }
59 
__rmul__(Scalar s)60 Distribution __rmul__(Scalar s)
61 {
62  return (*self) * s;
63 }
64 
__div__(Scalar s)65 Distribution __div__(Scalar s)
66 {
67  return (*self) / s;
68 }
69 
__pow__(const Scalar s)70 Distribution __pow__(const Scalar s) { return self->pow(s); }
71 
__rdiv__(Scalar s)72 Distribution __rdiv__(Scalar s) { return self->inverse() * s; }
73 
__rtruediv__(Scalar s)74 Distribution __rtruediv__(Scalar s) { return self->inverse() * s; }
75 
76 #if SWIG_VERSION < 0x030011
__truediv__(Scalar s)77   Distribution __truediv__(Scalar s) { return (*self) / s; }
78 #endif
79 
80 } // class Distribution
81 } // namespace OT
82 
83 %pythoncode %{
84 from openturns.typ import Interval
85 
86 class PythonDistribution(object):
87     """
88     Allow to override Distribution from Python.
89 
90     Parameters
91     ----------
92     dim : positive int
93         the distribution dimension
94 
95     Examples
96     --------
97     Not useful on its own, see the examples section on how to inherit from it.
98     """
99     def __init__(self, dim=0):
100         """
101         Constructor.
102         """
103         self.__dim = dim
104 
105     def __str__(self):
106         return 'PythonDistribution -> #%d' % self.__dim
107 
108     def __repr__(self):
109         return self.__str__()
110 
111     def getDimension(self):
112         """
113         Dimension accessor.
114         """
115         return self.__dim
116 
117     def computeCDF(self, X):
118         """
119         CDF accessor.
120         """
121         raise RuntimeError('You must define a method computeCDF(x) -> cdf, where cdf is a float')
122 
123 
124 class SciPyDistribution(PythonDistribution):
125     """
126     Allow to override Distribution from a scipy distribution.
127 
128     Parameters
129     ----------
130     dist : a scipy.stats distribution
131         The distribution to wrap
132 
133     Examples
134     --------
135     >>> import openturns as ot
136     >>> import scipy.stats as st  # doctest: +SKIP
137     >>> scipy_dist = st.johnsonsu(2.55, 2.25)  # doctest: +SKIP
138     >>> distribution = ot.Distribution(ot.SciPyDistribution(scipy_dist))  # doctest: +SKIP
139     >>> distribution.getRealization()  # doctest: +SKIP
140     """
141     def __init__(self, dist):
142         super(SciPyDistribution, self).__init__(1)
143         if dist.__class__.__name__ != 'rv_frozen':
144             raise TypeError('Argument is not a scipy distribution')
145         self._dist = dist
146 
147         # compute range
148         from openturns import ResourceMap
149         cdf_epsilon = ResourceMap.GetAsScalar('Distribution-DefaultCDFEpsilon')
150         lb = dist.ppf(0.0)
151         ub = dist.ppf(1.0)
152         flb = lb != float('-inf')
153         fub = ub != float('+inf')
154         if not flb:
155             lb = dist.ppf(cdf_epsilon)
156         if not fub:
157             ub = dist.ppf(1.0 - cdf_epsilon)
158         self.__range = Interval([lb], [ub])
159         self.__range.setFiniteLowerBound([int(flb)])
160         self.__range.setFiniteUpperBound([int(fub)])
161 
162     def getRange(self):
163         return self.__range
164 
165     def getRealization(self):
166         rvs = self._dist.rvs()
167         return [rvs]
168 
169     def getSample(self, size):
170         rvs = self._dist.rvs(size)
171         return rvs.reshape(size, 1)
172 
173     def computePDF(self, X):
174         pdf = self._dist.pdf(X[0])
175         return pdf
176 
177     def computeCDF(self, X):
178         cdf = self._dist.cdf(X[0])
179         return cdf
180 
181     def getMean(self):
182         mean = float(self._dist.stats('m'))
183         return [mean]
184 
185     def getStandardDeviation(self):
186         var = float(self._dist.stats('v'))
187         std = var ** 0.5
188         return [std]
189 
190     def getSkewness(self):
191         skewness = float(self._dist.stats('s'))
192         return [skewness]
193 
194     def getKurtosis(self):
195         kurtosis = float(self._dist.stats('k')) + 3.0
196         return [kurtosis]
197 
198     def getMoment(self, n):
199         moment = self._dist.moment(n)
200         return [moment]
201 
202     def computeScalarQuantile(self, p, tail=False):
203         q = self._dist.ppf(1.0 - p if tail else p)
204         return q
205 
206     def computeQuantile(self, prob, tail=False):
207         p = 1.0 - prob if tail else prob
208         q = self._dist.ppf(p)
209         return [q]
210 
211     def getParameter(self):
212         return self._dist.args
213 
214     def setParameter(self, params):
215         size = len(self._dist.args)
216         if len(params) != size:
217             raise ValueError('Parameter must be of size %d' % size)
218         self._dist.args = params
219 
220     def getParameterDescription(self):
221         size = len(self._dist.args)
222         return ['parameter' + str(i + 1) for i in range(size)]
223 
224 
225 class ChaospyDistribution(PythonDistribution):
226     """
227     Allow to override Distribution from a chaospy distribution.
228 
229     Parameters
230     ----------
231     dist : a chaospy distribution
232         The distribution to wrap. It is currently limited to stochastically
233         independent distributions as chaopy distributions doesn't implement CDF
234         computation for dependencies.
235 
236     Examples
237     --------
238     >>> import openturns as ot
239     >>> import chaospy as cp  # doctest: +SKIP
240     >>> chaospy_dist = cp.J(cp.Triangular(1.0, 2.0, 3.0), cp.F(4.0, 5.0))  # doctest: +SKIP
241     >>> distribution = ot.Distribution(ot.ChaospyDistribution(chaospy_dist))  # doctest: +SKIP
242     >>> distribution.getRealization()  # doctest: +SKIP
243     """
244     def __init__(self, dist):
245         super(ChaospyDistribution, self).__init__(len(dist))
246         from chaospy import Iid, J, __version__
247         independent = len(dist) == 1
248         independent |= isinstance(dist, Iid)
249         if __version__ < '4.0.0':
250             from chaospy import get_dependencies
251             independent |= isinstance(dist, J) and not get_dependencies(*dist)
252         else:
253             independent |= not dist.stochastic_dependent
254         if not independent:
255             raise Exception(
256                 "Dependent chaospy distributions doesn't implement CDF computation")
257         self._dist = dist
258         self.__range = Interval(dist.lower, dist.upper)
259 
260     def getRange(self):
261         return self.__range
262 
263     def getRealization(self):
264         rvs = self._dist.sample(1).flatten()
265         return rvs
266 
267     def getSample(self, size):
268         rvs = self._dist.sample(size).T
269         return rvs.reshape(size, len(self._dist))
270 
271     def computePDF(self, X):
272         pdf = self._dist.pdf(X)
273         return pdf
274 
275     def computeCDF(self, X):
276         cdf = self._dist.cdf(X)
277         return cdf
278 
279     def getMean(self):
280         import chaospy as cp
281         mean = cp.E(self._dist).reshape([len(self._dist)])
282         return mean
283 
284     def getStandardDeviation(self):
285         import chaospy as cp
286         std = cp.Std(self._dist).reshape([len(self._dist)])
287         return std
288 
289     def getSkewness(self):
290         import chaospy as cp
291         skewness = cp.Skew(self._dist).reshape([len(self._dist)])
292         return skewness
293 
294     def getKurtosis(self):
295         import chaospy as cp
296         kurtosis = cp.Kurt(self._dist).reshape([len(self._dist)]) + 3.0
297         return kurtosis
298 
299     def getMoment(self, n):
300         moment = self._dist.mom([n] * len(self._dist))
301         return moment
302 
303     def computeScalarQuantile(self, p, tail=False):
304         if len(self._dist) > 1:
305             raise Exception(
306                 "Multivariate distribution doesn't implement scalar quantile")
307         q = self._dist.inv(1 - p if tail else p)
308         return float(q)
309 
310     def computeQuantile(self, prob, tail=False):
311         p = 1.0 - prob if tail else prob
312         q = self._dist.inv(p).flatten()
313         return q
314 %}
315