方法。
使用约束库生成满足事件约束条件的所有事件顺序,不考虑 (不)均匀性,然后迭代地找到具有最小不均匀性的受约束解决方案。
什么是均匀性?
如果不均匀性是通过查看计算出的所有天数和事件天数之间的差异,并返回最大值减去最小值的天数差异来定义的,则需要澄清您的回答:
1 2 3 4 5 6 7
a b c
这句话的意思是它的数值相对于日期偏向于左侧。
更好的回答可能是:
1 2 3 4 5 6 7
a b c
将“一次向右移动”后,从第七天到任何事件日的拉伸程度减少了。
如果您认为上述内容是等价的,那么您需要更好地定义“均匀性”-也许是在事件天数的范围内的均匀性?
最新消息!作者已编辑“均匀性”,现在描述更加清晰。
代码
如果您只需按回车键即可运行示例,则源已设置好。
"""
Even distribution of directed acyclic graph with respect to edge length
https://dev59.com/0MPra4cB1Zd3GeqPs_MT
Created on Sat Mar 26 08:53:19 2022
@author: paddy
"""
from constraint import Problem
from itertools import product
days = input("Days: int = ")
try:
days = int(days.strip())
except:
days = 7
print(f"Using {days=}")
events = input("events: space_separated = ")
events = events.strip().split()
if not events:
events = list("abc")
print(f"Using {events=}")
constraint_funcs = []
while True:
constr = input("constraint: string_expression (. to end) = ").strip()
if not constr:
constraint_funcs = ["1 <= (b - a) <=2",
"(c - a) <= 4",
"(c - b) >= 3"]
break
if constr == '.':
break
constraint_funcs.append(constr)
print(f"\nUsing {constraint_funcs=}")
print()
problem = Problem()
problem.addVariables(events, range(1, days+1))
for constr in constraint_funcs:
constr_events = sorted( set(events) & set(compile(constr, '<input>',
mode='eval').co_names))
expr = f"lambda {', '.join(constr_events)}: {constr}"
print(f" Add Constraint {expr!r}, On {constr_events}")
func = eval(expr)
problem.addConstraint(func, constr_events)
print()
def unevenness(event_days: list[int], all_days: int):
"(Max - min diff between ordered events, leftmost event)"
maxdiff, mindiff = -1, all_days + 1
for event, next_event in zip(event_days, event_days[1:]):
diff = next_event - event
maxdiff = max(maxdiff, diff)
mindiff = min(mindiff, diff)
return maxdiff - mindiff, event_days[0]
def printit(solution, all_days):
drange = range(1, all_days+1)
print(' '.join(str(i)[0] for i in drange))
for event, day in sorted(solution.items(), key=lambda kv: kv[::-1]):
print(' ' * (day - 1) + event )
print()
current_best = None, 9e99
for ans in problem.getSolutionIter():
unev = unevenness(sorted(ans.values()), days)
if current_best[0] is None or unev < current_best[1]:
current_best = ans, unev
print("Best so far:")
printit(ans, days)
不均匀函数已更新。更好的函数可能是最小化连续事件之间天数的标准偏差,但对于这个示例,这个函数可行。
输出
使用您的约束条件进行样本运行,但事件名称更长。
Days: int = 7
Using days=7
events: space_separated = arch belt card
Using events=['arch', 'belt', 'card']
constraint: string_expression (. to end) = 1 <= (belt - arch) <= 2
constraint: string_expression (. to end) = (card - arch) <= 4
constraint: string_expression (. to end) = (card - belt) >= 3
constraint: string_expression (. to end) = .
Using constraint_funcs=['1 <= (belt - arch) <= 2', '(card - arch) <= 4', '(card - belt) >= 3']
Add Constraint 'lambda arch, belt: 1 <= (belt - arch) <= 2', On ['arch', 'belt']
Add Constraint 'lambda arch, card: (card - arch) <= 4', On ['arch', 'card']
Add Constraint 'lambda belt, card: (card - belt) >= 3', On ['belt', 'card']
Best so far:
1 2 3 4 5 6 7
arch
belt
card
Best so far:
1 2 3 4 5 6 7
arch
belt
card
Best so far:
1 2 3 4 5 6 7
arch
belt
card
注意:事件名称的
第一个字母与日期列对齐。
unevenness函数返回元组的第二个项目是最早(最左侧)事件发生的日期。如果事件的分布相等,则在最小化时倾向于更靠左的解决方案。