I have tried to optimize smooth objective (cost function) with tough non-linear constraints using diffevo algorithm. And I cant understand how to define such parameters as: constraints, bounds and init vectors.
My obj - just a sum of budget:
def minimize_me_reach(budgetA, *args):
# start = time.time()
# budget = args[0]
# # trp_total = args[0]
# freq = args[1]
# DF_GROUP = args[2]
# MEMBER = args[3]
# DF_GROUP['bud_part'] = 0
# DF_GROUP.loc[DF_GROUP['Prime'] == 1, 'bud_part'] = budgetA
# DF_GROUP.loc[DF_GROUP['Prime'] == 2, 'bud_part'] = budgetA
# DF_GROUP['budget_total'] = DF_GROUP['bud_part'] * budget
# execution of above program is :",(end - start), "sec")
return np.nan_to_num(budgetA).sum()
My constraint - 1 for now. Planing to add some more constraints
def constr_reach(x_all):
#budget = x_all[-1]
x = x_all[:-1]
print(DF_GROUP.info())
DF_GROUP['bud_part'] = 0
print(MEMBER.info())
DF_GROUP.loc[DF_GROUP['Prime'] == 1, 'bud_part'] = x
DF_GROUP.loc[DF_GROUP['Prime'] == 2, 'bud_part'] = x
DF_GROUP['budget_total'] = DF_GROUP['bud_part']
DF_GROUP['trp'] = DF_GROUP['budget_total'] / DF_GROUP['tcpp'] * DF_GROUP['trp_mult']
DF_GROUP['Q'] = pd.DataFrame([DF_GROUP['trp'] / DF_GROUP['Tvr_Origin'], DF_GROUP['COUNT'] - 1]).min()
test1 = tv_planet.calc_reach(MEMBER, DF_GROUP)
sOPT = test1.loc[freq - 1, '%']
return sOPT
I tried to optimize (minimize) it like this
stepmon = VerboseMonitor(50)
solver = DifferentialEvolutionSolver2(dim=53,NP=len(init_bud))
solver.SetConstraints(constr_reach)
#solver.SetInitialPoints(x0=x0, radius=0.1)
solver.SetGenerationMonitor(stepmon)
solver.enable_signal_handler()
solver.Solve(minimize_me_reach, termination=VTR(0.01), strategy=Best1Exp, \
CrossProbability=1.0, ScalingFactor=0.9, \
disp=True, ExtraArgs=(reach, freq, DF_GROUP, MEMBER, days))
result = solver.Solution()
iterations = len(stepmon)
cost = stepmon.y[-1]
print("Generation %d has best Chi-Squared: %f" % (iterations, cost))
print(result)
And this
result = diffev(minimize_me_reach, x0=x0, npop=len(init_bud), args=(reach, freq, DF_GROUP, MEMBER, days),
bounds=my_bounds, ftol=0.05, gtol=100,
maxiter=100, maxfun=None, cross=0.9, scale=0.8, full_output=False,
disp=1, retall=0, callback=None, strategy=Best1Exp, constraints=constr_reach)
But I have always encountered errors relative to constraint parameter. For instance.
File "d:\tvplan\tv-planner-backend\TV_PLANER2\top_to_bottom.py", line 1179, in optimizeReach_DE
solver.Solve(minimize_me_reach, termination=VTR(0.01), strategy=Best1Exp, \
File "C:\Users\Mi\AppData\Local\Programs\Python\Python310\lib\site-packages\mystic\differential_evolution.py", line 661, in Solve
super(DifferentialEvolutionSolver2, self).Solve(cost, termination,\
File "C:\Users\Mi\AppData\Local\Programs\Python\Python310\lib\site-packages\mystic\abstract_solver.py", line 1180, in Solve
self._Solve(cost, ExtraArgs, **settings)
File "C:\Users\Mi\AppData\Local\Programs\Python\Python310\lib\site-packages\mystic\abstract_solver.py", line 1123, in _Solve
stop = self.Step(**settings) #XXX: remove need to pass settings?
File "C:\Users\Mi\AppData\Local\Programs\Python\Python310\lib\site-packages\mystic\abstract_solver.py", line 1096, in Step
self._Step(**kwds) #FIXME: not all kwds are given in __doc__
File "C:\Users\Mi\AppData\Local\Programs\Python\Python310\lib\site-packages\mystic\differential_evolution.py", line 552, in _Step
self.trialSolution[candidate][:] = constraints(self.trialSolution[candidate])
TypeError: can only assign an iterable
I also tried to optimize it with set of SciPy algorithms. But had always failed. Could someone provide me example with optimization smooth function wit non-linear constraints on Mystic diffevo algorithms? Or any advise how to define my constraint to reach the solution?
I'm the author of mystic
. First, it seems that DF_GROUP
is not defined inside of constr_reach
, so it may fail with a NameError
. Regardless, your constraints function seems to not meet the interface requirements.
We define an objective as y = f(x)
, where x
is a list and y
is a scalar. You can do multi-objective optimization, but let's keep it simple. Soft constraints (i.e. a penalty) are defined as y' = p(x)
where x
is a list, and y'
is a scalar penalty that is representative of the amount that the soft constraint is violated. Hard constraints (i.e. operators / transforms / constraints) are defined as x
= c(x)where
xand
x'` are a list representing the inputs.
An objective that is both hard and soft constrained (internally to mystic) looks like this:
y' = f(c(x)) + p(x)
Thus, c
is applied to transform the inputs (critically, so it produces a list of inputs where the constraint has been applied), and penalty p
is then added to the cost of the objective to penalize where the soft constraints are violated.
There are maybe 30 examples of applying nonlinear and other complex constraints here: https://github.com/uqfoundation/mystic/tree/master/examples2
There are several examples with even more complex constraints examples (i.e. moment constraints) here: https://github.com/uqfoundation/mystic/tree/master/examples3
mystic
provides several pre-built constraints functions that you can use to help you construct your own constraint function, if you like. They are, for the most part, in:
https://github.com/uqfoundation/mystic/blob/master/mystic/constraints.py and a few more are in: https://github.com/uqfoundation/mystic/blob/master/mystic/tools.py
A simple, but instructive, example, from the mystic.constraints
doc is:
>>> @integers()
... def identity(x):
... return x
...
>>> identity([0.123, 1.789, 4.000])
[0, 2, 4]
>>> @integers(ints=float, index=(0,3,4))
... def squared(x):
... return [i**2 for i in x]
...
>>> squared([0.12, 0.12, 4.01, 4.01, 8, 8])
[0.0, 0.0144, 16.080099999999998, 16.0, 64.0, 64.0]