I have a class XYZ()
with methods build
and Predict
. I have another class BuildSurrogate()
which has an attribute SurrogateClass
pointing to an object of type class XYZ()
. A method of SurrogateClass
is _minima
which is defined below.
class XYZ():
...
def build(self):
...
def Predict(self):
...
class BuildSurrogate():
def __init__(self, args):
self.SurrogateClass = XYZ(*args)
def _minima(self):
"""
This returns the minima of the surrogate
"""
x0 = copy(self.x0_)
solution = minimize(fun=self.SurrogateClass.Predict, x0=x0, args=args, method='Nelder-Mead')# x0=x0, options={'xtol':1e-5,'ftol':1e-5})
return solution
The script raises an error:
Traceback (most recent call last):
File "/path/to/optiblade/Optimizer/SurrogateModel.py", line 1067, in <module>
print SurrogateObj._minima()
File "/path/to/optiblade/Optimizer/SurrogateModel.py", line 1006, in _minima
solution = minimize(fun=self.SurrogateClass.Predict, x0=x0, method='Nelder-Mead')# x0=x0, options={'xtol':1e-5,'ftol':1e-5})
File "/usr/local/lib/python2.7/dist-packages/scipy/optimize/_minimize.py", line 435, in minimize
return _minimize_neldermead(fun, x0, args, callback, **options)
File "/usr/local/lib/python2.7/dist-packages/scipy/optimize/optimize.py", line 439, in _minimize_neldermead
fsim[0] = func(x0)
ValueError: setting an array element with a sequence.
I presume this error is raised because self
where self = self.SurrogateClass
is to be passed to Predict
. Do I have to change my code structure or is there a way I can solve the above problem without changing my code structure?
Starting with an example for minimize
documentation:
In [183]: x0 = [1.3, 0.7, 0.8, 1.9, 1.2]
In [185]: optimize.minimize(optimize.rosen, x0, method='Nelder-Mead', tol=1e-6)
Out[185]:
final_simplex: (array([[ 1.00000002, 1.00000002, 1.00000007, 1.00000015, 1.00000028],
...
x: array([ 1.00000002, 1.00000002, 1.00000007, 1.00000015, 1.00000028])
Define a callable class that does the same thing:
In [191]: class Class1(object):
def __init__(self):
pass
def __call__(self,args):
return optimize.rosen(args)
In [190]: optimize.minimize(Class1(), x0, method='Nelder-Mead', tol=1e-6)
A Class1
object is callable, so I can use it exactly as though I had defined a rosen
method
In [191]: Class1()(x0)
Out[191]: 848.22000000000003
I could have defined it this way:
In [192]: class Class2(object):
def rosen(self,args):
return optimize.rosen(args)
In [193]: optimize.minimize(Class2().rosen, x0, method='Nelder-Mead', tol=1e-6)
In [194]: Class2().rosen(x0)
Out[194]: 848.22000000000003
Adding in class layer shouldn't make a difference, just so long as the first argument to minimize
is a function that returns a value when called with x0
.
In your case you just need to define:
class XYZ(object):
def predict(self, args):
return optimize.rosen(args)
class BuildSurrogate(object):
def __init__(self):
self.surrogateObj = XYZ()
def minima(self,x0):
return optimize.minimize(self.surrogateObj.predict, x0, method='Nelder-Mead', tol=1e-6)
And use:
BuildSurrogate().minima(x0)
Or something comparable.
I could have also defined self.SurrogateClass=XYZ
and called self.SurrogateClass().predict
. As long as predict
is a method of the XYZ
class I have to create an XYZ()
object before using it.