# 建模指南

用 `OptModel` 同时管理决策变量、派生表达式、约束和目标。所有参与同一个表达式的节点必须属于同一个模型。

## 数值变量与约束

```python
from optagent import OptModel

model = OptModel()
x = model.int(0, 10)
y = model.int(0, 10)
cost = 2 * x + y
model.constraint(x + y >= 7)
model.minimize(cost)
```

`int()` 和 `float()` 的上下界包含端点；省略边界表示未声明该边界。建议提供业务上有效的边界，尤其是需要有限域转换的模型。`default` 是初始值，不是固定变量的约束；省略时由内核构造初始候选。

!!! tip "表达式不是 Python 布尔值"
    使用 `&`、`|`、`~` 或 `model.and_()`、`model.or_()` 组合条件；两侧比较表达式加括号。不要使用 Python 的 `and`、`or`、`if expression` 或链式比较来构造约束。条件表达式使用 `model.iif(condition, when_true, when_false)`。

## 集合与序列

`set(n)` 和 `list(n)` 的成员来自 `0` 到 `n - 1`，每个成员最多出现一次。集合不关心顺序；序列保留顺序。`list(n)` 不自动要求包含所有成员，完整排列需要显式约束长度。

```python
from optagent import OptModel

model = OptModel()
team_a = model.set(6)
team_b = model.set(6)
model.constraint(model.partition(team_a, team_b))
model.constraint(team_a.count() >= 2)
model.minimize(team_a.count())
```

上述划分约束保证编号 `0` 到 `5` 恰好分给一组；第一组至少有 2 个成员，最小化人数会让它选取 2 个成员，其余 4 个归第二组。`partition()` 本身只生成布尔表达式，外层 `constraint()` 才把它加入模型。

三种关系都要求输入为同类、同全集的决策变量：`partition()` 要求每项恰好归属一组；`disjoint()` 要求最多归属一组，允许遗漏；`cover()` 要求至少归属一组，允许跨组重复。序列变量也能参与这些关系，但关系不限制组内顺序。

`union()` 和 `intersection()` 则生成并集与交集的集合值，可继续计数或判断成员。例如 `model.count(model.intersection(a, b)) == 0` 表达没有公共成员，还需传给 `constraint()` 才成为约束。

各接口的参数限制与可运行示例见 [`set`](../api/model-reference.md#optagent.OptModel.set)、[`list`](../api/model-reference.md#optagent.OptModel.list)、[`partition`](../api/model-reference.md#optagent.OptModel.partition)、[`disjoint`](../api/model-reference.md#optagent.OptModel.disjoint)、[`cover`](../api/model-reference.md#optagent.OptModel.cover)、[`union`](../api/model-reference.md#optagent.OptModel.union) 和 [`intersection`](../api/model-reference.md#optagent.OptModel.intersection)。

## 区间与可选任务

区间的边界是最早开始和最晚结束，持续时间需要通过 `length()` 或 `.length` 单独约束。必选区间允许零长度；可选区间可缺席。

```python
from optagent import OptModel

model = OptModel()
a = model.interval(0, 20)
b = model.interval(0, 20)
model.constraint(a.length == 3)
model.constraint(b.length == 5)
model.constraint(a.end <= b.start)
model.minimize(b.end)
```

用 `optional_interval()` 表达可不执行的任务，通过 `presence()` 约束出现条件。业务所需的时长、先后关系和资源约束仍需显式建模。

## 数组与 Lambda

`array()` 构造常量或表达式数组，`at()` 支持表达式索引；`range()` 与 `lambda_function()` 用于迭代和映射。Python 的列表是建模时的容器，模型的数组表达式参与求解时的计算。

```python
from optagent import OptModel

model = OptModel()
choice = model.int(0, 2)
costs = model.array([8, 3, 5])
model.minimize(costs[choice])
```

动态索引应有明确范围。需要默认值的数组访问可使用 `expression.at(index, default=value)`；具体形状与类型要求见 API 参考。

## 多目标与模型生命周期

多次调用 `minimize()` / `maximize()` 按声明顺序形成字典序目标。先比较第一个目标，相同后再比较后续目标；这不是加权求和。

完成全部建模后再求解。创建新表达式、变量或修改约束、目标会使模型上的旧值失效；需要重新求解后再读取 `.value`。在求解前保存好希望读取的派生表达式。

[查阅建模 API →](../api/modeling.md)
