跳转至
1.2.2

求解与配置

先阅读路径选择确认模型兼容性。一次性求解返回 Solution 并将本次解的值写入模型;业务代码应先检查 feasible。交互式入口返回会话,在 finish() 时写回最终解。

solve · 本地搜索

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,
    worker_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
worker_threads None 可选正整数,范围为 1 到 1024;默认采用机器报告的硬件并发数

需要重复得到相同结果时,固定模型、种子、线程配置、运行版本和评价预算,并为完成工作留出足够时间:

solution = model.solve(
    deterministic=True,
    evaluation_limit=10000,
    random_seed=1,
    worker_threads=4,
    time_limit_s=120,
)

solution.diagnostics["deterministic_completed"] 表示本次确定性工作正常完成。 若时间到期、取消、发生资源压力或执行失败,该值为 False,返回已有认证解,但不保证终态与其他运行相同。 相同秒数可能完成不同数量的工作,因此仅固定时间和种子不能保证完全相同的结果。

确定性模式暂不支持外部 Python 回调,也不运行依赖时间预算的 HiGHS 搜索路径; 模型包含外部回调时需显式传入 deterministic=False。它保留并行计算,但同步和搜索反馈顺序可能影响耗时与解质量。 默认启用确定性模式;model.solve(deterministic=False) 可切回吞吐模式。 该模式尚未通过性能与解质量无回退验收,是否适合业务模型应通过同时间预算的对照验证。

默认根据系统和容器可用内存调整搜索并发,在压力出现时回收缓存、降低并发,余量恢复后逐步增加并发。 例如 model.solve(memory_limit_bytes=2 * 1024**3) 将管理内存的目标限制在 2 GiB 以内;系统余量不足时实际目标可能更低。

该参数覆盖搜索工作区、候选存储和算法辅助空间,是协作式估算目标,不是整个进程的硬内存上限。 模型编译、Python、外部求解器和单次临时分配仍可能产生额外占用。资源不足时会保留已有的已验证结果, 通过 solution.diagnostics["termination_reason"] 报告 memory_limit,不表示模型无解。 solution.diagnostics["memory_policy"] 提供实际预算、资源来源、探测回退以及并发收缩和恢复次数。 系统资源无法探测时使用至多 256 MiB 的保护目标,并标记 probe_fallback。

solution.feasible=False 表示本次没有交付可行解。到达时间限制且没有可行解时, solution.status 为 deadline;其他终止情况保留其停止原因。 当前原生搜索路线不交付全局不可行证明,diagnostics 中的 globally_infeasible 为 False; 没有找到可行解时不会据此返回 infeasible。

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。修改集合需要整体赋值,例如:

order = list(outcome[route])
order.reverse()
outcome[route] = order

变量必须属于原模型且是决策变量。跨变量约束在完整评价时检查,因此可以先修改多个变量再评价。 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 除外。 模型声明在整个会话中冻结;外部函数对相同输入的含义也必须保持稳定。 当前仅原生搜索支持此会话接口,其他求解入口仍使用各自的一次性调用方式。

最终 result.diagnostics["interactive"] 包含暂停数、评价尝试/完成数、接纳数, 以及主动搜索、暂停排空、暂停等待、交互评价和 outcome 导出的纳秒计时。 暂停等待包含交互评价时间,两者不能重复相加。

solve_optx · HiGHS

from optagent import OptxConfig

solution = model.solve_optx(
    config=OptxConfig(time_limit=30.0, mip_rel_gap=0.01, threads=4),
    objective_threshold=None,
)

config=None 使用默认配置;包装层未配置时间限制时采用 30 秒。 未指定 threads 或传入 None 时,保留 HiGHS 的 threads=0 自动选择与线程池复用; 未指定 parallel 时保留原生 "choose"。包装层不再按模型规模、整数域或剩余时间推导线程数, 也不额外估算 CPU 配额。受限运行环境可显式设置 threads。 正整数线程数和原生选项始终优先,例如 OptxConfig(threads=4, parallel="on")。 4 和 8 都不是后端最低要求;threads=1 限制后端线程池为单线程。 固定版本中,MIP 树并行需要显式 parallel="on" 且线程数大于 1;默认 "choose" 不自动开启它。

MIP 树并行开启后,默认采用 mip_parallel_strategy="neighborhood",在有可行候选时分配一个 worker 搜索整数邻域。 需要原版树搜索策略时,可设置 OptxConfig(threads=4, parallel="on", mip_parallel_strategy="standard")。 策略效果与模型有关;邻域搜索可能改善候选发现,也可能增加成本。 neighborhood 的协作调度允许搜索轨迹变化,固定 seed 不保证节点和 LP 迭代数一致;standard 保留原版同步调度。 辅助累计预算 mip_neighborhood_budget 默认为 60 秒,时间片 mip_neighborhood_slice 默认为 10 秒,均采用协作式停止。 预算耗尽或没有有效邻域后,worker 返回树搜索;预算为 0 时只禁用辅助任务,完整回退应选择 standard。 这三个实际参数可在 solution.diagnostics["backend_attempts"] 中查询,LP 调用对应值为 None。

连续凸 QP 在 HiPO 可用时默认优先使用 solver="hipo",不按二次变量数量设分界。 HiPO 报错、返回 Unknown 或候选未通过原模型数值核验时,使用剩余总预算尝试一次 ASM, 保留两次尝试中已通过核验且原目标更好的候选。两次调用共享时限,切换不改变容差、线程或并行选项。 LP/MIP 保留原生算法;显式 solver 优先,显式选择的算法不会自动切换。 例如 OptxConfig(solver="qpasm") 固定使用 ASM,适合已确认受益的高频小 QP。 HiPO 默认编入;不可用时自动保留原生 QP 路线,显式请求不可用的 HiPO 会报错。 组合搜索内部 worker 继续遵守既有调度与线程配置。

backend_attempts 记录从实际 Highs 对象读回的顶层 solver、parallel、threads, 以及 algorithm_source 和 quadratic_variables;hipo_available 表示构建能力。 ASM 备选记录的 phase 为 "qp_asm_fallback",fallback_reason 为 "backend_error"、 "unknown" 或 "numerical_verification";time_limit_s 是该次后端调用的剩余时间额度。 verification.candidate_phase 表示最终交付候选来自哪一次尝试,不一定是最后一次调用。 threads=0 表示原生自动选项,不是观测到的活跃线程数,已有线程池可能继续复用。 这些字段也不代表 MIP 子求解器的实时配置或整个进程的线程硬上限。 mip_rel_gap 必须有限且非负;其他原生参数的有效性由求解路径与后端检查。

OptX 的模型转换资源配置与 HiGHS 参数分别传递,可通过以下参数控制:

参数 默认值 计量范围
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 每个二次目标的表达式展开、合并和凸性证明操作

这些参数必须是正整数;字节数上限为 2**63 - 1,其他计数上限为 2**31 - 1。字节预算不包含原始模型和后端搜索内存,也不是进程内存硬限制。 例如 OptxConfig(max_variables=500_000, max_compile_bytes=3 * 1024**3)。 超限时抛出 OptxUnsupportedError,问题详情包含转换阶段、实际规模、上限和来源。 二次操作预算与约束行数独立;多项式缓存、临时结果及凸性证明的 Schur 填充同样受非零项和估算字节预算限制。 超限不跳过凸性证明,也不放宽数值容差。 仿射和二次长链式加法可直接转换,无需通过增加 Python 递归上限来支持。 静态 lambda 调用、聚合、map 和固定数组下标行可与连续凸二次目标组合;二次目标仍只能排在最后优先级。 根合取及布尔条件选中的闭比较可直接转为约束行;连续比较作为一般条件或布尔值时仍受原有限制。 大数组的 Count、固定一维下标及适用的纯符号调用可按需读取;请求完整容器仍计入原集合槽位预算。 完整整数派生集合和 List 使用压缩表示,保留原顺序、唯一性和结果恢复语义。 整数常数除模可避免逐值建表;// 向负无穷取整,% 的余数跟随分子符号。 最小化 abs、max 和最大化 min 的适用单调目标可保留为连续模型, 也可与连续凸 QP 组合。表达式被一般约束、反向目标或除法等精确运算复用时,仍要求完整函数图和所需有限界。 整数时间轴上的适用区间加权和、根 All 资源比较按覆盖长度或起止事件转换, 支持缺席、零长度及不依赖时间的动态整数需求;一般时间相关函数仍受通用展开预算限制。 凸性核验无法完成时报告 quadratic_convexity_unverified,与已确认非凸的 nonconvex_quadratic_objective 区分;两者均不进入后端求解。

未知选项、后端不接受的值或超出允许范围的值会抛出 ValueError,包含选项名与传入值; 即使模型没有决策变量也会检查。主搜索保留 HiGHS 原生数值默认值: primal_feasibility_tolerance=1e-7、dual_feasibility_tolerance=1e-7、 mip_feasibility_tolerance=1e-6、small_matrix_value=1e-9。 显式配置的有效值会传给后端并从后端读回记录。 1e-11 低于后端允许下限,不能用来进一步收紧 primal 和 MIP 可行性容差。

可以显式配置 MIP 容差,并按需查询本次运行实际记录的有效值:

solution = model.solve_optx(
    config=OptxConfig(mip_feasibility_tolerance=1e-7),
)
verification = solution.diagnostics.get("verification", {})
if solution.feasible and verification.get("performed"):
    print(verification["tolerance"], verification["max_row_violation"])

primal_feasibility_tolerance=1e-5 不会把 MIP 原模型验解容差改成 1e-5。 mip_strict_numerics=True 收紧内部 LP 的数值策略,也不会自动将 MIP 候选验解容差改成 1e-10。 无候选或未完成验解时,verification.tolerance 的占位值不能作为有效验收容差。 不同输入格式、显式配置、重试阶段和平台的验证报告,应分别列明这些条件。

OptX 使用固定提交的个人 HiGHS fork,MIP 默认启用 mip_strict_numerics; 可显式设为 False 使用后端兼容策略。HiGHS 的顶层 LP 容差不直接控制 MIP 的 LP 松弛: 兼容模式的松弛 primal 容差取 MIP 容差, dual 容差取 max(1e-10, MIP 容差 * 0.1);严格模式的内部 primal 容差不大于 1e-10, dual 容差为 1e-10。候选的 MIP 可行性容差仍默认 1e-6。 显式顶层容差与内部策略不同时,或显式开启严格模式时,求解前发出 RuntimeWarning。

OptxConfig(numerical_recheck=False) 默认禁止因不可行报告或验解失败而提高精度重跑主搜索。 需要时可显式设为 True;启动前会告知采用的严格 MIP 容差,重试共享剩余总预算。 原模型的约束和变量域始终验解,不能通过验证的候选不会作为可行解交付。 受限修复后的最优性认证可能使用更严格的 LP 精度,启动前告知并单独记录 certification_started、certification_time_s。严格 MIP 路径的后端不可行结论保留为 infeasible; 显式选择兼容策略且未严格复核时,其不可行报告返回 unknown,原始状态仍可查询。 该选项不控制自动 QP 的 HiPO→ASM 切换;后者保持原精度,也不重新分配总时限。

不支持的模型抛出 OptxUnsupportedError,可读取 .issues 中的约束 / 目标名称、表达式路径和限制说明。该入口不回退到本地搜索。

返回值必须通过原模型验解。后端结果只有很小的数值误差时,求解器可固定整数并受限地调整连续变量, 重新检查全部约束和变量边界,并在同一修复范围内按原目标精修。目标值按最终赋值计算。 对有限域标量、单个仿射目标模型,OptX 使用覆盖原表达式舍入误差的全域放松重新求界; 最终可行解与有效全局界的差距达到声明精度时返回 optimal,否则返回 feasible。 精度由 OptxConfig(optimality_abs_tol=1e-8, optimality_rel_tol=1e-10) 配置, 允许间隙为两者中较大者,其中相对精度乘以 max(1, abs(目标值), abs(全局界))。 这两项不放宽约束或变量域。修复后的展开、二次和多目标模型当前保留 feasible。 solution.diagnostics 中的 numerical_repair、repaired_decisions 和 maximum_repair 分别说明是否修复、修复的决策数量和最大改动。

solution.status 描述最终交付结果;solution.diagnostics["backend_status"] 单独保存最后一次 HiGHS 运行的原始状态文本,例如 "Optimal"、"Infeasible"。 optimality_certified 说明修复后是否通过再次认证,optimality_bound、optimality_gap、 optimality_tolerance 给出界、实际间隙和允许间隙;optimality_method、optimality_reason 说明认证方法或未认证原因。未修复但仅容差可行的候选也会保留 feasible, 不会因后端返回 Optimal 就变为 optimal;最终结论和后端信息的读取方式见结果与诊断。 backend_objectives 保存修复前的线性化目标值,便于与最终原图目标比较。

solution.best_bound、solution.gap、solution.solve_time 提供后端报告的单目标界限、 相对间隙比值和搜索运行秒数,对应诊断的 backend_best_bound、backend_gap、 backend_solve_time_s。它们未经独立认证,不替代 optimality_bound 或 optimality_gap。 后端间隙以修正前的后端候选目标计算,可能与最终交付赋值不同;不可用时返回 None。 多目标模型没有单一后端界限或间隙,只按阶段提供运行记录。

backend_attempts 按运行顺序记录原始 status、status_code、 primal_feasibility_tolerance、dual_feasibility_tolerance、mip_feasibility_tolerance、 small_matrix_value,以及 requested_numerics、phase、numerical_warnings 和 infeasibility_recheck、verification_recheck。顶层 backend_status_code 对应最后一次运行, infeasibility_rechecked、verification_rechecked 分别表示是否因不可行报告、 原模型验解失败而执行过严格容差复核。 每次运行还记录 objective_index、objective_value、best_bound、gap 和 solve_time_s。 目标值和界限已恢复为原目标的最小化或最大化方向;缺失或非有限值返回 None。 没有实际进入 HiGHS 时,原始状态和状态码为 None,运行记录为空。

运行记录还包含 mip_strict_numerics 与 mip_proof_feasibility_tolerance,后者描述 预处理和 LP 原始可行性计算的策略精度;mip_lp_dual_tolerance 记录对应 dual 策略。 这些 MIP 内部值根据固定后端策略推导,mip_precision_source="pinned_backend_policy"、 mip_subsolver_options_observed=False 明确表示未直接观测运行中的内部 LP 对象。 顶层数值选项则由实际 Highs 对象读回。 backend_repository、backend_revision、backend_version、backend_githash 记录依赖来源及实际内核身份,避免只凭版本字符串判断是否包含修复。

原模型验证仍失败时抛出 RuntimeError,可读取异常的 .diagnostics。 其中 verification_failures 至多包含 64 个失败项,提供 kind、expression_id、name、 lhs、rhs 和 residual;compiled_constraint_index 是编译后的约束序号。 用户原始模型的约束宜通过名称和表达式 ID 定位。

整数取整可能使关联连续变量违反原约束。独立 OptX 可固定取整后的整数,在受限邻域内联合 修正连续变量,然后重新检查全部原约束、布尔条件和变量域;不提高交付容差,也不改变主搜索 选项。修正目标留出数值余量,修正阶段共享剩余预算,最多使用两秒后端运行时间。 verification 中的 completion_attempted、completion_succeeded、completion_status、 completion_time_s 记录这一步。修正不能通过全量验解时仍拒收候选。

solve_cpsat · OR-Tools CP-SAT

from optagent import CpSatConfig

solution = model.solve_cpsat(
    config=CpSatConfig(num_search_workers=4, random_seed=1),
    time_limit_s=30.0,
)
CpSatConfig 参数 说明
max_time_in_seconds 未显式传入 time_limit_s 时的总预算来源
num_search_workers CP-SAT 工作线程设置
random_seed 后端随机种子
relative_gap_limit / absolute_gap_limit 相对 / 绝对间隙限制
log_search_progress / log_to_stdout 后端日志设置
其他关键字参数 传递给 CP-SAT 原生参数

配置中值为 None 的选项不传递。显式 time_limit_s 优先,未设置时依次使用配置中的时间限制和 30 秒默认值。

solve_mathopt · OR-Tools MathOpt

from optagent import MathOptConfig

solution = model.solve_mathopt(
    config=MathOptConfig(solver_type="GSCIP", threads=4),
    time_limit_s=30.0,
)
MathOptConfig 参数 说明
solver_type 默认 "GSCIP",所选后端须可用且支持模型
time_limit 秒数或 datetime.timedelta;显式总预算未设置时采用
threads 后端线程设置
relative_gap_tolerance / absolute_gap_tolerance 相对 / 绝对间隙容差
其他关键字参数 传递给 MathOpt 原生求解参数

CP-SAT 和 MathOpt 的顶层入口不接受 objective_threshold。预算覆盖整个转换、求解与验证流程;验证前超时返回 UNKNOWN,没有可读变量值。

检查配置与结果

CpSatConfig.to_parameters()、MathOptConfig.to_parameters() 和 OptxConfig.to_options() 返回已设置选项的字典。MathOpt 的后端选择单独保存在 solver_type 中,不在 to_parameters() 字典内。

结果字段与状态处理见结果与诊断。