• Gurobi Staff

Hi WI,

Thanks for the response. Sure, I get that your decision variables represent the Euclidean distance between pairs of points (let us refer to them as $$x$$ for simplicity) on a grid of 1 by 1 with lower and upper bounds 0 and $$\sqrt{2}$$. And there are binary decision variables in the objective function. However, I am still not clear why you want to normalize the variables $$x$$ in the objective function and how they are connected to the binary decision variables.

Anyways, assuming $$x_{\tiny \mbox{min}}$$ and $$x_{\tiny \mbox{max}}$$ are decision variables and are not the lower and upper bounds of the variables $$x$$, you need to do the following:

• Define a new continuous variable $$x_{\tiny \mbox{min}}$$ and then use the Gurobi min_() general constraint helper API to define $$x_{\tiny \mbox{min}} = \min_{i} x_i$$
• Define a new continuous variable $$x_{\tiny \mbox{max}}$$ and then use the Gurobi max_() general constraint helper API to define $$x_{\tiny \mbox{max}} = \max_{i} x_i$$
• Define new continuous variables $$y$$ between 0 and 1 and then use the Model.addQConstr() method to model $$y_i (x_{\tiny \mbox{max}} - x_{\tiny \mbox{min}}) = x_i -x_{\tiny \mbox{min}}$$ for all $$i$$. This will make your problem non-convex and you would need to use NonConvex=2 setting to solve the problem

Best regards,

Maliheh

• Gurobi Staff

Hi WI,

You need a few changes. Please see below.

import gurobipy as gpfrom gurobipy import GRBfrom math import sqrtif __name__ == "__main__":     model = gp.Model("name")          Var = model.addVars(len(A), lb=0, ub=sqrt(2), vtype=GRB.CONTINUOUS, name="var")     xmin = model.addVar(lb=0, ub=sqrt(2), vtype=GRB.CONTINUOUS, name="xmin")     xmax = model.addVar(lb=0, ub=sqrt(2), vtype=GRB.CONTINUOUS, name="xmax")     y = model.addVars(len(A), lb=0, ub=1, vtype=GRB.CONTINUOUS, name="y")     model.addConstr(xmin == gp.min_(Var), name="min") # [*]     model.addConstr(xmax == gp.max_(Var), name="max") # [*]     for i in range(len(A)):         model.addConstr(             gp.quicksum(compute_value(A[i], B[j]) forjinrange(len(B))) == Var[i],             name=f"var_{i}",         )         model.addQConstr(y[i] * (xmax - xmin) == Var[i] - xmin, name=f"normalize_{i}"
# [*]: Edited

Best regards,
Maliheh
• Gurobi Staff

Hi WI,

Since $$\texttt{Var_min}$$ and $$\texttt{Var_max}$$ are variables in your model, normalizing the decision variables as $$(\texttt{Var[i]} - \texttt{Var_min})/(\texttt{Var_max} - \texttt{Var_min})$$ will make the problem non-linear. Do you really need to do this? Have you considered defining your decision variables to be between 0 and 1 right from the start? For example, instead of decision variable to represent the amount of money invested in each asset, you can define them to represent the fraction of the total budget invested in each asset. This way, you do not need to map the decision variables to values between 0 and 1.

What the decision variables and the objective function represent in your model in English?

Best regards,

Maliheh

Hi Maliheh,
The decision variables in the objective function are a binary type (0 or 1), and the variable Var is a Euclidean distance between points in a graph that has the x and y-axis bounded between 0 and 1.

So I should proceed as:

model = gp.Model('name')Var = m.addVars(len(A), vtype=GRB.CONTINUOUS, name='var')xmin=m.addVars(1, vtype=GRB.CONTINUOUS, name='xmin')xmax=m.addVars(1, vtype=GRB.CONTINUOUS, name='xmax')y=m.addVars(len(A),ub=1, vtype=GRB.CONTINUOUS, name='xmin')for i in range(len(A)):m.addConstr(gp.quicksum(compute_value(A[i],B[j]) for j in range(len(B)) == Var[i], name=f'var_{i}')xmin=min(Var)xmax=min(Var)m.addQConstr(y[i]=x[i]-xmin/(xmax-xmin) for i in Var)

then I utilize y in the objective function instead of Var, then:

m.params.NonConvex=2m.optimize()

Is that right?
And thank you for your help.

Thank you Maliheh

When runing the code it raises an error:

TypeError: unsupported operand type(s) for -: 'GenExprMax' and 'GenExprMin'

at this line:

m.addQConstr(y[i]*(xmax - xmin) == h[i] - xmin, name=f"normalize_{i}")

Any idea how to fix it?

• Gurobi Staff

Hi WI,

The error means that the subtraction is not supported for the general expressions, i.e., we cannot subtract $$x_{\small\mbox{min}}$$ from $$x_{\small\mbox{max}}$$. We likely need additional auxiliary variables to model this.

Could you please post the snippet that you are running such that I can reproduce the error? If the snippet is too long, you can share the file using Dropbox, Google Drive, or OneDrive.

Best regards,

Maliheh

This code generates the same error:

A=[0,4,3,2,8]B=[7,9,4,5,2]model = gp.Model("name")Var = model.addVars(5, lb=0, ub=sqrt(2), vtype=GRB.CONTINUOUS, name="var")xmin = model.addVar(lb=0, ub=sqrt(2), vtype=GRB.CONTINUOUS, name="xmin")xmax = model.addVar(lb=0, ub=sqrt(2), vtype=GRB.CONTINUOUS, name="xmax")y = model.addVars(5, lb=0, ub=1, vtype=GRB.CONTINUOUS, name="y")xmin = gp.min_(Var)xmax = gp.max_(Var)for i in range(5):  model.addConstr(gp.quicksum(A[i]*B[j] for j in range(5)) == Var[i], name=f"var_{i}")  model.addQConstr(y[i] * (xmax - xmin) == Var[i] - xmin, name=f"normalize_{i}")

And thank you for your comprehension

• Gurobi Staff

Hi WI,

Please see the snippet edited above. Specifically, below needs to change from:

xmin = gp.min_(Var)xmax = gp.max_(Var)

to:

model.addConstr(xmin == gp.min_(Var), name="min") model.addConstr(xmax == gp.max_(Var), name="max")

Your snippet should build the model without the previous error now.

Best regards,

Maliheh

Thank you very much Maliheh.