Skip to main content

Unable to model constraint

Answered

Comments

6 comments

  • Jaromił Najman
    • Gurobi Staff

    Could you please share a minimal reproducible example where you implement the respective lists/sets, variables and try to implement the constraint you mentioned?

    0
  • Sander Mertens
    • Gurobi-versary
    • Curious
    • Conversationalist

    First an multidict is created:

    proc_combo, costs = {
    (0, 0, 0): 5,
    (0, 1, 1): 10,
    (1, 1, 1): 15,
    (0, 2, 2): 20,
    (1, 2, 2): 25,
    (0, 3, 3): 30,
    (0, 4, 4): 35,
    (0, 5, 5): 40,
    (0, 6, 6): 45,
    (1, 6, 6): 50,
    (2, 6, 6): 55,
    (4, 6, 7): 60,
    (0, 7, 8): 65,
    (1, 7, 8): 70,
    (2, 7, 8): 75,
    (4, 7, 8): 80,
    (0, 8, 8): 85,
    (1, 8, 8): 90,
    (2, 8, 8): 95,
    (4, 8, 8): 100,
    (1, 9, 0): 105,
    (1, 10, 3): 110,
    (1, 11, 5): 115,
    (3, 12, 8): 120}

    The dictionary times, mentioned in the first post, is created. Note that the tuples that form the keys are the same tuples als in the multidict.

    times = { 
    (0.0, 0.0, 0.0) 12.0,
    (0.0, 1.0, 1.0) 9.0,
    (1.0, 1.0, 1.0) 11.0,
    (0.0, 2.0, 2.0) 11.0,
    (1.0, 2.0, 2.0) 80,0,
    (0.0, 3.0, 3.0) 13.0,
    (0.0, 4.0, 4.0) 9.0,
    (0.0, 5.0, 5.0) 15.0,
    (0.0, 6.0, 6.0) 2.0,
    (1.0, 6.0, 6.0) 4.0,
    (2.0, 6.0, 6.0) 44.0,
    (4.0, 6.0, 7.0) 11.0,
    (0.0, 7.0, 8.0) 99.0,
    (1.0, 7.0, 8.0) 13.0,
    (2.0, 7.0, 8.0) 4.0,
    (4.0, 7.0, 8.0) 15.0,
    (0.0, 8.0, 8.0) 23.0,
    (1.0, 8.0, 8.0) 23.0,
    (2.0, 8.0, 8.0) 2.0,
    (4.0, 8.0, 8.0) 34.0,
    (1.0, 9.0, 0.0) 29.0,
    (1.0, 10.0, 3.0) 77.0,
    (1.0, 11.0, 5.0) 4.0
    }

    Than a list of time points is created:

    time_points =[]
    for i in range(250):
        time_points.append(i)
        i += 1

    Here the first element of each tuple key is p, the second j and the third k. All the p's together for set P, all j's together for set J and all k's together form set K.

    The values in the dictionary are the tau for each p, j, k combination.

    Then the X and F variables are created with the aid of the multidict and the list:

    X = m.addVars([(int(p), int(j), int(k), t) for (p, j, k) in proc_combo for t in time_points], vtype=GRB.BINARY, name='X')
    F = m.addVars([(int(p), int(j), int(k), t) for (p, j, k) in proc_combo for t in time_points], vtype=GRB.BINARY, name='F')

     

    Subsequent I'm trying to add the constraint shown below.
     

    0
  • Jaromił Najman
    • Gurobi Staff

    Your constraint as it stands has an issue. You want to add a constraint \(\forall j \in J\setminus \{12\}, \{t \in T | t+\tau_{pjk} 1 \leq h\}\) where \(\tau\) depends on indices \(p,k\) which are only used in the sums, i.e., it is not clear which \(p,k\) to use when constructing for a fixed \(t\).

    Could you please clarify or adjust your constraint such that it is a valid one? 

    0
  • Sander Mertens
    • Gurobi-versary
    • Curious
    • Conversationalist

    My apologies, you're right. The additional condition for t can be dropped so that it the constraint must only hold for all j (except 12) and t:

    0
  • Jaromił Najman
    • Gurobi Staff

    Hi Sander,

    Here is a version which might work for you.

    m = gp.Model()

    proc_combo, costs = gp.multidict({
    (0, 0, 0): 5, 
    (0, 1, 1): 10, 
    (1, 1, 1): 15, 
    (0, 2, 2): 20, 
    (1, 2, 2): 25, 
    (0, 3, 3): 30, 
    (0, 4, 4): 35, 
    (0, 5, 5): 40, 
    (0, 6, 6): 45, 
    (1, 6, 6): 50, 
    (2, 6, 6): 55, 
    (4, 6, 7): 60, 
    (0, 7, 8): 65, 
    (1, 7, 8): 70, 
    (2, 7, 8): 75, 
    (4, 7, 8): 80, 
    (0, 8, 8): 85, 
    (1, 8, 8): 90, 
    (2, 8, 8): 95, 
    (4, 8, 8): 100, 
    (1, 9, 0): 105, 
    (1, 10, 3): 110, 
    (1, 11, 5): 115, 
    (3, 12, 8): 120})

    P = [p for p in range(5)]
    J = [j for j in range(13)]
    K = [k for k in range(9)]

    times = { 
    (0.0, 0.0, 0.0): 12.0,
    (0.0, 1.0, 1.0): 9.0,
    (1.0, 1.0, 1.0): 11.0,
    (0.0, 2.0, 2.0): 11.0,
    (1.0, 2.0, 2.0): 80.0,
    (0.0, 3.0, 3.0): 13.0,
    (0.0, 4.0, 4.0): 9.0,
    (0.0, 5.0, 5.0): 15.0,
    (0.0, 6.0, 6.0): 2.0,
    (1.0, 6.0, 6.0): 4.0,
    (2.0, 6.0, 6.0): 44.0,
    (4.0, 6.0, 7.0): 11.0,
    (0.0, 7.0, 8.0): 99.0,
    (1.0, 7.0, 8.0): 13.0,
    (2.0, 7.0, 8.0): 4.0,
    (4.0, 7.0, 8.0): 15.0,
    (0.0, 8.0, 8.0): 23.0,
    (1.0, 8.0, 8.0): 23.0,
    (2.0, 8.0, 8.0): 2.0,
    (4.0, 8.0, 8.0): 34.0,
    (1.0, 9.0, 0.0): 29.0,
    (1.0, 10.0, 3.0): 77.0,
    (1.0, 11.0, 5.0): 4.0
    }

    time_points =[]
    for i in range(250):
        time_points.append(i)
        i += 1

    X = m.addVars([(int(p), int(j), int(k), t) for (p, j, k) in proc_combo for t in time_points], vtype=GRB.BINARY, name='X')
    F = m.addVars([(int(p), int(j), int(k), t) for (p, j, k) in proc_combo for t in time_points], vtype=GRB.BINARY, name='F')

    for j in J:
      if j == 12:
        continue

      for t in time_points:
        m.addConstr(gp.quicksum(X[p,j,k,t_prime] for p in P
                                                 for k in K if (p,j,k) in proc_combo
                                                 for t_prime in range(t,t+int(times[p,j,k])-1) if t+int(times[p,j,k])-1 <= 250)
                    + gp.quicksum(F[p,j,k,t] for p in P
                                             for k in K if (p,j,k) in proc_combo)
                    <= 1)

    There are multiple things to note here. You originally did not define objects proc_combo and costs as a multidict. I added the lists P,J,K for easier \(\texttt{for}\)-loops in the quicksums. Additionally, there was a typo at "(1.0, 2.0, 2.0): 80,0,".

    In the above, we are adding a constraint 1 by 1. In your latest comment, it is \(J_{pk}\) so it might be that your set \(J\) is dependent on indicies \(p,k\). As mentioned in my previous comment, this will not work, because \(p,k\) are only within the constraint and not in the "\(\forall\)" block.

    We had to add the safe guards "if (p,j,k) in proc_combo" and "if t+int(times[p,j,k])-1 <= 250" to avoid index key errors. It is possible that there is a nicer way of writing these constraints when different data structures are used but I think this should give you a good idea of how to approach such constraints in the future.

    When working with complex constraints, I would recommend to write the model to a human-readable LP file via the write method and analyze the resulting file.

    m.write("myModel.lp")

    Best regards, 
    Jaromił

    0
  • Sander Mertens
    • Gurobi-versary
    • Curious
    • Conversationalist

    Thank you for your clear answer, despite the mistakes in my post. The constraint finally seems to work!

    0

Please sign in to leave a comment.