1 // -*- C++ -*-
2 /**
3 * @brief This class binds a Python object to an OpenTURNS' RandomVector
4 *
5 * Copyright 2005-2021 Airbus-EDF-IMACS-ONERA-Phimeca
6 *
7 * This library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include "openturns/PythonRandomVector.hxx"
23 #include "openturns/OSS.hxx"
24 #include "openturns/Description.hxx"
25 #include "openturns/PythonWrappingFunctions.hxx"
26 #include "openturns/PersistentObjectFactory.hxx"
27 #include "openturns/Exception.hxx"
28
29 BEGIN_NAMESPACE_OPENTURNS
30
31
32 CLASSNAMEINIT(PythonRandomVector)
33
34 static const Factory<PythonRandomVector> Factory_PythonRandomVector;
35
36
37
38 /* Default constructor */
PythonRandomVector()39 PythonRandomVector::PythonRandomVector()
40 : RandomVectorImplementation(),
41 pyObj_(0)
42 {
43 // Nothing to do
44 }
45
46
47 /* Constructor from Python object*/
PythonRandomVector(PyObject * pyObject)48 PythonRandomVector::PythonRandomVector(PyObject * pyObject)
49 : RandomVectorImplementation(),
50 pyObj_(pyObject)
51 {
52 if ( !PyObject_HasAttrString( pyObj_, const_cast<char *>("getRealization") ) ) throw InvalidArgumentException(HERE) << "Error: the given object does not have a getRealization() method.";
53
54 Py_XINCREF( pyObj_ );
55
56 // Set the name of the object as its Python classname
57 ScopedPyObjectPointer cls(PyObject_GetAttrString ( pyObj_,
58 const_cast<char *>( "__class__" ) ));
59 ScopedPyObjectPointer name(PyObject_GetAttrString( cls.get(),
60 const_cast<char *>( "__name__" ) ));
61
62 setName( checkAndConvert< _PyString_, String >(name.get()) );
63
64 const UnsignedInteger dimension = getDimension();
65 Description description(dimension);
66 ScopedPyObjectPointer desc(PyObject_CallMethod ( pyObj_,
67 const_cast<char *>( "getDescription" ),
68 const_cast<char *>( "()" ) ));
69 if ( ( desc.get() != NULL )
70 && PySequence_Check( desc.get() )
71 && ( PySequence_Size( desc.get() ) == static_cast<SignedInteger>(dimension) ) )
72 {
73 description = convert< _PySequence_, Description >( desc.get() );
74 }
75 else for (UnsignedInteger i = 0; i < dimension; ++i) description[i] = (OSS() << "x" << i);
76 setDescription(description);
77 }
78
79 /* Virtual constructor */
clone() const80 PythonRandomVector * PythonRandomVector::clone() const
81 {
82 return new PythonRandomVector(*this);
83 }
84
85 /* Copy constructor */
PythonRandomVector(const PythonRandomVector & other)86 PythonRandomVector::PythonRandomVector(const PythonRandomVector & other)
87 : RandomVectorImplementation(other),
88 pyObj_()
89 {
90 ScopedPyObjectPointer pyObjClone(deepCopy(other.pyObj_));
91 pyObj_ = pyObjClone.get();
92 Py_XINCREF(pyObj_);
93 }
94
95 /* Copy assignment operator */
operator =(const PythonRandomVector & rhs)96 PythonRandomVector & PythonRandomVector::operator=(const PythonRandomVector & rhs)
97 {
98 if (this != &rhs)
99 {
100 RandomVectorImplementation::operator=(rhs);
101 ScopedPyObjectPointer pyObjClone(deepCopy(rhs.pyObj_));
102 pyObj_ = pyObjClone.get();
103 Py_XINCREF(pyObj_);
104 }
105 return *this;
106 }
107
108 /* Destructor */
~PythonRandomVector()109 PythonRandomVector::~PythonRandomVector()
110 {
111 Py_XDECREF(pyObj_);
112 }
113
114 /* Comparison operator */
operator ==(const PythonRandomVector &) const115 Bool PythonRandomVector::operator ==(const PythonRandomVector & ) const
116 {
117 return true;
118 }
119
120 /* String converter */
__repr__() const121 String PythonRandomVector::__repr__() const
122 {
123 OSS oss;
124 oss << "class=" << PythonRandomVector::GetClassName()
125 << " name=" << getName()
126 << " description=" << getDescription();
127 return oss;
128 }
129
130 /* String converter */
__str__(const String &) const131 String PythonRandomVector::__str__(const String & ) const
132 {
133 OSS oss;
134 oss << "class=" << PythonRandomVector::GetClassName()
135 << " name=" << getName();
136 return oss;
137 }
138
139
140 /* Here is the interface that all derived class must implement */
141
142
143 /* Accessor for input point dimension */
getDimension() const144 UnsignedInteger PythonRandomVector::getDimension() const
145 {
146 ScopedPyObjectPointer result(PyObject_CallMethod ( pyObj_,
147 const_cast<char *>( "getDimension" ),
148 const_cast<char *>( "()" ) ));
149 if ( result.isNull() )
150 {
151 handleException();
152 }
153
154 UnsignedInteger dim = convert< _PyInt_, UnsignedInteger >( result.get() );
155 return dim;
156 }
157
getRealization() const158 Point PythonRandomVector::getRealization() const
159 {
160 ScopedPyObjectPointer result(PyObject_CallMethod ( pyObj_,
161 const_cast<char *>( "getRealization" ),
162 const_cast<char *>( "()" ) ));
163 if ( result.isNull() )
164 {
165 handleException();
166 }
167 Point point(convert<_PySequence_, Point>(result.get()));
168 return point;
169 }
170
171
172 /* Numerical sample accessor */
getSample(const UnsignedInteger size) const173 Sample PythonRandomVector::getSample(const UnsignedInteger size) const
174 {
175 Sample sample;
176
177 if ( PyObject_HasAttrString( pyObj_, const_cast<char *>("getSample") ) )
178 {
179 ScopedPyObjectPointer methodName(convert< String, _PyString_>( "getSample" ));
180 ScopedPyObjectPointer sizeArg(convert< UnsignedInteger, _PyInt_ >(size));
181 ScopedPyObjectPointer result(PyObject_CallMethodObjArgs( pyObj_,
182 methodName.get(),
183 sizeArg.get(), NULL ));
184 if ( result.get() )
185 {
186 sample = convert<_PySequence_, Sample>(result.get());
187 if (sample.getSize() != size) throw InvalidDimensionException(HERE) << "Sample returned by PythonRandomVector has incorrect size. Got " << sample.getSize() << ". Expected" << size;
188 }
189 }
190 else
191 {
192 sample = RandomVectorImplementation::getSample(size);
193 }
194 return sample;
195 }
196
197
198 /* Mean accessor */
getMean() const199 Point PythonRandomVector::getMean() const
200 {
201 ScopedPyObjectPointer result(PyObject_CallMethod ( pyObj_,
202 const_cast<char *>( "getMean" ),
203 const_cast<char *>( "()" ) ));
204 if ( result.isNull() )
205 {
206 handleException();
207 }
208
209 Point mean(convert<_PySequence_, Point>(result.get()));
210 if (mean.getDimension() != getDimension()) throw InvalidDimensionException(HERE) << "Mean returned by PythonRandomVector has incorrect dimension. Got " << mean.getDimension() << ". Expected" << getDimension();
211 return mean;
212 }
213
214 /* Covariance accessor */
getCovariance() const215 CovarianceMatrix PythonRandomVector::getCovariance() const
216 {
217 ScopedPyObjectPointer result(PyObject_CallMethod ( pyObj_,
218 const_cast<char *>( "getCovariance" ),
219 const_cast<char *>( "()" ) ));
220 if ( result.isNull() )
221 {
222 handleException();
223 }
224
225 CovarianceMatrix covariance(convert<_PySequence_, CovarianceMatrix>(result.get()));
226 if (covariance.getDimension() != getDimension()) throw InvalidDimensionException(HERE) << "Covariance matrix returned by PythonRandomVector has incorrect dimension. Got " << covariance.getDimension() << ". Expected" << getDimension();
227
228 return covariance;
229 }
230
isEvent() const231 Bool PythonRandomVector::isEvent() const
232 {
233 if (PyObject_HasAttrString(pyObj_, const_cast<char *>("isEvent")))
234 {
235 ScopedPyObjectPointer result(PyObject_CallMethod ( pyObj_,
236 const_cast<char *>( "isEvent" ),
237 const_cast<char *>( "()" ) ));
238 if ( result.isNull() )
239 {
240 handleException();
241 }
242
243 Bool isEvent = checkAndConvert<_PyBool_, Bool>(result.get());
244 return isEvent;
245 }
246 else
247 {
248 return RandomVectorImplementation::isEvent();
249 }
250 }
251
252 /* Parameter accessor */
getParameter() const253 Point PythonRandomVector::getParameter() const
254 {
255 if (PyObject_HasAttrString(pyObj_, const_cast<char *>("getParameter")))
256 {
257 ScopedPyObjectPointer callResult(PyObject_CallMethod( pyObj_,
258 const_cast<char *>( "getParameter" ),
259 const_cast<char *>( "()" ) ));
260 if (callResult.isNull())
261 {
262 handleException();
263 }
264 Point parameter(convert< _PySequence_, Point >(callResult.get()));
265 return parameter;
266 }
267 else
268 {
269 // RandomVectorImplementation::getParameter throws
270 return Point();
271 }
272 }
273
274 /* Parameter accessor */
setParameter(const Point & parameter)275 void PythonRandomVector::setParameter(const Point & parameter)
276 {
277 if (PyObject_HasAttrString(pyObj_, const_cast<char *>("setParameter")))
278 {
279 ScopedPyObjectPointer methodName(convert< String, _PyString_ >("setParameter"));
280 ScopedPyObjectPointer parameterArg(convert< Point, _PySequence_ >(parameter));
281 ScopedPyObjectPointer callResult(PyObject_CallMethodObjArgs( pyObj_,
282 methodName.get(),
283 parameterArg.get(), NULL));
284 if (callResult.isNull())
285 {
286 handleException();
287 }
288 }
289 }
290
291 /* Parameter description accessor */
getParameterDescription() const292 Description PythonRandomVector::getParameterDescription() const
293 {
294 if (PyObject_HasAttrString(pyObj_, const_cast<char *>("getParameterDescription")))
295 {
296 ScopedPyObjectPointer callResult(PyObject_CallMethod( pyObj_,
297 const_cast<char *>( "getParameterDescription" ),
298 const_cast<char *>( "()" ) ));
299 if (callResult.isNull())
300 {
301 handleException();
302 }
303 Description parameterDescription(convert< _PySequence_, Description >(callResult.get()));
304 return parameterDescription;
305 }
306 else
307 {
308 // RandomVectorImplementation::getParameterDescription throws
309 return Description();
310 }
311 }
312
313 /* Method save() stores the object through the StorageManager */
save(Advocate & adv) const314 void PythonRandomVector::save(Advocate & adv) const
315 {
316 RandomVectorImplementation::save( adv );
317
318 pickleSave(adv, pyObj_);
319 }
320
321
322 /* Method save() reloads the object from the StorageManager */
load(Advocate & adv)323 void PythonRandomVector::load(Advocate & adv)
324 {
325 RandomVectorImplementation::load( adv );
326
327 pickleLoad(adv, pyObj_);
328 }
329
330
331 END_NAMESPACE_OPENTURNS
332