簡體   English   中英

我是否可以在不約束 CPLEX model 的情況下添加具有最大值的 kpi?

[英]Can I add kpi with maximum values without contraining CPLEX model?

我正在使用 cplex 進行優化 model,以優化飲食成分。 現在我想添加一個額外的變量/KPI,它是 model 中其他 KPI 的總和。 但是,這個總和是一個有最大值的分數,這意味着當每個KPI超過某個上限時,總和不應該考慮超過這個值的值。 分數只是每種食物成分的衡量標准,因此,上限不是 model 的限制,而只是計算分數的限制,因此不應影響 model 結果。 最后,我想最小化總分。

我嘗試使用 mdl.sum 將其添加以對每個指標求和並將它們添加到列表中,然后如果超出上限,我嘗試將總和替換為另一個列表的值。 請參見下面的示例:

    # Decision variables, limited to be >= Food.qmin and <= Food.qmax
    ftype = mdl.integer_vartype if ints else mdl.continuous_vartype
    qty = mdl.var_dict(foods, ftype, lb=lambda f: f.qmin,ub=lambda f: f.qmax, name=lambda f: 
    "q_%s" % f.name)

    # Limit range of nutrients, and mark them as KPIs
    for c in constraints:
        amount = mdl.sum(qty[f] * food_constraints[f.name, c.name] for f in foods)
        mdl.add_range(c.qmin, amount, c.qmax)
        mdl.add_kpi(amount, publish_name="Total %s" % c.name)
    
    
    # add sum of indicators with max values:
    score1 = mdl.sum(qty[f] * f.veg for f in foods)
    score2 = mdl.sum(qty[f] * f.fruit for f in foods)
    score3 = mdl.sum(qty[f] * f.fish for f in foods)
    
    # add sum of indicators without max values:
    score4 = mdl.sum(qty[f] * f.sugar for f in foods)
    score5 = mdl.sum(qty[f] * f.fats for f in foods)
    
    Score_sum_A = [score1, score2, score3]
    
    max_scores = [10.6, 3.3, 9.7] 
   
    # cap values of Score_sum_A to max scores:
    for i in range(len(max_scores)):
        if Score_sum_A[i] >= max_scores[i]:
           Score_sum_A[i] = max_scores[i]
        else:
           Score_sum_A[i] = Score_sum_A[i] 
            
    
    Score_sum_B = [score4, score5]
              
    total_score_sum = sum(Score_sum_A + Score_sum_B)
    mdl.add_kpi(total_score_sum , 'Total food score')

    mdl.minimize(total_score_sum)

但是,在運行 model 時,我收到錯誤:“TypeError:無法將線性約束轉換為 boolean 值”,這是因為 if 語句。 因此,model 似乎無法使用 model 內的這種 if 語句進行操作。

有誰知道,是否可以在 cplex 中添加這樣一個具有最大值的指標,而不限制 model 結果?

任何提示將不勝感激。

謝謝

你不能寫

if Score_sum_A[i] >= max_scores[i]:
           Score_sum_A[i] = max_scores[i]

因為 Score_sum_A 不是常數。 你應該使用最大值

from docplex.mp.model import Model

mdl = Model(name='buses')

nbKids=300;
buses=[30,40,50]

#decision variables
mdl.nbBus = {b: mdl.integer_var(name="nbBus"+str(b)) for b in buses}

# Constraint
mdl.add_constraint(sum(mdl.nbBus[b]*b for b in buses) >= nbKids, 'kids')

# Objective
# logical constraint is the max of all nbBus
mdl.minimize(mdl.max(mdl.nbBus[b] for b in buses)) 

mdl.solve(log_output=True,)

mdl.export("c:\\temp\\buses.lp")

for v in mdl.iter_integer_vars():
    print(v," = ",v.solution_value)

或來自 docplex 的if_then

from docplex.mp.model import Model

mdl = Model(name='buses')
nbbus40 = mdl.integer_var(name='nbBus40')
nbbus30 = mdl.integer_var(name='nbBus30')
mdl.add_constraint(nbbus40*40 + nbbus30*30 >= 300, 'kids')
mdl.minimize(nbbus40*500 + nbbus30*400)

mdl.solve()

for v in mdl.iter_integer_vars():
   print(v," = ",v.solution_value)

print()
print("with if nb buses 40 more than 3  then nbBuses30 more than 7")

#if then constraint
mdl.add(mdl.if_then(nbbus40>=3,nbbus30>=7))
mdl.minimize(nbbus40*500 + nbbus30*400)

mdl.solve()

 

for v in mdl.iter_integer_vars():
    print(v," = ",v.solution_value)

如果我稍微改變https://ibmdecisionoptimization.github.io/docplex-doc/mp/diet.html

def nb_products(mdl_, s_):
    qvs = mdl_.find_matching_vars(pattern="q_")
    return sum(1 for qv in qvs if s_[qv] >= 1e-5)

mdl.add_kpi(nb_products, 'Nb foods')

def nb_products(mdl_, s_):
    qvs = mdl_.find_matching_vars(pattern="q_")
    return sum(1 for qv in qvs if s_[qv] >= 1e-5)

def nb_products_capped(mdl_, s_):
    qvs = mdl_.find_matching_vars(pattern="q_")
    return mdl_.min(3,sum(1 for qv in qvs if s_[qv] >= 1e-5))

mdl.add_kpi(nb_products, 'Nb foods')
mdl.add_kpi(nb_products_capped,'Nb foods capped to 3')

然后我會得到

*  KPI: Nb foods             = 5.000000
*  KPI: Nb foods capped to 3 = 3.000000

在像zookpi這樣的小例子中

from docplex.mp.model import Model

mdl = Model(name='buses')
nbbus40 = mdl.integer_var(name='nbBus40')
nbbus30 = mdl.integer_var(name='nbBus30')

nbbus=nbbus30+nbbus40
mdl.add_kpi(nbbus,"nbbus")
mdl.add_constraint(nbbus40*40 + nbbus30*30 >= 300, 'kids')
mdl.minimize(nbbus40*500 + nbbus30*400)

mdl.solve(log_output=True,)

mdl.export("c:\\temp\\buses.lp")

for v in mdl.iter_integer_vars():
    print(v," = ",v.solution_value)

for k in mdl.iter_kpis():
    print(k," = ",k.solution_value)

添加

mdl.add_kpi(mdl.min(nbbus,3),"nbbuscapped3")

會給

nbBus40  =  6.0
nbBus30  =  2.0
DecisionKPI(name=nbbus,expr=nbBus40+nbBus30)  =  8.0
DecisionKPI(name=nbbuscapped3,expr=min(nbBus40+nbBus30,3))  =  3

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM