求解与配置¶
先阅读路径选择确认模型兼容性。一次性求解返回 Solution 并将本次解的值写入模型;业务代码应先检查 feasible。交互式入口返回会话,在 finish() 时写回最终解。
solve¶
自动协调适用的启发式与精确求解能力,通常从此入口开始。模块函数 solve(model, ...) 使用相同参数;以下参数均按名称传入。
solution = model.solve(
time_limit_s=30.0,
objective_threshold=None,
log_level="on",
external_evaluation_limit=None,
memory_limit_bytes=None,
deterministic=True,
evaluation_limit=None,
random_seed=1,
threads=None,
)
| 参数 | 默认值 | 约束 / 含义 |
|---|---|---|
time_limit_s |
30.0 |
正数且有限;秒,包含序列化和编译 |
objective_threshold |
None |
目标索引到有限数值的映射;索引从零开始 |
log_level |
"on" |
"off"、"on"、"debug" |
external_evaluation_limit |
None |
可选正整数,限制实际启动的外部回调次数(失败也计入),已知结果和复用不额外计费 |
memory_limit_bytes |
None |
默认自动管理内存;正整数可设置受管内存的目标上限,单位字节,最大为 sys.maxsize |
deterministic |
True |
按固定逻辑顺序推进并行搜索,内部修复使用工作限额;设为 False 使用吞吐模式 |
evaluation_limit |
None |
可选正整数,限制搜索评价和内部试算;不包含初始化评价 |
random_seed |
1 |
随机种子,整数,范围为 0 到 2**64 - 1 |
threads |
None |
可选正整数,范围为 1 到 1024;默认采用机器报告的硬件并发数 |
需要重复得到相同结果时,固定模型、种子、线程配置、运行版本和评价预算,并为完成工作留出足够时间:
solution = model.solve(
deterministic=True,
evaluation_limit=10000,
random_seed=1,
threads=4,
time_limit_s=120,
)
solution.diagnostics["deterministic_completed"] 表示本次确定性工作正常完成。
若时间到期、取消、发生资源压力或执行失败,该值为 False,可能返回已验证的候选,但不保证终态与其他运行相同。是否有可行解仍以 feasible 为准。
相同秒数可能完成不同数量的工作,因此仅固定时间和种子不能保证完全相同的结果。
默认启用确定性模式。包含外部 Python 回调时,需显式传入 deterministic=False;
其他模型也可以用该设置切换到吞吐模式。两种模式的耗时和解质量可能不同,可用业务模型在相同预算下比较。
默认根据系统和容器可用内存调整搜索资源。
例如 model.solve(memory_limit_bytes=2 * 1024**3) 将受管内存的目标限制在 2 GiB 以内;系统余量不足时实际目标可能更低。
该参数覆盖搜索工作区、候选存储和算法辅助空间,是协作式估算目标,不是整个进程的硬内存上限。
模型转换、Python、求解后端和单次临时分配仍可能产生额外占用。资源不足时会保留已有的已验证结果,
通过 solution.diagnostics["termination_reason"] 报告 memory_limit,不表示模型无解。
可通过 solution.diagnostics.get("memory_policy") 查看本次实际使用的内存策略。
solution.feasible=False 表示本次没有交付可行解。到达时间限制且没有可行解时,
solution.status 为 deadline;其他终止情况保留其停止原因。
只有取得全局不可行证明时才返回 infeasible,并在 diagnostics 中标记 globally_infeasible=True。
interactive_solve · 暂停、改解与续跑¶
交互式求解沿用支持暂停、改解和续跑的异步吞吐路径。
from optagent import OptModel, interactive_solve
model = OptModel()
x = model.int(0, 100, default=80)
model.minimize(x * x)
with interactive_solve(model, wall_time_limit_s=60, log_level="off") as session:
outcome = session.run_for(0.1)
if not outcome.finished:
outcome[x] = max(0, outcome[x] - 1)
evaluated = session.evaluate(outcome)
if evaluated.feasible and evaluated.improves_incumbent:
receipt = session.submit(outcome)
print(receipt.status)
outcome = session.run_for(0.1)
result = session.finish()
使用建模时声明的变量定位值:outcome[x] 读取,outcome[x] = value 修改。
已有业务索引可以直接使用,例如 outcome[start_times[job]] = 20。
修改立即可读;x.value 在会话结束前仍表示上一次终态解。
入口参数按名称传入:
| 参数 | 默认值 | 含义 |
|---|---|---|
wall_time_limit_s |
None |
可选正数,单位秒;总墙钟预算,包含序列化、初始化、搜索、暂停和评价;默认不限总时间 |
objective_threshold |
None |
与 solve 相同;提交达到阈值后也会终结搜索 |
log_level |
"on" |
"off"、"on"、"debug" |
external_evaluation_limit |
None |
搜索和交互评价共用的外部函数调用额度 |
memory_limit_bytes |
None |
与 solve 相同的受管内存预算,包含交互评价;Python 导出的值不计入该预算 |
会话操作¶
| 操作 | 返回及约束 |
|---|---|
session.run_for(seconds) |
返回 SolveOutcome;从可搜索状态开始计时,到期请求安全暂停,保留搜索资源 |
session.evaluate(outcome, timeout_s=None) |
返回 EvaluationReport;对当前暂停轮次的完整候选原生验解,不替换当前最好候选 |
session.submit(outcome) |
返回 SubmissionReceipt;只能提交最后一次修改后已成功验解的当前候选 |
session.cancel() |
非阻塞请求终结,可在另一线程或外部函数中调用;之后用 finish/close 等待清理 |
session.finish() |
终结并返回最后一个认证的 Solution;重复调用返回同一个结果 |
session.close() |
幂等关闭;with 退出时自动调用 |
暂停和取消均为协作式操作;在途任务、外部函数及结果排空可能延长返回时间。
timeout_s 只限制本次评价;到期的评价不提交,若会话总预算仍有效,可继续修改和评价。
已经执行的 Python 外部函数必须自行返回,无法被硬中断。
outcome 的读写与认证¶
SolveOutcome.finished 表示返回时搜索已终结,与可行性分开。
feasible、objectives 是当前版本的认证结果;修改后均变为 None,成功评价后恢复。
revision 记录成功修改次数,incumbent_version 记录创建 outcome 时的全局版本。
非法赋值不改变原值、版本或证书;无认证赋值的终结结果读取决策时抛出 RuntimeError。
标量遵守声明的类型和范围。list 读取返回 tuple,set 返回 frozenset;区间读取为不可变映射,
缺席的可选区间为 None。修改集合需要整体赋值,例如:
变量必须属于原模型且是决策变量。跨变量约束在完整评价时检查,因此可以先修改多个变量再评价。
EvaluationReport 提供 feasible、objectives、improves_incumbent、revision,以及
constraint_violations、hard_structure_violations、undefined_constraints、
undefined_objectives 四项计数。
SubmissionReceipt.accepted 表示实际接纳,status 为 accepted、infeasible 或
not_improving,incumbent_version 是提交后的全局版本。相等目标默认不替换。
未评价、过期或已经终结的提交抛出 RuntimeError,其他会话的 outcome 抛出 ValueError。
每次赋值会使旧证书失效;修改 Python 中的评价报告不会改变原生认证结果。
续跑不会自动提交修改。旧 outcome 保留原值供读取,但不能在之后的暂停轮次提交。
评价和提交期间修改该 outcome 会立即失败;同时运行第二个控制操作也会失败,cancel 除外。
模型声明在整个会话中冻结;外部函数对相同输入的含义也必须保持稳定。
此会话接口使用异步吞吐搜索。solve_heuristic() 和 solve_optx() 仍使用一次性调用方式;
session.finish() 的 solver_name 当前为 search。
最终 result.diagnostics["interactive"] 包含暂停数、评价尝试/完成数、接纳数,
以及主动搜索、暂停排空、暂停等待、交互评价和 outcome 导出的纳秒计时。
暂停等待包含交互评价时间,两者不能重复相加。
solve_heuristic¶
from optagent import GaOptions
solution = model.solve_heuristic(
time_limit_s=30.0,
threads=4,
ga=GaOptions(population_size=64, search_definition="automatic"),
objective_threshold={0: 100},
)
通用运行和停止参数直接按名称传入;GA 专用参数可通过 ga=GaOptions(...) 单独配置。模块函数 solve_heuristic(model, ...) 使用相同参数。返回 Solution,
solver_name 为 "heuristic",原决策与已计算表达式的值写回模型。该入口只运行 GA,
不自动切换其他求解引擎,也不要求提供初始可行解。
search_definition="automatic" 在 GA 内部选择适用的搜索方案;可显式指定
decision、cvrp_tour、schedule_priority 或 machine_dispatch。
显式方案不适用时抛出 HeuristicUnsupportedError,其 search_definition 和 diagnostics
保留请求方案与准备原因。耗时、内存或准备额度耗尽单独报告,不作为数学不支持或不可行证明。
基础运行参数¶
以下参数直接传给 solve_heuristic()。不接受 config 包装;可选的 ga 仅配置遗传算法。
| 参数 | 默认值 | 含义与范围 |
|---|---|---|
time_limit_s |
30.0 |
正数且有限;总协作式预算,单位秒 |
threads |
None |
自动采用机器硬件并发数;可指定 1~1024 |
random_seed |
1 |
0~2**64 - 1 |
deterministic |
True |
固定逻辑顺序;False 使用吞吐执行 |
evaluation_limit |
None |
可选正整数;包括 GA 自行生成初值及子代内部试算;外部函数所需的共享初始化不计入此项 |
memory_limit_bytes |
None |
可选正整数,最大 sys.maxsize;协作式受管内存目标,不是进程 RSS 硬限制 |
external_evaluation_limit |
None |
可选正整数;限制实际启动的外部评价次数 |
log_level |
"on" |
"off"、"on" 或 "debug" |
ga |
None |
可选 GaOptions;省略时使用默认遗传参数 |
GaOptions¶
GA 的搜索表示、种群及遗传操作通过 ga=GaOptions(...) 设置。该对象不可变;to_options() 返回独立字典。
| 参数 | 默认值 | 含义与范围 |
|---|---|---|
search_definition |
"automatic" |
上述五种 GA 搜索方案选择 |
population_size |
32 |
每个搜索方案的目标种群大小,2~65536 |
minimum_decision_distance |
1 |
正整数;初始种群的最小决策距离 |
mutation_enabled |
True |
是否安排独立变异任务 |
mutations_per_parent |
1 |
每个父代的独立变异任务数,0~1024;启用时与种群大小之积不超过 65536 |
crossover_enabled |
True |
是否安排交叉任务 |
crossovers_per_round |
None |
默认当轮实际父代数的一半;可指定 0~65536,0 关闭交叉任务 |
crossover_mutation_rate |
None |
交叉子代再变异的概率,0~1;未配置时为 0,不控制独立变异任务 |
restart_after |
64 |
正整数;停滞与重启阈值,不是总迭代上限 |
preparation_work_limit |
None |
可选非负整数;额外限制准备工作,仍受总预算约束 |
generation_evaluation_limit |
None |
单个子代任务的内部试算上限,0~65536;默认 16,不含最终评价确认,耗尽后放弃该任务 |
max_in_flight |
None |
可选正整数;同时进行的任务数上限,默认自动确定 |
max_resident_populations |
4 |
正整数;同时保留的种群数上限 |
max_pending_preparations |
16 |
正整数;等待准备的搜索方案数上限 |
diversity_archive_size |
8 |
非负整数;多样性档案容量 |
总时间包含模型准备、搜索、结果校验和返回。正在执行的操作和清理可能使调用稍晚返回。
结果校验未完成时,不提供可读取的解;读取变量值前仍须检查 solution.feasible。
确定性复现还要求相同模型、运行版本、种子、线程配置和逻辑评价预算,且未受时间或资源压力中断。
外部 Python 回调要求 deterministic=False,其调用次数统计规则与 solve() 相同。
整数目标阈值保留 int64 精度。达到阈值或搜索停滞不意味着已证明最优;
feasible=False 只表示本次没有取得可用的可行解,不能据此判断模型无解。
solve_optx¶
from optagent import HighsConfig
solution = model.solve_optx(
config=HighsConfig(time_limit_s=30.0, relative_gap_limit=0.01, threads=4),
objective_threshold=None,
)
config=None 使用 HighsConfig()。传入 HighsConfig 选择 HiGHS,传入 CpSatConfig 选择原生 CP-SAT。
配置类型就是后端声明,不需要 backend 参数或其他包装对象。
其他类型、字典或多个配置组成的容器在 Python 端立即触发 TypeError。
两个具体配置都直接接收以下运行字段:
| 参数 | 默认值 | 含义 |
|---|---|---|
time_limit_s |
30.0 |
正数且有限;覆盖序列化、准备、搜索、验解和交付的协作式总预算 |
threads |
None |
原生自动选择,或指定 1~1024 的总物理线程额度 |
random_seed |
1 |
整数,范围为 0 到 2**31 - 1 |
log_level |
"off" |
off、on 或 debug |
relative_gap_limit / absolute_gap_limit |
0.0 |
非负有限数;原生停止公式依后端解释,不等于严格最优证明 |
返回结果的 solver_name 为 optx,diagnostics["backend"] 记录实际后端 highs 或 cp_sat。
所选后端不支持模型时,统一抛出 OptxUnsupportedError,.issues 保留原表达式位置、实际后端和原因,不自动切换。
HighsConfig¶
使用 HiGHS 求解线性、混合整数线性或受支持的连续凸二次模型。模型条件见求解指南。
常用调优参数可直接作为 HighsConfig 的命名参数传入。例如,使用四个线程并开启 MIP 并行搜索:
from optagent import HighsConfig
solution = model.solve_optx(
config=HighsConfig(time_limit_s=30.0, threads=4, parallel="on"),
)
省略 threads 时由后端自动选择。parallel="choose" 是原生默认值,不自动开启 MIP 树并行;
需要该能力时显式传入 parallel="on",并提供大于 1 的可用线程数。并行效果取决于模型和机器。
数值与结果校验¶
| 参数 | 默认值 | 含义 |
|---|---|---|
numerical_recheck |
False |
是否允许在剩余预算内,以更严格精度重试不可行报告或未通过校验的候选 |
optimality_abs_tol |
1e-8 |
非负有限数;原模型最优性确认的绝对允许间隙 |
optimality_rel_tol |
1e-10 |
非负有限数;原模型最优性确认的相对允许间隙 |
可用原生选项调整数值容差,例如 HighsConfig(mip_feasibility_tolerance=1e-7)。
默认 primal、dual 和 MIP 可行性容差分别为 1e-7、1e-7 和 1e-6;
LP 容差不直接决定 MIP 候选的验解容差。mip_strict_numerics 默认开启,控制 MIP 内部数值策略;
改变此策略也不会自动改变交付可行解的容差。设置影响数值策略时,求解器可能发出 RuntimeWarning。
交付候选始终经过原模型约束和变量范围校验。小幅数值修正后,目标值按最终赋值重新计算。
支持原模型最优性确认的情形中,允许间隙为绝对精度与
optimality_rel_tol * max(1, abs(目标值), abs(全局界)) 中的较大者;这两项不放宽可行性要求。
无法确认最优但已有可行解时返回 feasible。未经确认的后端不可行报告也不会直接作为原模型无解的结论。
连续凸二次目标默认自动选择算法,必要时在剩余预算内尝试备选算法。
这类切换保持原精度,不受 numerical_recheck 控制。显式指定 solver 时遵循该选择。
模型转换资源¶
| 参数 | 默认值 | 含义 |
|---|---|---|
max_variables |
1,000,000 | 转换后的标量变量数,包含辅助变量 |
max_constraints |
2,000,000 | 转换生成的约束行数 |
max_nonzeros |
20,000,000 | 稀疏系数数量,包含转换工作区 |
max_compile_bytes |
2,147,483,648 | 模型转换工作区的估算字节数 |
max_collection_slots |
4,096 | 有限集合展开槽位数 |
max_quadratic_work |
50,000,000 | 每个二次目标的展开和凸性检查工作量 |
以上均为正整数;max_compile_bytes 最大为 sys.maxsize,其他计数最大为 2**31 - 1。
例如 HighsConfig(max_variables=500000, max_compile_bytes=3 * 1024**3)。
转换内存预算不包含后端搜索内存,也不是进程内存的硬限制。
超出转换能力或上限时抛出 OptxUnsupportedError,.issues 提供原因和位置。
原生参数与诊断¶
presolve="on"、parallel="on" 等 HiGHS 选项直接传入配置对象。
时间、线程、随机种子、日志和停止间隙使用上方统一字段,例如
relative_gap_limit=0.01,不能再用 mip_rel_gap 覆盖。
未知原生选项或无效值会在求解时抛出 ValueError。
diagnostics["backend_attempts"] 记录各次后端运行的状态、目标、界限、间隙、耗时和生效参数。
backend_status 表示最后一次后端运行的原始状态;optimality_certified 表示是否通过原模型最优性确认。
这些诊断可能随执行阶段而缺失,使用 .get() 按需读取。
原模型校验失败且不能交付候选时会抛出 RuntimeError,可从异常的 .diagnostics 定位原因。
结果字段见结果与诊断。
CpSatConfig¶
from optagent import CpSatConfig
solution = model.solve_optx(config=CpSatConfig(time_limit_s=30.0, threads=4))
使用内置 OR-Tools CP-SAT 求解整数兼容模型,无须安装 Python ortools。
继续使用 OptModel 建模,通过 CpSatConfig() 设置上方通用运行参数及以下资源选项。
模型不受支持时抛出 OptxUnsupportedError,可读取 .issues 查看原因和对应位置;不会自动切换到其他入口。
因时间或资源限制停止时,是否取得可行解以 solution.feasible 为准。
CpSatConfig 参数 |
默认值与说明 |
|---|---|
max_variables / max_constraints |
None,按编译内存额度估算变量与约束上限 |
max_nonzeros |
None,按编译内存额度估算标量项上限 |
max_compile_bytes |
None,按可用内存选择模型转换的估算内存预算;不包含后端搜索占用 |
max_collection_slots |
None,按编译内存额度估算通用有限容器展开上限 |
max_native_bytes |
None,按可用内存选择搜索软预算,并为系统保留余量 |
| 开放的 CP-SAT 原生选项 | 直接作为命名参数传入,例如 cp_model_presolve=False;求解时检查名称和取值 |
六项资源参数均可传入正整数,固定对应上限;未指定的参数继续自动选择。
max_variables、max_constraints、max_collection_slots 最大为 2**31 - 1,其余最大为 2**63 - 1。
solution.diagnostics.get("cp_sat", {}) 中的 limit_compile_bytes、
limit_native_bytes、limit_collection_slots 和 limit_threads 可用于核对实际设置。
例如 CpSatConfig(max_collection_slots=4096, max_native_bytes=512 * 1024**2)
保留这两项固定上限,其余参数自动选择。
max_native_bytes 是搜索期间的软内存预算,不是整个进程的硬内存上限。
同一进程中的其他内存占用也可能影响停止时机。资源不足时可能提前结束;已通过校验的可行解仍可保留。
原生参数仅开放部分调优项,例如 cp_model_presolve、linearization_level 和 stop_after_first_solution。
时间、线程和日志仍须使用统一字段;不接受 max_time_in_seconds、num_search_workers 或 log_search_progress 覆盖,也不支持枚举全部解。
objective_threshold 与其他入口一样使用从零开始的目标索引,整数阈值限于 [-2^53, 2^53]。
达到阈值返回可行候选,不升级为最优。多目标逐级求解,前级确认最优后才继续;后级中止保留已验证候选。
CP-SAT 不隐式离散化连续变量。整数转换当前仍受精确数值范围与有限展开约束。
solver_name 为 "optx",diagnostics["backend"] 为 "cp_sat"。diagnostics 可查询终止原因与各阶段耗时;时间到期或取消后,结果清理可能使调用稍晚返回。
检查配置与结果¶
HighsConfig 与 CpSatConfig 的 to_options() 返回独立字典;原生选项在配置中不可变,修改导出的嵌套字典或列表不回写配置。
结果字段与状态处理见结果与诊断。