I'm trying to optimize a 52x5 matrix to maximize a return value y
. I first flatten the matrix into an array of 260 elements, then apply Scipy optimize and mystic. However, the max_limit
constraint keeps getting violated?
Please see the main part of the code below:
max_limit = 2000
def constraint_func():
var_number = ['x'+str(i) for i in range(260)]
constraint = ' + '.join(var_number) + f' <= {max_limit}'
return constraint
eqns = ms.simplify(constraint_func(), all=True)
constraint = ms.generate_constraint(ms.generate_solvers(eqns), join=my.constraints.and_)
def objective_func(x):
constraint_vars = constraint(x)
y = -model.func(constraint_vars)
return y
initial_matrix = [random.randint(0,3) for i in range(260)]
output = so.minimize(objective_func, initial_matrix, method='SLSQP',bounds=[(0,max_limit)]*260 ,tol=0.01, options={ 'disp': True, 'maxiter':100})
I'm the
mystic
author. Your code is incomplete above, so I'm going to make some assumptions to produce a full working example.I'm guessing that the constraints are not getting violated, I'm guessing that you are looking at the result from the
scipy.optimize
result object, which is preserving the unconstrained value of x.Let's use a simple model function that's just the sum of the parameter vector. I also note that you only have a single constraint (i.e. sum(x) <= 2000), so you don't need
all=True
orjoin=and_
in the constraints definition. It doesn't hurt to keep them, however.The problem is that
scipy
considers yourobjective_func
in the result object, so that means it tracksy
for a givenx
, defined byy = objective_func(x)
, and as is, your constrainedx
that you are interested in tracking is only known insideobjective_func
asconstraint_vars
. So, if you are ok with being a little inefficient (i.e. being a bit lazy and doing a minimal rewrite of your code), then we can use one of mystic's monitors to get the value ofconstraint_vars
. I'm going to use a callback to do that, so we capture the desired values after each iteration.We can see the results being printed to the verbose monitor, and we can see the difference extracting the results from the monitor, as opposed to from the result object.
The constrained solution is found at
mon.x[-1]
.