跳转至

建模接口

OptAgent 使用 ModelBuilder 描述优化问题。建模阶段的目标是把业务问题转成一个可执行的 program,后续求解器和编排器都围绕这个 program 工作。

基本流程

  1. 创建 ModelBuilder
  2. 添加变量。
  3. 用表达式组合约束和目标。
  4. 调用 freeze() 生成可求解的 program
from optagent import ModelBuilder

# 1. 创建建模入口,并记录案例名。
builder = ModelBuilder(metadata={"case": "knapsack_small"})

# 2. 准备业务数据:每个物品的重量和价值。
weights = [2, 3, 4]
values = [4, 5, 7]

# 3. 为每个物品创建一个 0/1 决策变量,1 表示选择该物品。
picks = [
    builder.int_var(default=0, lb=0, ub=1, name=f"pick_{idx}")
    for idx in range(len(weights))
]

# 4. 用表达式计算总重量和总价值。
total_weight = builder.sum(*(pick * weight for pick, weight in zip(picks, weights, strict=True)))
total_value = builder.sum(*(pick * value for pick, value in zip(picks, values, strict=True)))

# 5. 登记背包容量约束和收益最大化目标。
builder.constraint(total_weight <= 5, name="capacity")
builder.maximize(total_value, name="profit")

# 6. 冻结为可求解的 ExecutableProgram。
program = builder.freeze()

常用变量

方法 用途
bool_var(...) 0/1 或布尔决策
int_var(...) 整数决策,可设置 lb / ub
float_var(...) 连续数值决策
set_var(...) 集合型选择
sequence_var(...) 排列、路径、访问顺序
interval_var(...) 调度任务的开始、结束、长度

表达式与约束

变量和常量可以直接组合为表达式:

# 1. 组合变量和常量,得到一个成本表达式。
cost = (x * 3) + (y * 5)

# 2. 调用 constraint 后,该表达式才会成为正式约束。
builder.constraint(cost <= 20, name="budget")

常见表达式工具包括:

方法 用途
sum(...) 多个表达式求和
min(...) / max(...) 聚合最小值或最大值
abs(...) 绝对值
all_different(...) 互异约束
element(array, index) 根据索引取数组值
external_call(...) 接入黑盒目标或外部函数

约束是单独登记的

表达式本身只是在图中构造条件,只有调用 constraint(...) 后才会被注册为正式约束:

# 1. 登记容量约束。
builder.constraint(total_weight <= 5, name="capacity")

# 2. 登记二选一约束。
builder.constraint(x + y == 1, name="choose_one")

如果只写了 total_weight <= 5,但没有传给 constraint(...),这个条件不会进入模型的约束列表。

目标函数

使用 minimize(...)maximize(...) 声明目标:

# 1. 最小化总成本。
builder.minimize(total_cost, name="total_cost")

# 2. 或最大化总收益。
builder.maximize(total_profit, name="profit")

一个模型可以记录多个目标,但实际求解能力取决于当前求解路径和后端支持范围。公开示例中建议先从单目标问题开始。

特殊建模方法

除了通用数值建模,ModelBuilder 还提供了几类针对优化结构的专用方法。

集合与序列

方法 用途
set_len(set_expr) 集合大小
set_contains(set_expr, value_expr) 元素是否在集合中
sequence_contains(sequence_expr, value_expr) 元素是否在序列中
all_different(...) 互异约束
table(exprs, allowed_tuples) 允许元组表约束

调度

方法 用途
interval_start(interval_expr) 读取 interval 开始时间
interval_end(interval_expr) 读取 interval 结束时间
interval_length(interval_expr) 读取 interval 长度
cumulative(intervals, demands, capacity) 累积资源约束
no_overlap(sequence_expr, *interval_exprs) 不重叠约束
precedence(before, after, lag=0) 前后工序约束

条件与逻辑

方法 用途
and_(lhs, rhs) 逻辑与
or_(lhs, rhs) 逻辑或
not_(expr) 逻辑非
iif(cond, when_true, when_false) 条件表达式

黑盒与外部函数

方法 用途
external_call(fn, *inputs, ...) 将 Python 函数登记为外部调用节点
def score(order):
    # 1. 外部函数接收求解器给出的候选序列,并返回评分。
    return len(order)

# 2. route 是待优化的排列型决策变量。
route = builder.sequence_var(5, name="route")

# 3. external_call 把 Python 函数接入模型图。
blackbox_score = builder.external_call(score, route, name="route_score")

# 4. 将黑盒评分登记为目标。
builder.minimize(blackbox_score, name="score")

freeze() 的含义

freeze() 会把当前 builder 中的图结构编译为 ExecutableProgram

# 1. freeze 会编译当前图结构。
program = builder.freeze()

生成 program 后,建模图会被冻结,后续应把它交给 Orchestrator().run(...) 求解。

完整公开方法范围

当前公开建模接口可按下面分组理解:

分组 方法
常量与变量 const, bool_var, int_var, float_var, set_var, sequence_var, interval_var
聚合与逻辑 abs, sum, min, max, and_, or_, not_, iif
集合与序列 set_len, set_contains, sequence_contains, all_different, element, table
调度 interval_start, interval_end, interval_length, cumulative, no_overlap, precedence
黑盒 external_call
模型登记 constraint, minimize, maximize
输出 to_program_spec, freeze

下一步