You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于OptaPlanner的整数网络流问题建模与约束实现咨询

OptaPy整数网络流问题建模解决方案

一、建模方向正确性确认

你的思路是正确的,核心建模逻辑需符合以下要点:

  • 问题事实:定义Node(标记是否为源/汇节点)和Edge(包含流量上下限、单位成本、源/目标节点ID),这是网络流问题的标准事实建模方式。
  • 规划实体与变量:将Edge作为规划实体,把每个边上的flow设为整数型规划变量,绑定边自身的流量上下限作为变量范围。如果你的初步定义符合这个逻辑,就是正确的。

二、流量边界硬约束实现

直接针对每个边的流量值做范围校验,违反则触发硬约束惩罚:

from optapy import constraint_provider
from optapy.types import HardSoftScore

@constraint_provider
def define_constraints(constraint_factory):
    constraints = []
    # 流量边界硬约束
    constraints.append(
        constraint_factory.for_each(Edge)
            .filter(lambda edge: edge.flow < edge.min_flow or edge.flow > edge.max_flow)
            .penalize("流量超出边界", HardSoftScore.ONE_HARD)
            .build()
    )
    # 后续添加其他约束...
    return constraints

三、流量守恒硬约束实现

这是核心难点,需统计每个非源汇节点的流入总量与流出总量,确保两者相等。以下是两种可行实现方式:

方式一:按节点分组统计

# 流量守恒硬约束
    constraints.append(
        constraint_factory.for_each(Node)
            .filter(lambda node: not node.is_source and not node.is_sink)
            # 关联流入该节点的边,统计流入总量
            .join(Edge, lambda node, edge: node.id == edge.target_node_id)
            .group_by(lambda node, edge: node, sum(lambda node, edge: edge.flow))
            # 关联流出该节点的边,统计流出总量
            .join(Edge, lambda node_inflow, edge: node_inflow[0].id == edge.source_node_id)
            .group_by(lambda node_inflow, edge: node_inflow[0], 
                      lambda node_inflow, edge: node_inflow[1], 
                      sum(lambda node_inflow, edge: edge.flow))
            # 校验流入流出是否相等,按差值惩罚
            .filter(lambda node, inflow, outflow: inflow != outflow)
            .penalize("流量不守恒", HardSoftScore.ONE_HARD, 
                      lambda node, inflow, outflow: abs(inflow - outflow))
            .build()
    )

方式二:先统计全节点流入流出再校验

# 流量守恒硬约束(另一种写法)
    constraints.append(
        constraint_factory.for_each(Edge)
            # 统计每个节点的流出总量
            .group_by(lambda edge: edge.source_node_id, sum(lambda edge: edge.flow))
            # 关联流入该节点的边,统计流入总量
            .join(Edge, lambda source_sum, edge: source_sum[0] == edge.target_node_id)
            .group_by(lambda source_sum, edge: source_sum[0], 
                      lambda source_sum, edge: source_sum[1], 
                      sum(lambda source_sum, edge: edge.flow))
            # 关联节点信息,过滤源汇节点
            .join(Node, lambda node_flow, node: node_flow[0] == node.id)
            .filter(lambda node, outflow, inflow: not node.is_source and not node.is_sink and outflow != inflow)
            .penalize("流量不守恒", HardSoftScore.ONE_HARD, 
                      lambda node, outflow, inflow: abs(outflow - inflow))
            .build()
    )

四、最小化流量成本软约束实现

将所有边的流量与单位成本的乘积之和作为软约束惩罚,OptaPlanner会自动最小化总惩罚值(即最小化总成本):

# 最小化流量成本软约束
    constraints.append(
        constraint_factory.for_each(Edge)
            .penalize("流量成本", HardSoftScore.ONE_SOFT, 
                      lambda edge: edge.flow * edge.unit_cost)
            .build()
    )

补充:规划实体与变量标准定义示例

如果你的初步定义有疑问,参考以下写法:

from optapy import PlanningEntity, PlanningVariable, PlanningId, ValueRangeProvider, ValueRangeProviderType

@PlanningEntity
class Edge:
    def __init__(self, id, source_node_id, target_node_id, min_flow, max_flow, unit_cost):
        self.id = id
        self.source_node_id = source_node_id
        self.target_node_id = target_node_id
        self.min_flow = min_flow
        self.max_flow = max_flow
        self.unit_cost = unit_cost
        self.flow = None  # 规划变量

    @PlanningId
    def get_id(self):
        return self.id

    @PlanningVariable(range_provider_refs=["flowRange"], 
                      value_range_provider_type=ValueRangeProviderType.INTEGER)
    def get_flow(self):
        return self.flow

    def set_flow(self, flow):
        self.flow = flow

# 为每个边提供对应流量范围
@ValueRangeProvider(id="flowRange")
def get_flow_range(edge):
    return range(edge.min_flow, edge.max_flow + 1)

# 节点问题事实定义
class Node:
    def __init__(self, id, is_source=False, is_sink=False):
        self.id = id
        self.is_source = is_source
        self.is_sink = is_sink

    @PlanningId
    def get_id(self):
        return self.id

内容的提问来源于stack exchange,提问作者Fabian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 20:36:23