メインコンテンツへスキップ

Writing in Minimum Order Quantity and Order Discounts into Jupyter Notebook

回答済み

コメント

13件のコメント

  • 正式なコメント
    Simranjit Kaur
    • Gurobi Staff
    This post is more than three 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.
  • Jaromił Najman
    • Gurobi Staff

    One way to model your discount is to use a piecewise-linear function (cf. piecewise-linear section in the documentation for more details)

    Let's assume that the maximum order quantity is \(100\). You can define the cost depending on the quantity as

    import gurobipy as gp
    from gurobipy import GRB

    m = gp.Model("test")

    quantity = m.addVar(lb=5, ub=100, vtype=GRB.INTEGER, name="quantity")
    cost = m.addVar(lb=0.5, ub=2, vtype=GRB.CONTINUOUS, name="cost")
    m.addGenConstrPWL(quantity, cost, [5, 9, 10, 14, 15, 100], [2, 2, 1, 1, 0.5, 0.5])

    The piecewise-linear function states

    \[\text{cost}=\begin{cases} 2, &\text{if quantity} \in [5,9] \\  1, &\text{if quantity} \in [10,14] \\  0.5, &\text{if quantity} \in [15,100] \end{cases}.\]

    The same function also works if the maximum order quantity is \(>100\) because Gurobi interpolate the last two points of the piecewise-linear function to compute the function value for larger quantities.

    Best regards, 
    Jaromił

    0
  • Chou Chun_Yen
    • Gurobi-versary
    • Conversationalist

    Hello
    I'm not a native English speaker, please forgive me
    Can you please tell me how to write the objective function of  piecewise-linear function in gurobi for this question

    Best regards

    0
  • Jaromił Najman
    • Gurobi Staff

    Hi Chou,

    It seems like you did not successfully post your question regarding the piecewise-linear formulation. Could you please retry?

    Best regards, 
    Jaromił

    0
  • Chou Chun_Yen
    • Gurobi-versary
    • Conversationalist
    0
  • Jaromił Najman
    • Gurobi Staff

    Could you show the last ~20 lines of the log file?

    You could try fixing the variable flow_add_Artificial_i3 to value 8 via an equality constraint. If the model solves with a worse objective value, then value 9 is indeed better. If the objective value is better, then you should try to lower the MIPGap value. If the model is infeasible, then please refer to How do I determine why my model is infeasible?

    0
  • Chou Chun_Yen
    • Gurobi-versary
    • Conversationalist

    Thank you for your reply Jaromił Najman
    I'm not sure what the log file is, so I searched online for the log file of gurobi, and my log file should be as follows

    Restricted license - for non-production use only - expires 2023-10-25
    Set parameter NonConvex to value 2
    Gurobi Optimizer version 9.5.1 build v9.5.1rc2 (win64)
    Thread count: 6 physical cores, 12 logical processors, using up to 12 threads
    Optimize a model with 96 rows, 138 columns and 276 nonzeros
    Model fingerprint: 0x6713140c
    Model has 46 quadratic objective terms
    Model has 46 general constraints
    Variable types: 92 continuous, 46 integer (0 binary)
    Coefficient statistics:
      Matrix range     [1e+00, 1e+00]
      Objective range  [9e+00, 9e+00]
      QObjective range [2e+00, 2e+00]
      Bounds range     [8e+00, 1e+06]
      RHS range        [3e+00, 1e+06]
      PWLCon x range   [3e+02, 2e+03]
      PWLCon y range   [8e+00, 1e+01]
    Presolve added 0 rows and 68 columns
    Presolve removed 6 rows and 0 columns
    Presolve time: 0.00s
    Presolved: 145 rows, 234 columns, 629 nonzeros
    Presolved model has 27 SOS constraint(s)
    Presolved model has 27 bilinear constraint(s)
    Variable types: 207 continuous, 27 integer (0 binary)

    Root relaxation: objective 5.659300e+05, 129 iterations, 0.00 seconds (0.00 work units)

        Nodes    |    Current Node    |     Objective Bounds      |     Work
     Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time

         0     0 565930.000    0    3          - 565930.000      -     -    0s
    H    0     0                    567889.00000 565930.000  0.34%     -    0s
    *    0     0               0    565930.00000 565930.000  0.00%     -    0s

    Cutting planes:
      Gomory: 1
      RLT: 1

    Explored 1 nodes (130 simplex iterations) in 0.01 seconds (0.00 work units)
    Thread count was 12 (of 12 available processors)

    Solution count 2: 565930 567889

    Optimal solution found (tolerance 1.00e-04)
    Best objective 5.659300000000e+05, best bound 5.659300000000e+05, gap 0.0000%


    obj:565930
    flow_add_Incentive_i1-> 134
    flow_add_Incentive_i2-> 3853
    flow_add_Incentive_i3-> 1738
    flow_add_Incentive_i4-> 0
    flow_add_Incentive_i5-> 1850
    flow_add_Incentive_i6-> 603
    flow_add_Incentive_i7-> 987
    flow_add_Incentive_i8-> 0
    flow_add_Incentive_i9-> 358
    flow_add_Incentive_i10-> 0
    flow_add_Incentive_i11-> 530
    flow_add_Incentive_i12-> 3
    flow_add_Incentive_i13-> 9548
    flow_add_Incentive_i14-> 522
    flow_add_Incentive_i15-> 141
    flow_add_Incentive_i16-> 168
    flow_add_Incentive_i17-> 0
    flow_add_Incentive_i18-> 300
    flow_add_Incentive_i19-> 161
    flow_add_Incentive_i20-> 436
    flow_add_Incentive_i21-> 49
    flow_add_Incentive_i22-> 0
    flow_add_Incentive_i23-> 1170
    flow_add_Artificial_i1-> 3780
    flow_add_Artificial_i2-> 2219
    flow_add_Artificial_i3-> 1959
    flow_add_Artificial_i4-> 2790
    flow_add_Artificial_i5-> 0
    flow_add_Artificial_i6-> 3780
    flow_add_Artificial_i7-> 0
    flow_add_Artificial_i8-> 0
    flow_add_Artificial_i9-> 0
    flow_add_Artificial_i10-> 3073
    flow_add_Artificial_i11-> 0
    flow_add_Artificial_i12-> 0
    flow_add_Artificial_i13-> 0
    flow_add_Artificial_i14-> 0
    flow_add_Artificial_i15-> 0
    flow_add_Artificial_i16-> 0
    flow_add_Artificial_i17-> 2276
    flow_add_Artificial_i18-> 0
    flow_add_Artificial_i19-> 0
    flow_add_Artificial_i20-> 0
    flow_add_Artificial_i21-> 0
    flow_add_Artificial_i22-> 2673
    flow_add_Artificial_i23-> 0
    flow_cut_Incentive_i1-> 1188
    flow_cut_Incentive_i2-> 0
    flow_cut_Incentive_i3-> 2330
    flow_cut_Incentive_i4-> 1856
    flow_cut_Incentive_i5-> 0
    flow_cut_Incentive_i6-> 1071
    flow_cut_Incentive_i7-> 0
    flow_cut_Incentive_i8-> 0
    flow_cut_Incentive_i9-> 332
    flow_cut_Incentive_i10-> 301
    flow_cut_Incentive_i11-> 430
    flow_cut_Incentive_i12-> 0
    flow_cut_Incentive_i13-> 2433
    flow_cut_Incentive_i14-> 0
    flow_cut_Incentive_i15-> 23
    flow_cut_Incentive_i16-> 208
    flow_cut_Incentive_i17-> 0
    flow_cut_Incentive_i18-> 37
    flow_cut_Incentive_i19-> 41
    flow_cut_Incentive_i20-> 35
    flow_cut_Incentive_i21-> 0
    flow_cut_Incentive_i22-> 0
    flow_cut_Incentive_i23-> 453
    flow_cut_Artificial_i1-> 0
    flow_cut_Artificial_i2-> 874
    flow_cut_Artificial_i3-> 0
    flow_cut_Artificial_i4-> 990
    flow_cut_Artificial_i5-> 1805
    flow_cut_Artificial_i6-> 0
    flow_cut_Artificial_i7-> 694
    flow_cut_Artificial_i8-> 0
    flow_cut_Artificial_i9-> 0
    flow_cut_Artificial_i10-> 707
    flow_cut_Artificial_i11-> 0
    flow_cut_Artificial_i12-> 0
    flow_cut_Artificial_i13-> 3125
    flow_cut_Artificial_i14-> 923
    flow_cut_Artificial_i15-> 0
    flow_cut_Artificial_i16-> 0
    flow_cut_Artificial_i17-> 922
    flow_cut_Artificial_i18-> 0
    flow_cut_Artificial_i19-> 0
    flow_cut_Artificial_i20-> 0
    flow_cut_Artificial_i21-> 0
    flow_cut_Artificial_i22-> 699
    flow_cut_Artificial_i23-> 0
    art_cost_add_Artificial_i1-> 8
    art_cost_add_Artificial_i2-> 8
    art_cost_add_Artificial_i3-> 8
    art_cost_add_Artificial_i4-> 8
    art_cost_add_Artificial_i5-> 10
    art_cost_add_Artificial_i6-> 8
    art_cost_add_Artificial_i7-> 10
    art_cost_add_Artificial_i8-> 10
    art_cost_add_Artificial_i9-> 10
    art_cost_add_Artificial_i10-> 8
    art_cost_add_Artificial_i11-> 10
    art_cost_add_Artificial_i12-> 10
    art_cost_add_Artificial_i13-> 10
    art_cost_add_Artificial_i14-> 10
    art_cost_add_Artificial_i15-> 10
    art_cost_add_Artificial_i16-> 10
    art_cost_add_Artificial_i17-> 8
    art_cost_add_Artificial_i18-> 10
    art_cost_add_Artificial_i19-> 10
    art_cost_add_Artificial_i20-> 10
    art_cost_add_Artificial_i21-> 10
    art_cost_add_Artificial_i22-> 8
    art_cost_add_Artificial_i23-> 10
    art_cost_cut_Artificial_i1-> 10
    art_cost_cut_Artificial_i2-> 8
    art_cost_cut_Artificial_i3-> 10
    art_cost_cut_Artificial_i4-> 8
    art_cost_cut_Artificial_i5-> 8
    art_cost_cut_Artificial_i6-> 10
    art_cost_cut_Artificial_i7-> 8
    art_cost_cut_Artificial_i8-> 10
    art_cost_cut_Artificial_i9-> 10
    art_cost_cut_Artificial_i10-> 8
    art_cost_cut_Artificial_i11-> 10
    art_cost_cut_Artificial_i12-> 10
    art_cost_cut_Artificial_i13-> 8
    art_cost_cut_Artificial_i14-> 8
    art_cost_cut_Artificial_i15-> 10
    art_cost_cut_Artificial_i16-> 10
    art_cost_cut_Artificial_i17-> 8
    art_cost_cut_Artificial_i18-> 10
    art_cost_cut_Artificial_i19-> 10
    art_cost_cut_Artificial_i20-> 10
    art_cost_cut_Artificial_i21-> 10
    art_cost_cut_Artificial_i22-> 8
    art_cost_cut_Artificial_i23-> 10
    0
  • Jaromił Najman
    • Gurobi Staff

    Thanks for the output. Now you can try fixing the particular variable to the value you think is correct.

    variablename = "<some_name>"
    var = model.getVarByName(variablename)
    model.addConstr(var == <the_value_it_should_have>, name="fix_constraint")
    0
  • Chou Chun_Yen
    • Gurobi-versary
    • Conversationalist

     

    Thank you for your reply Jaromił Najman

    But my shipping cost variable art _cost variable depends on the number of shipments, so I should not be able to fix my cost variable, I am referring to the quantity discount( piecewise-linear function )you mentioned in this discussion board

    for h in lacks:
        for i,j in art_arcs:
            #add
            if h == "add":
               m.addGenConstrPWL(flow[h,i,j], art_cost[h,i,j], [0,979,980,1959,1960,2940], [10,10,9,9,8,8])
            #cut     
            else:
                 m.addGenConstrPWL(flow[h,i,j], art_cost[h,i,j], [0, 279,280,559,560,840], [10,10,9,9,8,8])

    The model runs out that the  flow_add_Artificial_i3-> 1959 shipping volume is 1959, but its cost is 8. According to the above code constraint the shipping cost should be 9 because it doesn't touch 1960. I checked the link of gurobi  piecewise-linear function you posted and I don't know where the error is.

     

    0
  • Jaromił Najman
    • Gurobi Staff

    Your flow variables are continuous. However, your print statement prints them as integers

    print('%s-> %d'%(v.varName,v.x))

    The value of the flow_add_Artificial_i3 is not 1959 but 1959.9999999999 which is the float representation of 1960. It is getting truncated because you are telling Python to convert it to an integer by using \(\texttt{%d}\).

    The correct output should be

    print('%s-> %f'%(v.varName,v.x))

    Note that even integer variables can attain continuous values, e.g., 0.9999999 instead of 1.

    0
  • Chou Chun_Yen
    • Gurobi-versary
    • Conversationalist

    Jaromił Najman

    Omg thank you very much, I did not notice this detail, I have another question, I revise quantity discount cost to [20,20,10,10,5,5], as the code below, but the model becomes infeasible, this should be free to adjust, right. Sorry for taking your time.

            #add
            if h == "add":
                    m.addGenConstrPWL(flow[h,i,j], art_cost[h,i,j], [0,980,981,1960,1961,2940], [20,20,10,10,5,5])
                   
          #cut      
            else:
                 m.addGenConstrPWL(flow[h,i,j], art_cost[h,i,j], [0,280,281,560,561,840], [20,20,10,10,5,5])
    0
  • Jaromił Najman
    • Gurobi Staff

    The Knowledge Base article How do I determine why my model is infeasible? should be helpful.

    0
  • Chou Chun_Yen
    • Gurobi-versary
    • Conversationalist

    Thanks you so much Jaromił Najman

    I solve the problem! 

    0

投稿コメントは受け付けていません。