python Pyomo访问/检索双变量-使用二进制变量的影子价格

l0oc07j2  于 2024-01-05  发布在  Python
关注(0)|答案(1)|浏览(153)

我是一个新手,尤其是pyomo,所以我为新手的错误提前道歉。
我已经定义了一个简单的单元提交练习([1]中的示例3.1),使用[2]作为起点。我得到了正确的结果,我的代码运行,但我有一些关于如何访问东西的问题。

  1. import matplotlib.pyplot as plt
  2. import numpy as np
  3. import pandas as pd
  4. import shutil
  5. import sys
  6. import os.path
  7. import pyomo.environ as pyo
  8. import pyomo.gdp as gdp #necessary if you use booleans to select active and inactive units
  9. def bounds_rule(m, n, param='Cap_MW'):
  10. # m because it pases the module
  11. # n because it needs a variable from each set, in this case there was only m.N
  12. return (0, Gen[n][param]) #returns lower and upper bounds.
  13. def unit_commitment():
  14. m = pyo.ConcreteModel()
  15. m.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT)
  16. N=Gen.keys()
  17. m.N = pyo.Set(initialize=N)
  18. m.Pgen = pyo.Var(m.N, bounds = bounds_rule) #amount of generation
  19. m.Rgen = pyo.Var(m.N, bounds = bounds_rule) #amount of generation
  20. # m.OnOff = pyo.Var(m.N, domain=pyo.Binary) #boolean on/off marker
  21. # objective
  22. m.cost = pyo.Objective(expr = sum( m.Pgen[n]*Gen[n]['energy_$MWh'] + m.Rgen[n]*Gen[n]['res_$MW'] for n in m.N), sense=pyo.minimize)
  23. # demand
  24. m.demandP = pyo.Constraint(rule=lambda m: sum(m.Pgen[n] for n in N) == Demand['ener_MWh'])
  25. m.demandR = pyo.Constraint(rule=lambda m: sum(m.Rgen[n] for n in N) == Demand['res_MW'])
  26. # machine production limits
  27. # m.lb = pyo.Constraint(m.N, rule=lambda m, n: Gen[n]['Cap_min']*m.OnOff[n] <= m.Pgen[n]+m.Rgen[n] )
  28. # m.ub = pyo.Constraint(m.N, rule=lambda m, n: Gen[n]['Cap_MW']*m.OnOff[n] >= m.Pgen[n]+m.Rgen[n])
  29. m.lb = pyo.Constraint(m.N, rule=lambda m, n: Gen[n]['Cap_min'] <= m.Pgen[n]+m.Rgen[n] )
  30. m.ub = pyo.Constraint(m.N, rule=lambda m, n: Gen[n]['Cap_MW'] >= m.Pgen[n]+m.Rgen[n])
  31. m.rc = pyo.Suffix(direction=pyo.Suffix.IMPORT)
  32. return m
  33. Gen = {
  34. 'GenA' : {'Cap_MW': 100, 'energy_$MWh': 10, 'res_$MW': 0, 'Cap_min': 0},
  35. 'GenB' : {'Cap_MW': 100, 'energy_$MWh': 30, 'res_$MW': 25, 'Cap_min': 0},
  36. } #starting data
  37. Demand = {
  38. 'ener_MWh': 130, 'res_MW': 20,
  39. } #starting data
  40. m = unit_commitment()
  41. pyo.SolverFactory('glpk').solve(m).write()
  42. m.display()
  43. df = pd.DataFrame.from_dict([m.Pgen.extract_values(), m.Rgen.extract_values()]).T.rename(columns={0: "P", 1: "R"})
  44. print(df)
  45. print("Cost Function result: " + str(m.cost.expr()) + "$.")
  46. print(m.rc.display())
  47. print(m.dual.display())
  48. print(m.dual[m.demandR])
  49. da= {'duals': m.dual[m.demandP],
  50. 'uslack': m.demandP.uslack(),
  51. 'lslack': m.demandP.lslack(),
  52. }
  53. db= {'duals': m.dual[m.demandR],
  54. 'uslack': m.demandR.uslack(),
  55. 'lslack': m.demandR.lslack(),
  56. }
  57. duals = pd.DataFrame.from_dict([da, db]).T.rename(columns={0: "demandP", 1: "demandR"})
  58. print(duals)

字符串
以下是我的问题:

  1. Duals/shadow-price:根据定义,影子价格是约束条件的对偶变量(m.demandP和m.demandR).有没有一种方法可以访问这些值并将它们放入一个嵌套框架中,而不用做我做的“糟糕”的事情?我的意思是手动定义da和db,然后在两个字典连接时创建嵌套框架?我想做一些更干净的东西,比如保存系统中每个生成器的P和R结果的df。
    1.通常,在机组组合问题中,使用二进制变量来“标记”或“选择”活动和非活动机组。(注解行)。对于我在[3]中发现的,在包含二进制变量的模型中不存在二进制变量。之后,我重写了这个问题,没有包含二进制变量。在这个简单的练习中,所有单元都运行,这不是一个问题,但是对于更大的问题。我需要能够让优化决定哪些单元将运行,哪些单元将不运行,我仍然需要影子价格。在包含二进制变量的问题中,有没有一种方法可以获得影子价格/影子价格?
    我让基于二进制变量的约束定义也在那里,以防有人发现它有用。
    注意事项:代码也运行二进制变量,并得到正确的结果,但我不知道如何得到影子价格。因此,我的问题。
    [1]Morales,J. M.,Conejo,A. J.,Madsen,H.,Pinson,P.,& Zugno,M.(2013). Integrating renewables in electricity markets:operational problems(Vol. 205). Springer Science & Business Media.
    [2][https://jckantor.github.io/ND-Pyomo-Cookbook/04.06-Unit-Commitment.html](https://jckantor.github.io/ND-Pyomo-Cookbook/04.06-Unit-Commitment.html)
    [3][Dual Variable Returns Nothing in Pyomo](https://stackoverflow.com/questions/64160458/dual-variable-returns-nothing-in-pyomo)的
hjzp0vay

hjzp0vay1#

要回答1,您可以使用model.component_objects(pyo.Constraint)从模型中动态获取约束对象,它将返回约束的迭代器,这使您不必硬编码约束名称。对于索引变量来说,这很棘手,因为您必须执行一个额外的步骤来获取每个索引的松弛,而不仅仅是约束对象。你可以遍历keys属性来检索这些值。

  1. duals_dict = {str(key):m.dual[key] for key in m.dual.keys()}
  2. u_slack_dict = {
  3. # uslacks for non-indexed constraints
  4. **{str(con):con.uslack() for con in m.component_objects(pyo.Constraint)
  5. if not con.is_indexed()},
  6. # indexed constraint uslack
  7. # loop through the indexed constraints
  8. # get all the indices then retrieve the slacks for each index of constraint
  9. **{k:v for con in m.component_objects(pyo.Constraint) if con.is_indexed()
  10. for k,v in {'{}[{}]'.format(str(con),key):con[key].uslack()
  11. for key in con.keys()}.items()}
  12. }
  13. l_slack_dict = {
  14. # lslacks for non-indexed constraints
  15. **{str(con):con.lslack() for con in m.component_objects(pyo.Constraint)
  16. if not con.is_indexed()},
  17. # indexed constraint lslack
  18. # loop through the indexed constraints
  19. # get all the indices then retrieve the slacks for each index of constraint
  20. **{k:v for con in m.component_objects(pyo.Constraint) if con.is_indexed()
  21. for k,v in {'{}[{}]'.format(str(con),key):con[key].lslack()
  22. for key in con.keys()}.items()}
  23. }
  24. # combine into a single df
  25. df = pd.concat([pd.Series(d,name=name)
  26. for name,d in {'duals':duals_dict,
  27. 'uslack':u_slack_dict,
  28. 'lslack':l_slack_dict}.items()],
  29. axis='columns')

字符串
关于2,我同意@Erwin关于用二进制变量求解以获得最优解的评论,然后去除二进制限制,但将变量固定为最优值以获得一些对偶变量值。

展开查看全部

相关问题