我正在与“更高级别”的ConstraintStreams (bi,tri ..)作斗争。在Optaplanner用户指南中,显示了最简单的案例,我理解它们。同样,通过这些示例,我能够对BiConstraintStream求和。现在我有了一个TriConstraintStream,并且面临着问题。有谁知道更好的信息来源来更好地理解ConstraintStreams吗?
我的案例:问题结构与运输问题非常相似。我有节点和边,想要计算边的数量。
我的主要问题是:
class Node{
UUID id;
int itemsInInventory;
...
}和规划实体:
@PlanningEntity
class Edge{
Node from;
Node to;
@PlanningVariable
int itemsTransported;
getFromId(){return from.getId()}
getToId(){return to.getId()}
}我希望将边连接到节点中两次,然后groupBy它们确实有一个像(Node, Sum(to), Sum(from))这样的对象
约束的当前代码为:
public Constraint minimizeShortage(ConstraintFactory constraintFactory) {
return constraintFactory.fromUnfiltered(Node.class)
.join(Edge.class,
equal(Node::getId, Edge::getFromId))
.join(Edge.class,
equal((node, edge) -> node.getId(), Edge::getToId))
groupBy(...)
}对于BiConstraintStream (仅使用fromNode或toNode),groupBy将为.groupBy((node, edge) -> node, sum((node, edge) -> edge.getItemsTransported())),但在第二次连接后,我没有获得TriConstraintStream。
发布于 2021-04-27 15:40:03
我将把前面答案中的代码作为我的起点:
public Constraint minimizeShortage(ConstraintFactory constraintFactory) {
return constraintFactory.fromUnfiltered(Node.class)
.join(Edge.class,
equal(Node::getId, Edge::getFromId))
.groupBy((node, edgeFrom) -> node,
sum((node, tsaO) -> edgeFrom.transportedItems()))
.join(Edge.class,
equal((node, edge) -> node.getId(), Edge::getToId))
.groupBy((node, edgeFrom, edgeTo) -> node,
(node, edgeFrom, edgeTo) -> qtO,
sum((node, qtO, edgeTo) -> edgeTo.transportedItems()))
...
}这段代码不太可能执行得很好,因为groupBy()是昂贵的,并且链接它们会使问题逐渐变得更糟。让我们看看我们是否可以用一个groupBy()做同样的事情
public Constraint minimizeShortage(ConstraintFactory constraintFactory) {
return constraintFactory.fromUnfiltered(Node.class)
.join(Edge.class,
equal(Node::getId, Edge::getFromId))
.join(Edge.class,
equal((node, edge) -> node.getId(), Edge::getToId))
.groupBy((node, edgeFrom, edgeTo) -> node,
sum((node, edgeFrom, edgeTo) -> edgeFrom.transportedItems()),
sum((node, edgeFrom, edgeTo) -> edgeTo.transportedItems())
...
}让我们再多讨论一下。这个特殊的groupBy()重载由两部分组成:键映射和收集器。
键映射将三元组分成组-在本例中((node, edgeFrom, edgeTo) -> node)具有相同node的所有三元组将落入同一组。
然后,每个收集器对每个这样的三元组应用给定的操作(在本例中为sum),从而产生一个结果。我们在这里使用了两个收集器,一个收集器汇总在edgeFrom中传输的项目,另一个收集器对edgeTo执行相同的操作。这两个收集器只适用于共享相同node的边-正如前面提到的键映射所保证的那样。
顺便说一句,在开发像这样的非平凡约束时,我绝对建议使用Constraint Verifier对一些典型的结果进行建模,并查看约束是否按预期运行。
发布于 2021-04-27 06:45:31
我找到了解决我的问题的办法。解决方案是使用下面的语法,特别是不要在一个groupBy中总结。我必须将求和分成两个groupBys,并按以下顺序进行计算: Join1 - groupBy1 - join2 - groupBy2。
public Constraint minimizeShortage(ConstraintFactory constraintFactory) {
return constraintFactory.fromUnfiltered(Node.class)
.join(Edge.class,
equal(Node::getId, Edge::getFromId))
.groupBy((node, edgeFrom) -> node,
sum((node, tsaO) -> edgeFrom.transportedItems()))
.join(Edge.class,
equal((node, edge) -> node.getId(), Edge::getToId))
.groupBy((node, edgeFrom, edgeTo) -> node,
(node, edgeFrom, edgeTo) -> qtO,
sum((node, qtO, edgeTo) -> edgeTo.transportedItems()))
...
}https://stackoverflow.com/questions/67271731
复制相似问题