土地利用优化,选项可以使用一种或其他土地类型来满足他们的要求
Land-use optimisation where options can use one OR other land type to satisfy their requirements
我想解决一个简单的土地利用优化问题,以最大化每个潜在土地利用提供的数量。
土地分为类别 1-3(Cat1、Cat2、Cat3)。
有:
- 7 米的 Cat1 可用
- 15 米 Cat2 可用
- 10 米 Cat3 可用
土地利用有 2 个选项(op1、op2)
- op1 必须使用 10m 的 Cat3 或以上(Cat3 或 Cat2 或 Cat1)和 5m 如果 Cat2 或以上(Cat2 或 Cat1)
- op2必须使用Cat3或以上的5m和Cat2或以上的10m。
op1 提供 6 个单位,而 op2 提供 8 个单位。
我正在尝试解决这个问题,但答案不符合约束条件。任何人都可以帮助找到我在我的配方中做错了什么,我是 Pulp 的新手,不知道为什么它不起作用。
定义变量和参数:
land_uses = list(["op1","op2"])
provides = dict(zip(land_uses, [6,8]))
usage1 = dict(zip(land_uses, [10,5]))
usage2 = dict(zip(land_uses, [5,10]))
cat1 = LpVariable.dicts("cat1", land_uses, lowBound = 0, cat = 'Integer')
cat2 = LpVariable.dicts("cat2", land_uses, lowBound = 0, cat = 'Integer')
cat3 = LpVariable.dicts("cat3", land_uses, lowBound = 0, cat = 'Integer')
land_vars = LpVariable.dicts("Land_use", land_uses, lowBound = 0, cat = 'Integer')
定义问题和objective函数:
simple = LpProblem("land_optimisation", LpMaximize)
simple += lpSum([provides[i] * land_vars[i] for i in land_vars])
定义约束:
simple += lpSum([(usage1[i]*land_vars[i]) - (cat1[i] + cat2[i] + cat3[i] ) for i in land_vars]) == 0
simple += lpSum([(usage2[i]*land_vars[i]) - (cat1[i] + cat2[i]) for i in land_vars]) == 0
simple += lpSum([cat1[i] for i in land_vars]) <= 7
simple += lpSum([cat2[i] for i in land_vars]) <= 15
simple += lpSum([cat3[i] for i in land_vars]) <= 10
求解及结果:
simple.solve()
for v in simple.variables():
print(v.name, "=", v.varValue)
Land_use_op1 = 2
Land_use_op2 = 1
cat1_op1 = 7
cat1_op2 = 0
cat2_op1 = 0
cat2_op2 = 13
cat3_op1 = 0
cat3_op2 = 0
好像是说对于选项 1,例如,它只使用 7 个 Cat3 或以上,而应该使用 20 个(因为选择了 2 个 op1)。我不知道这是否可以在纸浆中完成,但我想不出任何其他表达方式!真的很想 help/pointers,我相信这应该比想象中容易。非常感谢!
欢迎访问本站。
你的公式中有 2 件事导致了你现在的问题....让我们讨论一下,然后进行有效的修复。
- 在你的约束中:
simple += lpSum([(usage1[i]*land_vars[i]) - (cat1[i] + cat2[i] + cat3[i] ) for i in land_vars]) == 0
您同时对这两种用途求和,因此您得到的是汇总结果,而不是您想要的结果,即“按每次”使用。您应该将该约束放在 for 循环中,并为每次使用分别构建一个。下一个问题使情况变得更加复杂...
- 在您的公式中,您根据 2 种不同的要求对分配进行总计,并且不清楚承诺针对的是哪种要求,因此当您为 (cat 1, 2, 3) 和(cat 1, 2)
cat1[i]
可以计入 both 的要求,这显然是不正确的。
因此,您需要一种方法来跟踪土地对 (1) 特定用途的承诺,以及 (2) 根据您的两个要求中的哪一个来避免这种情况。这可以通过双索引变量(use,reqt)来完成。我这样做了,又走了 1 步将不同类别的土地汇总到索引中(这是可选的,但会阻止您为每个命名变量编写单独的约束)。
因此,上面的两点:您需要单独处理“for each”约束,这可以通过循环来完成。由于只需要根据一项要求跟踪一项承诺,您应该将其拆分为一个索引。
示例:
from pulp import *
### DATA
cats = [1, 2, 3] # categories of land
land_uses = ['op1', 'op2']
reqts = ['regular', 'premium'] # regular = cat 3+, premium = cat 2+
provides = dict(zip(land_uses, [6, 8]))
reqt_use = { ('op1', 'regular') : 10,
('op1', 'premium') : 5,
('op2', 'regular') : 5,
('op2', 'premium') : 10}
# need some way to indicate which cats are tied to which reqt...
cat_pool = { 'regular' : [1, 2, 3],
'premium' : [1, 2]}
avail = { 1 : 7,
2 : 15,
3 : 10}
### SETUP
# decision variable to commit x amount of "cat" land to "use" against "reqt"
x = LpVariable.dicts("commit", [(cat, use, reqt)
for cat in cats
for use in land_uses
for reqt in reqts],
lowBound=0, cat='Integer')
# decision variable to count what is built
build = LpVariable.dicts("build", land_uses, lowBound=0, cat='Integer')
### OBJ
simple = LpProblem("land_optimisation", LpMaximize)
# collect value, subtract tiny penalty for committed land prevents extra
# commitments that don't credit a build
simple += lpSum([provides[i] * build[i] for i in land_uses]) - \
lpSum(0.01*x[cat, use, reqt] for cat in cats for use in land_uses for reqt in reqts)
### CONSTRAINTS
# only use what is available in EACH category, across all uses and reqts
for cat in cats:
simple += lpSum(x[cat, use, reqt] for use in land_uses for reqt in reqts) <= avail[cat]
# limit the build to what is committed, by individual requirement.
# This is a double "for each" ...uses and reqts
for use in land_uses:
for reqt in reqts:
simple += build[use]*reqt_use[use, reqt] <= lpSum(x[cat, use, reqt] for cat in cat_pool[reqt])
simple.solve()
for v in simple.variables():
print(v.name, "=", v.varValue)
产量
Result - Optimal solution found
Objective value: 15.70000000
Enumerated nodes: 0
Total iterations: 0
Time (CPU seconds): 0.00
Time (Wallclock seconds): 0.00
Option for printingOptions changed from normal to all
Total time (CPU seconds): 0.00 (Wallclock seconds): 0.00
build_op1 = 0.0
build_op2 = 2.0
commit_(1,_'op1',_'premium') = 0.0
commit_(1,_'op1',_'regular') = 0.0
commit_(1,_'op2',_'premium') = 7.0
commit_(1,_'op2',_'regular') = 0.0
commit_(2,_'op1',_'premium') = 0.0
commit_(2,_'op1',_'regular') = 0.0
commit_(2,_'op2',_'premium') = 13.0
commit_(2,_'op2',_'regular') = 0.0
commit_(3,_'op1',_'premium') = 0.0
commit_(3,_'op1',_'regular') = 0.0
commit_(3,_'op2',_'premium') = 0.0
commit_(3,_'op2',_'regular') = 10.0
[Finished in 175ms]
我想解决一个简单的土地利用优化问题,以最大化每个潜在土地利用提供的数量。
土地分为类别 1-3(Cat1、Cat2、Cat3)。 有:
- 7 米的 Cat1 可用
- 15 米 Cat2 可用
- 10 米 Cat3 可用
土地利用有 2 个选项(op1、op2)
- op1 必须使用 10m 的 Cat3 或以上(Cat3 或 Cat2 或 Cat1)和 5m 如果 Cat2 或以上(Cat2 或 Cat1)
- op2必须使用Cat3或以上的5m和Cat2或以上的10m。
op1 提供 6 个单位,而 op2 提供 8 个单位。
我正在尝试解决这个问题,但答案不符合约束条件。任何人都可以帮助找到我在我的配方中做错了什么,我是 Pulp 的新手,不知道为什么它不起作用。
定义变量和参数:
land_uses = list(["op1","op2"])
provides = dict(zip(land_uses, [6,8]))
usage1 = dict(zip(land_uses, [10,5]))
usage2 = dict(zip(land_uses, [5,10]))
cat1 = LpVariable.dicts("cat1", land_uses, lowBound = 0, cat = 'Integer')
cat2 = LpVariable.dicts("cat2", land_uses, lowBound = 0, cat = 'Integer')
cat3 = LpVariable.dicts("cat3", land_uses, lowBound = 0, cat = 'Integer')
land_vars = LpVariable.dicts("Land_use", land_uses, lowBound = 0, cat = 'Integer')
定义问题和objective函数:
simple = LpProblem("land_optimisation", LpMaximize)
simple += lpSum([provides[i] * land_vars[i] for i in land_vars])
定义约束:
simple += lpSum([(usage1[i]*land_vars[i]) - (cat1[i] + cat2[i] + cat3[i] ) for i in land_vars]) == 0
simple += lpSum([(usage2[i]*land_vars[i]) - (cat1[i] + cat2[i]) for i in land_vars]) == 0
simple += lpSum([cat1[i] for i in land_vars]) <= 7
simple += lpSum([cat2[i] for i in land_vars]) <= 15
simple += lpSum([cat3[i] for i in land_vars]) <= 10
求解及结果:
simple.solve()
for v in simple.variables():
print(v.name, "=", v.varValue)
Land_use_op1 = 2
Land_use_op2 = 1
cat1_op1 = 7
cat1_op2 = 0
cat2_op1 = 0
cat2_op2 = 13
cat3_op1 = 0
cat3_op2 = 0
好像是说对于选项 1,例如,它只使用 7 个 Cat3 或以上,而应该使用 20 个(因为选择了 2 个 op1)。我不知道这是否可以在纸浆中完成,但我想不出任何其他表达方式!真的很想 help/pointers,我相信这应该比想象中容易。非常感谢!
欢迎访问本站。
你的公式中有 2 件事导致了你现在的问题....让我们讨论一下,然后进行有效的修复。
- 在你的约束中:
simple += lpSum([(usage1[i]*land_vars[i]) - (cat1[i] + cat2[i] + cat3[i] ) for i in land_vars]) == 0
您同时对这两种用途求和,因此您得到的是汇总结果,而不是您想要的结果,即“按每次”使用。您应该将该约束放在 for 循环中,并为每次使用分别构建一个。下一个问题使情况变得更加复杂...
- 在您的公式中,您根据 2 种不同的要求对分配进行总计,并且不清楚承诺针对的是哪种要求,因此当您为 (cat 1, 2, 3) 和(cat 1, 2)
cat1[i]
可以计入 both 的要求,这显然是不正确的。
因此,您需要一种方法来跟踪土地对 (1) 特定用途的承诺,以及 (2) 根据您的两个要求中的哪一个来避免这种情况。这可以通过双索引变量(use,reqt)来完成。我这样做了,又走了 1 步将不同类别的土地汇总到索引中(这是可选的,但会阻止您为每个命名变量编写单独的约束)。
因此,上面的两点:您需要单独处理“for each”约束,这可以通过循环来完成。由于只需要根据一项要求跟踪一项承诺,您应该将其拆分为一个索引。
示例:
from pulp import *
### DATA
cats = [1, 2, 3] # categories of land
land_uses = ['op1', 'op2']
reqts = ['regular', 'premium'] # regular = cat 3+, premium = cat 2+
provides = dict(zip(land_uses, [6, 8]))
reqt_use = { ('op1', 'regular') : 10,
('op1', 'premium') : 5,
('op2', 'regular') : 5,
('op2', 'premium') : 10}
# need some way to indicate which cats are tied to which reqt...
cat_pool = { 'regular' : [1, 2, 3],
'premium' : [1, 2]}
avail = { 1 : 7,
2 : 15,
3 : 10}
### SETUP
# decision variable to commit x amount of "cat" land to "use" against "reqt"
x = LpVariable.dicts("commit", [(cat, use, reqt)
for cat in cats
for use in land_uses
for reqt in reqts],
lowBound=0, cat='Integer')
# decision variable to count what is built
build = LpVariable.dicts("build", land_uses, lowBound=0, cat='Integer')
### OBJ
simple = LpProblem("land_optimisation", LpMaximize)
# collect value, subtract tiny penalty for committed land prevents extra
# commitments that don't credit a build
simple += lpSum([provides[i] * build[i] for i in land_uses]) - \
lpSum(0.01*x[cat, use, reqt] for cat in cats for use in land_uses for reqt in reqts)
### CONSTRAINTS
# only use what is available in EACH category, across all uses and reqts
for cat in cats:
simple += lpSum(x[cat, use, reqt] for use in land_uses for reqt in reqts) <= avail[cat]
# limit the build to what is committed, by individual requirement.
# This is a double "for each" ...uses and reqts
for use in land_uses:
for reqt in reqts:
simple += build[use]*reqt_use[use, reqt] <= lpSum(x[cat, use, reqt] for cat in cat_pool[reqt])
simple.solve()
for v in simple.variables():
print(v.name, "=", v.varValue)
产量
Result - Optimal solution found
Objective value: 15.70000000
Enumerated nodes: 0
Total iterations: 0
Time (CPU seconds): 0.00
Time (Wallclock seconds): 0.00
Option for printingOptions changed from normal to all
Total time (CPU seconds): 0.00 (Wallclock seconds): 0.00
build_op1 = 0.0
build_op2 = 2.0
commit_(1,_'op1',_'premium') = 0.0
commit_(1,_'op1',_'regular') = 0.0
commit_(1,_'op2',_'premium') = 7.0
commit_(1,_'op2',_'regular') = 0.0
commit_(2,_'op1',_'premium') = 0.0
commit_(2,_'op1',_'regular') = 0.0
commit_(2,_'op2',_'premium') = 13.0
commit_(2,_'op2',_'regular') = 0.0
commit_(3,_'op1',_'premium') = 0.0
commit_(3,_'op1',_'regular') = 0.0
commit_(3,_'op2',_'premium') = 0.0
commit_(3,_'op2',_'regular') = 10.0
[Finished in 175ms]