建模接口¶
OptAgent 使用 ModelBuilder 描述优化问题。建模阶段的目标是把业务问题转成一个可执行的 program,后续求解器和编排器都围绕这个 program 工作。
基本流程¶
- 创建
ModelBuilder。 - 添加变量。
- 用表达式组合约束和目标。
- 调用
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:
生成 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 |
下一步¶
- 发起求解:阅读 求解接口。
- 查完整对象成员:阅读 Builder API。
- 看完整线性示例:从 示例入口 跳转到公开示例仓库。