Skip to main content

How to Define a Constraint for Calculating the Maximum of Two Multi-Dimensional Variables in Gurobi

Answered

Comments

5 comments

  • Official comment
    Simranjit Kaur
    • Gurobi Staff
    This post is more than two years old. Some information may not be up to date. For current information, please check the Gurobi Documentation or Knowledge Base. If you need more help, please create a new post in the community forum, or try Gurobot, our chatbot interface offering instant, expert-level support.
  • Maliheh Aramon
    • Gurobi Staff

    Hi Amir, 

    It is possible to use the max_() helper function regardless of the variables dimension and there is no need for the variables to have similar dimensions. See the code snippet below:

    import gurobipy as gp

    model = gp.Model()

    M, R = 5, 4
    x1 = model.addVars(M, R, name="x1")
    x2 = model.addVars(M, R, name="x2")
    x3 = model.addVars(M, R, name="x3")

    model.addConstrs((x3[m,r] == gp.max_(x1[m,r], x2[m,r]) for m in range(M) for r in range(R)), name="c_max")

    Could you please post a small working example so that we can reproduce the error you see?

    Best regards,

    Maliheh

    0
  • Amir Fayaz Heidari
    • Gurobi-versary
    • Conversationalist
    • First Question

    Thanks for your response.

    Could you please check the code below? It works correctly without the constraint regarding the max function.

    " model.addConstrs((con_SCG[m,r] == gp.max_(x_SCG[m,r], min_con_SCG[m,r]) for m in range(M) for r in range(R)), name="c_max") "

    However, when I deactivate it (excluded from the optimization problem), I get the error "GurobiError: Invalid data in vars array"

    import gurobipy as gp
    from gurobipy import *
    import numpy as np

    # Create a new model
    model = Model()

    M = 2
    R = 2
    N = 2

    P_tot = np.zeros((M,R))
    P_tot[0,0] = 5000
    P_tot[0,1] = 2000
    P_tot[1,0] = 3000
    P_tot[1,1] = 1000

    min_con_SCG = np.zeros((M,R))
    min_con_SCG[0,0] = 200
    min_con_SCG[0,1] = 200
    min_con_SCG[1,0] = 300
    min_con_SCG[1,1] = 300


    # Define decision variables
    x_SCG = model.addVars(M,R, lb=0.0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="x_SCG")
    x_ON_SCG = model.addVars(M,R, lb=0.0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="x_ON_SCG")
    x_act_SCG = model.addVars(M,R, lb=0.0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="x_act_SCG")
    con_SCG = model.addVars(M,R, lb=0.0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="con_SCG")
    Total_con_SCG = model.addVars(R, lb=0.0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="con_RES")

    x_SCG[0,0].ub = 1000
    x_SCG[1,0].ub = 800
    x_SCG[0,1].ub = 500
    x_SCG[1,1].ub = 600

     

    x_RES = model.addVars(N,R, lb=0.0, ub=400, vtype=GRB.CONTINUOUS, name="x_RES")
    con_RES = model.addVars(N,R, lb=0.0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="con_RES")
    Total_con_RES = model.addVars(R, lb=0.0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="con_RES")


    z = model.addVar(lb=0.0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="z")


    delta_P = model.addVars(R, lb=0.0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="delta_P")


    SSS_1 = model.addVar(lb=0.0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="SSS_1")
    SSS_2 = model.addVar(lb=0.0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, name="SSS_2")


    # objective_expr = 10 * x_SCG + 5 * x_act_SCG + 3 * x_RES + ( SSS_1 + SSS_2 )*1000 + con_SCG

    objective_expr = gp.quicksum( gp.quicksum( 10 * x_SCG[m,r] for r in range(R) ) for m in range(M) ) + gp.quicksum( gp.quicksum( 5 * x_act_SCG[m,r] for r in range(R) ) for m in range(M) ) + gp.quicksum( gp.quicksum( 3 * x_RES[n,r] for r in range(R) ) for n in range(N) ) 


    model.addConstr(gp.quicksum( x_SCG[m,0] for m in range(M) )  + gp.quicksum( x_RES[n,0] for n in range(N) )  == 2500 , name="Demand")
    model.addConstr(gp.quicksum( x_SCG[m,1] for m in range(M) )  + gp.quicksum( x_RES[n,1] for n in range(N) )  == 500 , name="Demand")


    model.addConstrs(x_SCG[m,r] <= x_ON_SCG[m,r] for m in range(M) for r in range(R))
    model.addConstrs(x_ON_SCG[m,r] <= x_act_SCG[m,r] for m in range(M) for r in range(R))
    model.addConstrs(x_act_SCG[m,r] <= P_tot[m,r] for m in range(M) for r in range(R))

     

    model.addConstrs((con_SCG[m,r] == gp.max_(x_SCG[m,r], min_con_SCG[m,r]) for m in range(M) for r in range(R)), name="c_max")

     

    model.addConstrs(Total_con_SCG[r] == max_( con_SCG[0,r] , con_SCG[1,r]) for r in range(R))

    # model.addConstr(con_SCG <= x_SCG , name="Constraint555")
    # model.addConstr(con_SCG <= 200 , name="Constraint555")

    # model.addConstr(con_SCG >= x_SCG - SSS_1 - SSS_2 , name="Constraint3")
    # model.addConstr(con_SCG >= 200 - SSS_1 - SSS_2 , name="Constraint4")
    # model.addConstr(SSS_1 >= x_SCG - 200, name="Constraint5")
    # model.addConstr(SSS_2 >= 200 - x_SCG , name="Constraint6")


    model.addConstrs(con_RES[n,r] == 0.25 * x_RES[n,r] for n in range(N) for r in range(R))
    model.addConstrs(Total_con_RES[r] == max_( con_RES[0,r] , con_RES[1,r]) for r in range(R))


    model.addConstrs(delta_P[r] == max_( Total_con_SCG[r] , Total_con_RES[r]) for r in range(R))


    # model.addConstr(delta_P >= con_SCG , name="Constraint555")
    # model.addConstr(delta_P[r] >= con_RES[n,r] for n in range(N) for r in range(R) )
    model.addConstrs(3 * gp.quicksum( x_act_SCG[m,r] for m in range(M) ) >= 50 * delta_P[r] for r in range(R))


    model.setObjective(objective_expr, GRB.MINIMIZE)
    model.optimize()

    # Access the values of decision variables
    x_SCG_values = model.getAttr('X', x_SCG)
    x_ON_SCG_values = model.getAttr('X', x_ON_SCG)
    x_act_SCG_values = model.getAttr('X', x_act_SCG)
    con_SCG_values = model.getAttr('X', con_SCG)


    x_RES_values = model.getAttr('X', x_RES)
    con_RES_values = model.getAttr('X', con_RES)
    Total_con_RES_values = model.getAttr('X', Total_con_RES)
    Total_con_SCG_values = model.getAttr('X', Total_con_SCG)


    z_value = z.X
    delta_P_values = model.getAttr('X', delta_P)


    SSS_1_value = SSS_1.X
    SSS_2_value = SSS_2.X

    # You can access the values of variables, one by one, like the examples above.

    # For example, to print the values of x_SCG for all indices:
    for m in range(M):
        for r in range(R):
            print(f'x_SCG[{m}, {r}] = {x_SCG_values[m, r]}')
            print(f'x_ON_SCG[{m}, {r}] = {x_ON_SCG_values[m, r]}')
            print(f'x_act_SCG[{m}, {r}] = {x_act_SCG_values[m, r]}')
            print(f'con_SCG[{m}, {r}] = {con_SCG_values[m, r]}')
            print()

    for n in range(N):
        for r in range(R):
            print(f'x_RES[{n}, {r}] = {x_RES_values[n, r]}')
            print(f'con_RES[{n}, {r}] = {con_RES_values[n, r]}')
            print()


    for r in range(R):
        print(f'Total_con_SCG[{r}] = {Total_con_SCG_values[r]}')
        print(f'Total_con_RES[{r}] = {Total_con_RES_values[r]}')
        print(f'delta_P[{r}] = {delta_P_values[r]}')
        print()
           


    # Close the model
    model.close()

    In my main code, I want to add these constraints:


    SCG_type_con[m,r,y,d,h] == min ( SCG_dis[m,r,y,d,h] , x_1[m,r] ) ∀ m, r, y, d, h


    SCG_con[r,y,d,h] == max ( SCG_type_con[m,r,y,d,h] ) over all m and ∀ r, y, d, h
    ## For example: SCG_con[r,y,d,h] == max ( SCG_type_con[0,r,y,d,h] , SCG_type_con[1,r,y,d,h] , SCG_type_con[2,r,y,d,h] )
    ## However, I want to define generally not manually like the above example


    RES_con[r,y,d,h] == max ( RES_type_con[n,r,y,d,h] ) over all n and ∀ r, y, d, h


    delta_P[r,y,d,h] == max ( SCG_con[r,y,d,h] , RES_con[r,y,d,h] ) ∀ r, y, d, h

    0
  • Maliheh Aramon
    • Gurobi Staff

    Hi, 

    In the constraint below:

    model.addConstrs(
    (
    con_SCG[m,r] == gp.max_(x_SCG[m,r], min_con_SCG[m,r])
    for m in range(M)
    for r in range(R)
    ),
    name="c_max",
    )

    The \(\texttt{min_con_SCG[m,r]}\) is a constant and not a Gurobi variable. According to the Gurobi documentation, the signature of the max_() function is: 

    max_(*args, constant=None )

    Therefore, your constraint needs to change to:

    model.addConstrs(
    (
    con_SCG[m, r] ==gp.max_(x_SCG[m, r], constant=min_con_SCG[m, r])
    for m in range(M)
    for r in range(R)
    ),
    name="c_max",
    )

    Best regards,
    Maliheh

    0
  • Amir Fayaz Heidari
    • Gurobi-versary
    • Conversationalist
    • First Question

    Thanks Maliheh.

    0

Post is closed for comments.