Algorithm 线性规划:我可以制定一个目标,一次最大化多个变量吗?

Algorithm 线性规划:我可以制定一个目标,一次最大化多个变量吗?,algorithm,mathematical-optimization,linear-programming,or-tools,Algorithm,Mathematical Optimization,Linear Programming,Or Tools,假设我有一些变量和约束,由以下系统说明: 灰线可以拉伸和收缩其顶部范围给定的量。蓝线只是端点,显示了灰线是如何相互作用的 我的目标:我想使用线性规划来均匀地最大化灰线的大小,如图所示。你可以想象这些灰色的线条,上面有弹簧,它们都是同样向外推的。一个糟糕的解决方案是将所有的蓝线尽可能地推到一边。请注意,在这个描述中有一点回旋余地,并且有多种解决方案是可能的——我所需要的是使它们合理地均匀,而不是让一个值最大化而挤压其他所有值 我尝试的目标函数只是最大化线的大小之和: maximize: (B -

假设我有一些变量和约束,由以下系统说明: 灰线可以拉伸和收缩其顶部范围给定的量。蓝线只是端点,显示了灰线是如何相互作用的

我的目标:我想使用线性规划来均匀地最大化灰线的大小,如图所示。你可以想象这些灰色的线条,上面有弹簧,它们都是同样向外推的。一个糟糕的解决方案是将所有的蓝线尽可能地推到一边。请注意,在这个描述中有一点回旋余地,并且有多种解决方案是可能的——我所需要的是使它们合理地均匀,而不是让一个值最大化而挤压其他所有值

我尝试的目标函数只是最大化线的大小之和:

maximize: (B - A) + (C - B) + (C - A) + (D - C) + (E - B) + (E - D) + (F - E) + (F - D) + (F - A) 
我很清楚,这不是一个好的解决方案,因为这些条件相互抵消,一行上的增加只会使另一行上的减少相同的数量,所以目标永远不会在变量之间平均分配最大值

我还试图尽量减少每条线与中间可能范围的距离。对于行
B-A
,其
(1,3)
范围内的中间值为
2
。第一学期的目标如下:

minimize: |(B - A) - 2| + ...
为了实现绝对值,我将术语替换为
U
,并添加了附加约束:

minimize: U + ...
with: U <= (B - A - 2)
      U <= -(B - A - 2)
最小化:U+。。。

记住,你最大的问题是你不知道你到底想要什么。所以我不得不猜测。有时候,看到一些猜测可以帮助你完善你想要的东西,所以这对你来说并不太糟糕,但它确实会让你的问题对于这个网站的格式更加困难

首先,我假设弹簧可以建模为有向无环图。也就是说,我可以用指向右侧的箭头替换所有弹簧。永远不会有从右向左的箭头(否则弹簧会弯曲成圆形)

完成此操作后,可以使用set逻辑来确定最左侧蓝色条的标识。(我假设只有一个-这是一个练习,以找出如何概括。)然后您可以将此条锚定在适当的位置。所有其他钢筋将相对其进行定位。此约束看起来像:

S[leftmost] = 0
现在,我们需要一些约束

每个边
i
都有一个源和终点(因为边是定向的)。调用源点的位置
S
和端点的位置
E
。此外,边缘具有最小长度
l
和最大长度
l
。因为我们锁定了最左边的蓝杆的位置,所以连接到蓝杆的弹簧定义了它们端点下落的间隔。这些端点是其他弹簧和c的源点。因此,每条边在其端点的位置上定义了两个约束

S[i]+l[i] <= E[i]
E[i]      <= S+L[i]
有问题的是,这个值可以是正的,也可以是负的,这取决于
(E[i]-S[i])>(L[i]+L[i])/2
。这是不好的,因为我们希望最小化与
(L[i]+L[i])/2的偏差,该值应始终为正值

为了解决这个问题,让我们将这个值平方,然后取一个平方根,它给出:

sqrt(((E[i]-S[i])-(L[i]+l[i])/2)^2)
这可能看起来无法解决,但请和我在一起

请注意,上述内容与采用单元素向量的L2范数相同,因此我们可以将其改写为:

|(E[i]-S[i])-(L[i]+l[i])/2|_2
现在,我们可以求每个条的偏差之和:

|(E[0]-S[0])-(L[0]+l[0])/2|_2 + |(E[1]-S[1])-(L[1]+l[1])/2|_2 + ...
这给我们带来了以下优化问题:

min |(E[0]-S[0])-(L[0]+l[0])/2|_2 + |(E[1]-S[1])-(L[1]+l[1])/2|_2 + ...
s.t.  S[leftmost]  = 0
      S[i]+l[i]   <= E[i]
      E[i]        <= S+L[i]
这个问题与前面的问题完全相同。那么我们得到了什么

优化是将问题转化为标准形式的游戏。一旦我们有了一个标准形式的问题,我们就可以站在巨人的肩膀上,使用强大的工具来解决我们的问题

上述操作已将问题转化为一个问题。一旦以这种形式出现,它就可以非常直接地解决

执行此操作的代码如下所示:

#!/usr/bin/env python3

import cvxpy as cp
import networkx as nx
import matplotlib.pyplot as plt

def FindTerminalPoints(springs):
  starts = set([x[0] for x in springs.edges()])
  ends   = set([x[1] for x in springs.edges()])
  return list(starts-ends), list(ends-starts)

springs = nx.DiGraph()
springs.add_edge('a', 'b', minlen= 1, maxlen= 3)
springs.add_edge('a', 'c', minlen= 1, maxlen= 4)
springs.add_edge('a', 'f', minlen=15, maxlen=15)
springs.add_edge('b', 'c', minlen= 0, maxlen= 1)
springs.add_edge('b', 'e', minlen= 9, maxlen=11)
springs.add_edge('c', 'd', minlen= 7, maxlen=11)
springs.add_edge('d', 'e', minlen= 0, maxlen= 1)
springs.add_edge('d', 'f', minlen= 3, maxlen= 6)
springs.add_edge('e', 'f', minlen= 3, maxlen= 5)

if not nx.is_directed_acyclic_graph(springs):
  raise Exception("Springs must be a directed acyclic graph!")

starts, ends = FindTerminalPoints(springs)
if len(starts)!=1:
  raise Exception("One unique start is needed!")

if len(ends)!=1:
  raise Exception("One unique end is needed!")  

start = starts[0]
end   = ends[0]

#At this point we have what is essentially a directed acyclic graph beginning at
#`start` and ending at `end`

#Generate a variable for the position of each blue bar
bluevars = {n: cp.Variable(name=n) for n in springs.nodes()}
dvars    = {e: cp.Variable()       for e in springs.edges()}
#Anchor the leftmost blue bar to prevent pathological solutions
cons   = [bluevars[start]==0]
for s,e in springs.edges():
  print("Loading edge {0}-{1}".format(s,e))
  sv   = bluevars[s]
  ev   = bluevars[e]
  edge = springs[s][e]
  cons += [sv+edge['minlen']<=ev]
  cons += [ev<=sv+edge['maxlen']]
  cons += [cp.norm((ev-sv)-(edge['maxlen']-edge['minlen'])/2,2)<=dvars[(s,e)]]

obj  = cp.Minimize(cp.sum(list(dvars.values())))
prob = cp.Problem(obj,cons)

val = prob.solve()

fig, ax = plt.subplots()
for var, val in bluevars.items():
  print("{:10} = {:10}".format(var,val.value))
  plt.plot([val.value,val.value],[0,3])

plt.show()
#!/usr/bin/env python3

import cvxpy as cp
import networkx as nx
import matplotlib.pyplot as plt
import itertools

def FindTerminalPoints(springs):
  starts = set([x[0] for x in springs.edges()])
  ends   = set([x[1] for x in springs.edges()])
  return list(starts-ends), list(ends-starts)

springs = nx.DiGraph()
springs.add_edge('a', 'b', minlen= 1, maxlen= 3)
springs.add_edge('a', 'c', minlen= 1, maxlen= 4)
springs.add_edge('a', 'f', minlen=15, maxlen=15)
springs.add_edge('b', 'c', minlen= 0, maxlen= 1)
springs.add_edge('b', 'e', minlen= 9, maxlen=11)
springs.add_edge('c', 'd', minlen= 7, maxlen=11)
springs.add_edge('d', 'e', minlen= 0, maxlen= 1)
springs.add_edge('d', 'f', minlen= 3, maxlen= 6)
springs.add_edge('e', 'f', minlen= 3, maxlen= 5)

if not nx.is_directed_acyclic_graph(springs):
  raise Exception("Springs must be a directed acyclic graph!")

starts, ends = FindTerminalPoints(springs)
if len(starts)!=1:
  raise Exception("One unique start is needed!")

if len(ends)!=1:
  raise Exception("One unique end is needed!")  

start = starts[0]
end   = ends[0]

#At this point we have what is essentially a directed acyclic graph beginning at
#`start` and ending at `end`

#Generate a variable for the position of each blue bar
bluevars = {n: cp.Variable(name=n) for n in springs.nodes()}

#Anchor the leftmost blue bar to prevent pathological solutions
cons   = [bluevars[start]==0]

#Constraint each blue bar to its range
for s,e in springs.edges():
  print("Loading edge {0}-{1}".format(s,e))
  sv   = bluevars[s]
  ev   = bluevars[e]
  edge = springs[s][e]
  cons += [sv+edge['minlen']<=ev]
  cons += [ev<=sv+edge['maxlen']]

dist_combos = list(itertools.combinations(springs.nodes(), 2))
dvars       = {(na,nb):cp.Variable() for na,nb in dist_combos}
distcons    = []
for na,nb in dist_combos:
  distcons += [cp.norm(bluevars[na]-bluevars[nb],2)<=dvars[(na,nb)]]

cons += distcons

#Find feasible locations for the blue bars. This is a heuristic for getting a
#sorted order for the bars
obj  = cp.Minimize(cp.sum(list(dvars.values())))
prob = cp.Problem(obj,cons)

val = prob.solve()

fig, ax = plt.subplots()
for var, val in bluevars.items():
  print("{:10} = {:10}".format(var,val.value))
  plt.plot([val.value,val.value],[0,3])

plt.show()
w[i]
越大,所讨论的弹簧接近其平均长度就越重要

根据约束条件最小化有序蓝色条之间的平方距离 使用与上述相同的策略,我们可以最小化蓝色条之间的平方距离,并假定某种已知顺序。这导致:

min   t[0] + t[1] + ...
s.t.  S[leftmost]  = 0
      S[i]+l[i]   <= E[i]
      E[i]        <= S+L[i]
      |(S[i]-S[i+1])/2|_2<=t[i]
mint[0]+t[1]+。。。
s、 t.s[最左边]=0

S[i]+l[i]记住,你最大的问题是你不知道你到底想要什么。所以我不得不猜测。有时候,看到一些猜测可以帮助你完善你想要的东西,所以这对你来说并不太糟糕,但它确实会让你的问题对于这个网站的格式更加困难

首先,我假设弹簧可以建模为有向无环图。也就是说,我可以用指向右侧的箭头替换所有弹簧。永远不会有从右向左的箭头(否则弹簧会弯曲成圆形)

完成此操作后,可以使用set逻辑来确定最左侧蓝色条的标识。(我假设只有一个-这是一个练习,以找出如何概括。)然后您可以将此条锚定在适当的位置。所有其他钢筋将相对其进行定位。此约束看起来像:

S[leftmost] = 0
现在,我们需要一些约束

每个边
i
都有一个源和终点(因为边是定向的)。调用源点的位置
S
和端点的位置
E
。此外,边缘具有最小长度
l
和最大长度
l
。因为我们锁定了最左边的蓝杆的位置,所以连接到蓝杆的弹簧定义了它们端点下落的间隔。这些终点是a
#!/usr/bin/env python3

import cvxpy as cp
import networkx as nx
import matplotlib.pyplot as plt

def FindTerminalPoints(springs):
  starts = set([x[0] for x in springs.edges()])
  ends   = set([x[1] for x in springs.edges()])
  return list(starts-ends), list(ends-starts)

springs = nx.DiGraph()
springs.add_edge('a', 'b', minlen= 1, maxlen= 3)
springs.add_edge('a', 'c', minlen= 1, maxlen= 4)
springs.add_edge('a', 'f', minlen=15, maxlen=15)
springs.add_edge('b', 'c', minlen= 0, maxlen= 1)
springs.add_edge('b', 'e', minlen= 9, maxlen=11)
springs.add_edge('c', 'd', minlen= 7, maxlen=11)
springs.add_edge('d', 'e', minlen= 0, maxlen= 1)
springs.add_edge('d', 'f', minlen= 3, maxlen= 6)
springs.add_edge('e', 'f', minlen= 3, maxlen= 5)

if not nx.is_directed_acyclic_graph(springs):
  raise Exception("Springs must be a directed acyclic graph!")

starts, ends = FindTerminalPoints(springs)
if len(starts)!=1:
  raise Exception("One unique start is needed!")

if len(ends)!=1:
  raise Exception("One unique end is needed!")  

start = starts[0]
end   = ends[0]

#At this point we have what is essentially a directed acyclic graph beginning at
#`start` and ending at `end`

#Generate a variable for the position of each blue bar
bluevars = {n: cp.Variable(name=n) for n in springs.nodes()}
dvars    = {e: cp.Variable()       for e in springs.edges()}
#Anchor the leftmost blue bar to prevent pathological solutions
cons   = [bluevars[start]==0]
for s,e in springs.edges():
  print("Loading edge {0}-{1}".format(s,e))
  sv   = bluevars[s]
  ev   = bluevars[e]
  edge = springs[s][e]
  cons += [sv+edge['minlen']<=ev]
  cons += [ev<=sv+edge['maxlen']]
  cons += [cp.norm((ev-sv)-(edge['maxlen']-edge['minlen'])/2,2)<=dvars[(s,e)]]

obj  = cp.Minimize(cp.sum(list(dvars.values())))
prob = cp.Problem(obj,cons)

val = prob.solve()

fig, ax = plt.subplots()
for var, val in bluevars.items():
  print("{:10} = {:10}".format(var,val.value))
  plt.plot([val.value,val.value],[0,3])

plt.show()
min   w[0]*t[0] + w[1]*t[1] + ...
s.t.  S[leftmost]  = 0
      S[i]+l[i]   <= E[i]
      E[i]        <= S+L[i]
      |(E[i]-S[i])-(L[i]+l[i])/2|_2<=t[i]
min   t[0] + t[1] + ...
s.t.  S[leftmost]  = 0
      S[i]+l[i]   <= E[i]
      E[i]        <= S+L[i]
      |(S[i]-S[i+1])/2|_2<=t[i]
#!/usr/bin/env python3

import cvxpy as cp
import networkx as nx
import matplotlib.pyplot as plt

def FindTerminalPoints(springs):
  starts = set([x[0] for x in springs.edges()])
  ends   = set([x[1] for x in springs.edges()])
  return list(starts-ends), list(ends-starts)

springs = nx.DiGraph()
springs.add_edge('a', 'b', minlen= 1, maxlen= 3)
springs.add_edge('a', 'c', minlen= 1, maxlen= 4)
springs.add_edge('a', 'f', minlen=15, maxlen=15)
springs.add_edge('b', 'c', minlen= 0, maxlen= 1)
springs.add_edge('b', 'e', minlen= 9, maxlen=11)
springs.add_edge('c', 'd', minlen= 7, maxlen=11)
springs.add_edge('d', 'e', minlen= 0, maxlen= 1)
springs.add_edge('d', 'f', minlen= 3, maxlen= 6)
springs.add_edge('e', 'f', minlen= 3, maxlen= 5)

if not nx.is_directed_acyclic_graph(springs):
  raise Exception("Springs must be a directed acyclic graph!")

starts, ends = FindTerminalPoints(springs)
if len(starts)!=1:
  raise Exception("One unique start is needed!")

if len(ends)!=1:
  raise Exception("One unique end is needed!")  

start = starts[0]
end   = ends[0]

#At this point we have what is essentially a directed acyclic graph beginning at
#`start` and ending at `end`

#Generate a variable for the position of each blue bar
bluevars = {n: cp.Variable(name=n) for n in springs.nodes()}

#Anchor the leftmost blue bar to prevent pathological solutions
cons   = [bluevars[start]==0]

#Constraint each blue bar to its range
for s,e in springs.edges():
  print("Loading edge {0}-{1}".format(s,e))
  sv   = bluevars[s]
  ev   = bluevars[e]
  edge = springs[s][e]
  cons += [sv+edge['minlen']<=ev]
  cons += [ev<=sv+edge['maxlen']]

#Find feasible locations for the blue bars. This is a heuristic for getting a
#sorted order for the bars
obj  = cp.Minimize(1)
prob = cp.Problem(obj,cons)

prob.solve()

#Now that we have a sorted order, we modify the objective to minimize the
#squared distance between the ordered bars
bar_locs = list(bluevars.values())
bar_locs.sort(key=lambda x: x.value)

dvars = [cp.Variable() for n in range(len(springs.nodes())-1)]
for i in range(len(bar_locs)-1):
  cons += [cp.norm(bar_locs[i]-bar_locs[i+1],2)<=dvars[i]]

obj  = cp.Minimize(cp.sum(dvars))
prob = cp.Problem(obj,cons)

val = prob.solve()

fig, ax = plt.subplots()
for var, val in bluevars.items():
  print("{:10} = {:10}".format(var,val.value))
  plt.plot([val.value,val.value],[0,3])

plt.show()
min   t[i,j] + ...                 for all i,j
s.t.  S[leftmost]        = 0
      S[i]+l[i]         <= E[i]    for all i
      E[i]              <= S+L[i]  for all i
      |(S[i]-S[j])/2|_2 <= t[i,j]  for all i,j
#!/usr/bin/env python3

import cvxpy as cp
import networkx as nx
import matplotlib.pyplot as plt
import itertools

def FindTerminalPoints(springs):
  starts = set([x[0] for x in springs.edges()])
  ends   = set([x[1] for x in springs.edges()])
  return list(starts-ends), list(ends-starts)

springs = nx.DiGraph()
springs.add_edge('a', 'b', minlen= 1, maxlen= 3)
springs.add_edge('a', 'c', minlen= 1, maxlen= 4)
springs.add_edge('a', 'f', minlen=15, maxlen=15)
springs.add_edge('b', 'c', minlen= 0, maxlen= 1)
springs.add_edge('b', 'e', minlen= 9, maxlen=11)
springs.add_edge('c', 'd', minlen= 7, maxlen=11)
springs.add_edge('d', 'e', minlen= 0, maxlen= 1)
springs.add_edge('d', 'f', minlen= 3, maxlen= 6)
springs.add_edge('e', 'f', minlen= 3, maxlen= 5)

if not nx.is_directed_acyclic_graph(springs):
  raise Exception("Springs must be a directed acyclic graph!")

starts, ends = FindTerminalPoints(springs)
if len(starts)!=1:
  raise Exception("One unique start is needed!")

if len(ends)!=1:
  raise Exception("One unique end is needed!")  

start = starts[0]
end   = ends[0]

#At this point we have what is essentially a directed acyclic graph beginning at
#`start` and ending at `end`

#Generate a variable for the position of each blue bar
bluevars = {n: cp.Variable(name=n) for n in springs.nodes()}

#Anchor the leftmost blue bar to prevent pathological solutions
cons   = [bluevars[start]==0]

#Constraint each blue bar to its range
for s,e in springs.edges():
  print("Loading edge {0}-{1}".format(s,e))
  sv   = bluevars[s]
  ev   = bluevars[e]
  edge = springs[s][e]
  cons += [sv+edge['minlen']<=ev]
  cons += [ev<=sv+edge['maxlen']]

dist_combos = list(itertools.combinations(springs.nodes(), 2))
dvars       = {(na,nb):cp.Variable() for na,nb in dist_combos}
distcons    = []
for na,nb in dist_combos:
  distcons += [cp.norm(bluevars[na]-bluevars[nb],2)<=dvars[(na,nb)]]

cons += distcons

#Find feasible locations for the blue bars. This is a heuristic for getting a
#sorted order for the bars
obj  = cp.Minimize(cp.sum(list(dvars.values())))
prob = cp.Problem(obj,cons)

val = prob.solve()

fig, ax = plt.subplots()
for var, val in bluevars.items():
  print("{:10} = {:10}".format(var,val.value))
  plt.plot([val.value,val.value],[0,3])

plt.show()