编程语言
首页 > 编程语言> > python-constraint:根据函数的输出设置约束

python-constraint:根据函数的输出设置约束

作者:互联网

我一直在开发一个系统,该系统接收有关驾驶员,潜在乘客及其位置的数据,并尝试在给定限制的情况下优化可以乘搭电梯的乘客数量.我正在使用python-constraint模块,因此决策变量表示为:

p = [(passenger, driver) for driver in drivers for passenger in passengers]
driver_set = [zip(passengers, [e1]*len(drivers)) for e1 in drivers]
passenger_set = [zip([e1]*len(passengers), drivers) for e1 in passengers]
self.problem.addVariables(p, [0,1])

因此,当我打印p的值以及driver_set和passenger_set时,得到以下输出(鉴于我提供的测试数据):

[(0, 0), (1, 0), (2, 0), (0, 1), (1, 1), (2, 1)] # p
[[(0, 0), (0, 1)], [(1, 0), (1, 1)], [(2, 0), (2, 1)]] # passenger_set
[[(0, 0), (1, 0)], [(0, 1), (1, 1)]] # driver_set

因此,有3名乘客和2名驾驶员:变量(2,0)表示乘客2在轿厢0中,依此类推.我添加了以下约束条件,以确保没有乘客乘坐多于一辆汽车,并且驾驶员的人数不能超过座位数:

for passenger in passenger_set:
        self.problem.addConstraint(MaxSumConstraint(1), passenger)
for driver in driver_set:
        realdriver = self.getDriverByOpId(driver[0][1])
        self.problem.addConstraint(MaxSumConstraint(realdriver.numSeats), driver)

这行得通-生成的所有解决方案都满足了这些约束.但是,我现在要添加约束条件,说任何解决方案都不应让驾驶员走超过一定距离.我有一个函数,可以接受驾驶员(与driver_set中的实体格式相同),并计算出驾驶员接载所有乘客的最短距离.我试图添加这样的约束:

for driver in driver_set:
        self.problem.addConstraint(MaxSumConstraint(MAX_DISTANCE), [self.getRouteDistance(self.getShortestRoute(driver))])

这产生了以下错误:

KeyError: 1.8725031790578293

我不确定应该如何为python-constraint定义此约束:每个驱动程序只有一个最短的距离值.我应该为此使用lambda函数吗?

编辑

我尝试实现此功能的lambda版本,但是我似乎没有降低lambda语法.我到处都看过,但似乎找不到这是怎么回事.基本上,我替换了最后一小段代码(添加了约束以限制getRouteDistance(driver)的值),而是将其放置为:

for driver in driver_set:
    self.problem.addConstraint(lambda d: self.getRouteDistance(d) <= float(MAX_DISTANCE), driver)

但是然后我得到了这个错误(请注意,它不是从我编辑的行中调用的,它是来自后来出现的问题.

File "allocation.py", line 130, in buildProblem
for solution in self.problem.getSolutions():
File "/Users/wadben/Documents/Dev/Python/sp-allocation/constraint.py", line 236, in getSolutions
return self._solver.getSolutions(domains, constraints, vconstraints)
File "/Users/wadben/Documents/Dev/Python/sp-allocation/constraint.py", line 529, in getSolutions
return list(self.getSolutionIter(domains, constraints, vconstraints))
File "/Users/wadben/Documents/Dev/Python/sp-allocation/constraint.py", line 506, in getSolutionIter
pushdomains):
File "/Users/wadben/Documents/Dev/Python/sp-allocation/constraint.py", line 939, in __call__
self.forwardCheck(variables, domains, assignments)))
File "/Users/wadben/Documents/Dev/Python/sp-allocation/constraint.py", line 891, in forwardCheck
if not self(variables, domains, assignments):
File "/Users/wadben/Documents/Dev/Python/sp-allocation/constraint.py", line 940, in __call__
return self._func(*parms)
TypeError: <lambda>() takes exactly 1 argument (3 given)

有没有其他人试图做这样的事情?我看不到为什么约束库不允许这样做.

解决方法:

Python中的lambda表单提供了一种创建匿名(无名)函数的方法.以下两个定义是等效的:

name = lambda arguments: expression

def name(arguments):
    return expression

由于lambda表达式的主体本身就是一个表达式,因此主体可以不包含任何语句(如print).

向问题添加函数约束时,必须确保该函数接受的变量与变量一样多.当应用约束时,每个参数都传递一个当前绑定到相应变量的值(根据约定,驾驶员和乘客一起乘车为1,否则为0).

由于与给定驾驶员相关联的变量数量(等于乘客数量)可能会发生变化,因此约束中的函数接受任意数量的参数将是明智的.这可以在Python中使用位置参数来完成.因此,对于给定的一组驱动程序变量(此处使用名称driver_variables),约束采用以下形式:

problem.addConstraint(FunctionConstraint(lambda *values: ...), driver_variables)

参数值绑定到当前绑定到driver_variables列表中的相应变量的值的列表.应编写lambda正文,以便执行以下操作:

>创建一个列表,将值列表中的每个值(0或1)与driver_variables列表中的相应变量相关联;
>从此列表中,选择值为1的变量(对应于与驾驶员一起骑行的乘客)-该列表形成驾驶员选择的路线;
>查找路线距离(在此示例中使用get_route_distance函数),然后将其与最大值(maximum_distance)进行比较.

可以对(1)使用zip(保证值的顺序与变量的顺序相同),对(2)的列表理解以及对(3)的简单函数调用和比较.这产生一个采用以下lambda形式的函数:

lambda *values: get_route_distance([variable for variable, value in zip(driver_variables, values) if value == 1]) <= maximum_distance

事实证明,使用def显式编写此功能可能有益于代码的可读性.

另外,上面的定义driver_set的代码中有一个错误. driver_set的正确值应为:

[[(0, 0), (1, 0), (2, 0)], [(0, 1), (1, 1), (2, 1)]]

在上面的示例中,由于len(drivers)为2,因此zip(passengers,[e1] * len(drivers))仅被截断为两个项目.解决此问题的一种方法是对driver_set使用表达式zip(passengers,[e1] * len(passengers))(对passenger_set进行类似的更改).但是,还有一种更Python化的方法.

可以使用以下语句生成正确的乘客和驾驶员集合(在此示例中为passengers_variables和drivers_variables):

passengers_variables = [[(passenger, driver) for driver in drivers] for passenger in passengers]
drivers_variables = [[(passenger, driver) for passenger in passengers] for driver in drivers]

标签:constraints,shortest-path,python
来源: https://codeday.me/bug/20191208/2093535.html