解决方案文件格式#

SOL 格式#

Gurobi解决方案(SOL)文件用于输出解决方案向量。每当有解决方案可用时,可以写入(例如使用GRBwrite)。

文件由变量-值对组成,每对占一行。文件中为模型中的每个变量包含一行。以下是一个简单的示例:

# Solution file
x  1.0
y  0.5
z  0.2

JSON 解决方案格式#

JSON(或JavaScript对象表示法)是一种轻量级的、基于文本的、独立于语言的数据交换格式。它源自JavaScript,但许多现代编程语言都包含生成和解析JSON格式数据的代码。

Gurobi JSON 解决方案格式旨在成为一种简单且标准的方式来捕获和共享优化结果。它符合RFC-8259标准。JSON 解决方案可以写入文件或捕获在字符串中。

JSON解决方案捕获了与模型解决方案相关的各种Gurobi属性的值。有些与整个模型相关,有些与单个变量相关,有些与单个约束相关。JSON解决方案字符串的确切内容将取决于几个因素:

  • 正在求解的模型类型(线性、二次、混合整数、多目标等)。某些求解信息对于特定问题类型不可用(例如,MIP模型的对偶变量值)。

  • 模型中标记元素的集合。默认情况下,JSON 解决方案将仅包含模型属性和变量数据。用户可以标记变量(使用 VTag 属性)、线性约束(使用 CTag 属性)和二次约束(使用 QCTag 属性)以在更具选择性的基础上请求数据。如果使用了任何此类属性,则只有标记的元素才会在 JSON 解决方案中包含解决方案信息。

  • JSONSolDetail 参数,控制 JSON 解决方案中包含的详细信息量。

  • 参数设置如InfUnbdInfoQCPDual,这些设置会导致优化过程生成更多的解决方案信息。

JSON解决方案通常不是直接供人类解释的。相反,您通常将它们输入到JSON解析器中,该解析器提供了从字符串中提取所需信息的工具。JSON是一种广泛使用的格式,几乎所有现代编程语言都有可用的库来帮助解析JSON字符串和文件。如果您决心直接检查字符串,JSON解析器通常还包括美化打印实用程序,使这样做更容易。

基本结构#

一个JSON解决方案字符串由一组命名的组件组成。在最简单的形式中,它可能看起来像下面这样:

{ "SolutionInfo": { "Status": 3,
                    "Runtime": 3.4289908409118652e-01,
                    "BoundVio": 0,
                    "ConstrVio": 0,
                    "IterCount": 0,
                    "BarIterCount": 0}}

JSON解析器使得从该字符串中提取各种组件变得相对容易。例如,在Python中,您可以通过访问result['SolutionInfo']['Status']来检索优化状态,解析后。

在讨论此格式中可用的具体信息之前,让我们先谈谈数据的表示方式。每个数据项的类型取决于属性类型。例如,状态 是一个整数属性,因此相应的值存储为整数。运行时间 是一个双精度属性,它表示为字符串,并且该字符串始终捕获属性的精确双精度(IEEE754)值。

命名组件#

一个JSON解决方案将始终包含至少一个命名对象: SolutionInfo。它可能包含最多三个可选的命名数组: Vars, Constrs, QConstrs。一个JSON解决方案字符串可能如下所示:

{ "SolutionInfo": {...},
  "Vars": [...],
  "Constrs": [...],
  "QConstrs": [...]}

三个可选部分的确切内容将取决于哪些模型组件被标记以及哪些解决方案信息可用。例如,如果没有元素被标记,那么Vars数组将存在,并包含所有具有非零解决方案值的变量的名称和解决方案值。对于MIP模型,Constrs数组将不存在,因为MIP解决方案不包含任何约束信息。

解决方案信息对象#

SolutionInfo 对象包含有关为此模型计算的解决方案的高级信息。某些条目将始终存在,而其他条目则取决于问题类型或优化的结果。此组件可能包括以下模型属性:

状态 (always present)

优化状态(最优、不可行、达到时间限制等)。

运行时间 (always present)

优化的运行时间(以秒为单位)。

ObjVal

解决方案的目标值。

ObjBound

目标值的最佳已知界限。

ObjBoundC

目标值的最佳已知界限(在使用完整性信息加强界限之前)。

MIPGap

最优性差距。

IntVio

最大完整性违规。

BoundVio

最大边界违规。

约束违反

最大约束违反。

ObjNVal (multi-objective only)

目标值的数组,每个目标对应一个值。

ScenNObjVal (multi-scenario only)

目标值的数组,每个场景一个。

ScenNObjBound (multi-scenario only)

一个目标界限的数组,每个场景一个。

IterCount

单纯形迭代次数。

BarIterCount

障碍迭代次数。

NodeCount

为MIP模型探索的分支切割节点数量。

FarkasProof

不可行模型的部分不可行性证明。请注意,在优化调用之前,您必须设置InfUnbdInfo参数,以便此信息可用。

SolCount

存储解的数量(仅适用于MIP模型)。

PoolObjBound

未发现的MIP解决方案的目标界限。

PoolObjVal

仅适用于至少有一个解的MIP模型。对于单目标模型,这是一个包含每个存储解的目标值的数组(从当前解开始)。对于多目标模型,这是一个包含SolCount个值数组的数组,每个数组包含特定解的每个多目标的目标值。

以下是一个MIP模型的SolutionInfo对象的示例:

{ "SolutionInfo": { "Status": 2,
                    "Runtime": 5.8451418876647949e+00,
                    "ObjVal": 3089,
                    "ObjBound": 3089,
                    "ObjBoundC": 3089,
                    "MIPGap": 0,
                    "IntVio": 0,
                    "BoundVio": 0,
                    "ConstrVio": 0,
                    "IterCount": 32,
                    "BarIterCount": 0,
                    "NodeCount": 1,
                    "SolCount": 1,
                    "PoolObjBound": 3089,
                    "PoolObjVal": [ 3089]}}

变量数组#

Vars 组件是一个对象数组(可能为空),包含有关变量的信息。如果完全没有设置显式标签(VTag、CTag 或 QCTag),则将包括所有具有非零目标值的变量及其名称。否则,仅包括设置了 VTag 的变量,并且此标签将成为对象的一部分。某些数据将始终存在,而其他数据将取决于问题类型或优化的结果。此组件可能包括以下变量属性:

VarName

模型中变量的名称。仅在未设置任何标签时显示。

VTag

包含变量标签的数组。请注意,这是以数组形式存储的,但目前该数组只会包含一个字符串。

X (always present)

对应于当前解决方案中VarName或VTag的变量的值。请注意,除非JSONSolDetail大于零,否则变量值为零的对象将从Vars数组中省略。

Xn

所有存储解决方案的值,包括当前解决方案(仅适用于MIP)。

ScenNX

对于多种场景,所有场景解决方案的值。

RC

对于具有对偶信息的连续模型,变量的减少成本。

VBasis

对于解为基本的连续模型,变量的基础状态。

UnbdRay

对于启用了InfUnbdInfo的无界模型,与变量相关的无界射线分量。

以下属性仅在JSONSolDetail大于0时包含:RC, UnbdRay, VBasis, Xn.

这些对象可能看起来像:

{ "VTag": ["VTag7"], "X": 1}
{ "VTag": ["VTag12"], "X": 3.6444895037909271e-02, "RC": 0}
{ "VTag": ["VTag2747"],
  "X": 0,
  "Xn": [ 0, 1, 1, 1, 0, 1, 1, 0, 0, 0]}

约束数组#

Constrs 组件是一个对象数组(可能为空),包含有关标记线性约束的信息。某些条目将始终存在,而其他条目则取决于问题类型或优化的结果。此组件可能包括以下约束属性:

CTag (always present)

包含线性约束标签的数组。请注意,这是以数组形式存储的,但该数组目前只会包含一个字符串。

Slack (always present)

当前解中松弛变量的值。

Pi

对于具有对偶信息的连续模型,对应约束的对偶值。

FarkasDual

对于启用了InfUnbdInfo的不可行模型,与约束相关的Farkas对偶分量。对于MIP模型,此分量将始终为空。

以下属性仅在JSONSolDetail大于0时包含:CBasisFarkasDualPiSlack

这些对象可能看起来像:

{ "CTag": ["CTag72"],
  "Slack": -1.3877787807814457e-17,
  "Pi": -5.6530866311690423e-02}

QConstrs 数组#

QConstrs 组件是一个对象数组(可能为空),包含有关标记的二次约束的信息。某些条目将始终存在,而其他条目则取决于问题类型或优化的结果。此组件可能包括以下二次约束属性:

QCTag (always present)

包含二次约束标签的数组。请注意,这是存储为数组的,但数组目前只会包含一个字符串。

QCSlack (always present)

当前解中松弛变量的值。

QCPi

对于具有对偶信息的连续模型,这是相应约束的对偶值。对于MIP模型,此组件将始终为空。

以下属性仅在JSONSolDetail大于0时包含:QCPi, QCSlack

JSON 解决方案示例#

对于一个连续模型,JSON解决方案字符串可能看起来像

{ "SolutionInfo": {
     "Status": 2,
     "Runtime": 9.9294495582580566e-01,
     "ObjVal": 5.2045497375374854e-07,
     "BoundVio": 0,
     "ConstrVio": 1.002e-07,
     "IterCount": 0,
     "BarIterCount": 3},
  "Vars": [
     {"VTag": ["VTag7"], "X": -3.0187172916263982e-09, "RC": 0},
     {"VTag": ["VTag1340"], "X": -3.0696132844593768e-09, "RC": 0},
     {"VTag": ["VTag2673"], "X": -4.8134359014615295e-09, "RC": 0},
     {"VTag": ["VTag4006"], "X": -7.1652420015125937e-02, "RC": 0},
     {"VTag": ["VTag5339"], "X": -1.5815441619302997e-02, "RC": 0},
     {"VTag": ["VTag6672"], "X": 1.4945278866946186e-02, "RC": 0}],
  "Constrs": [
     {"CTag": ["CTag7"], "Slack": 4.85722506e-17, "Pi": 2.3140310696e-06},
     {"CTag": ["CTag673"], "Slack": 0, "Pi": -1.4475853138350041e-06},
     {"CTag": ["CTag1339"], "Slack": -2.7758914e-17, "Pi": -3.7443785e-06},
     {"CTag": ["CTag2005"], "Slack": 4.3420177e-18, "Pi": -1.0277524e-06},
     {"CTag": ["CTag2671"], "Slack": -1.3895245e-17, "Pi": 8.0012944e-07},
     {"CTag": ["CTag3337"], "Slack": 6.39465e-16, "Pi": -5.3368958e-06}]}

对于一个多目标线性规划问题,JSON解决方案字符串可能看起来像

{ "SolutionInfo": {
     "Status": 2,
     "Runtime": 2.2838807106018066e-01,
     "ObjNVal": [ 10, 339],
     "IterCount": 112,
     "BarIterCount": 0,
     "NodeCount": 0},
  "Vars": [
     {"VTag": ["VTag7"], "X": 0},
     {"VTag": ["VTag569"], "X": 0},
     {"VTag": ["VTag1131"], "X": 0},
     {"VTag": ["VTag1693"], "X": 0},
     {"VTag": ["VTag2255"], "X": 0},
     {"VTag": ["VTag2817"], "X": 0},
     {"VTag": ["VTag3379"], "X": 0},
     {"VTag": ["VTag3941"], "X": 0},
     {"VTag": ["VTag4503"], "X": 0},
     {"VTag": ["VTag5065"], "X": 1},
     {"VTag": ["VTag5627"], "X": 1},
     {"VTag": ["VTag6189"], "X": 1}]}

对于一个常规的MIP问题,JSON解决方案字符串可能看起来像

{ "SolutionInfo": {
     "Status": 2,
     "Runtime": 2.4669170379638672e-03,
     "ObjVal": 3124,
     "ObjBound": 3124,
     "ObjBoundC": 3124,
     "MIPGap": 0,
     "IntVio": 1.958742e-08,
     "BoundVio": 0,
     "ConstrVio": 1.002e-07,
     "IterCount": 465,
     "BarIterCount": 0,
     "NodeCount": 1,
     "SolCount": 4,
     "PoolObjBound": 3124,
     "PoolObjVal": [ 3124, 3124, 3124, 3124]},
  "Vars": [
     {"VTag": ["VTag7"], "X": 1, "Xn": [ 1, 1, 1, 1]},
     {"VTag": ["VTag466"], "X": 0, "Xn": [ 0, 1, 1, 0]},
     {"VTag": ["VTag925"], "X": 0, "Xn": [ 0, 0, 0, 0]},
     {"VTag": ["VTag1384"], "X": 0, "Xn": [ 0, 0, 1, 1]},
     {"VTag": ["VTag1843"], "X": 0, "Xn": [ 0, 1, 0, 0]},
     {"VTag": ["VTag2302"], "X": 0, "Xn": [ 0, 1, 1, 0]}]}

对于一个多目标MIP,JSON解决方案字符串可能看起来像

{ "SolutionInfo": {
     "Status": 2,
     "Runtime": 3.5403838157653809e+00,
     "ObjNVal": [ 2763, 704],
     "IterCount": 595,
     "BarIterCount": 0,
     "NodeCount": 1,
     "SolCount": 6,
     "PoolObjVal": [ [ 2763, 704 ], [ 2763, 705 ],
                     [ 2763, 716 ], [ 2763, 718 ],
                     [ 2763, 769 ], [ 2763, 1060 ]]},
  "Vars": [
     {"VTag": ["VTag7"], "X": 1, "Xn": [ 1, 1, 1, 1, 1, 1]},
     {"VTag": ["VTag466"], "X": 0, "Xn": [ 0, 1, 0, 0, 0, 0]},
     {"VTag": ["VTag925"], "X": 0, "Xn": [ 0, 0, 0, 0, 1, 1]},
     {"VTag": ["VTag1384"], "X": 0, "Xn": [ 0, 0, 0, 0, 0, 0]},
     {"VTag": ["VTag1843"], "X": 0, "Xn": [ 0, 0, 1, 1, 0, 0]},
     {"VTag": ["VTag2302"], "X": 0, "Xn": [ 0, 1, 0, 0, 0, 0]}]}

对于多场景模型,JSON解决方案字符串可能如下所示

{ "SolutionInfo": {
     "Status": 2,
     "Runtime": 3.5403838157653809e+00,
     "ObjVal": 2763,
     "ObjBound": 2763,
     "ObjBoundC": 1324,
     "IntVio": 0,
     "BoundVio": 0,
     "ConstrVio": 0,
     "ScenNObjVal": [2763, 3413, 1e+100],
     "ScenNObjBound": [2763, 3413, 1e+100],
     "IterCount": 595,
     "BarIterCount": 0,
     "NodeCount": 1,
     "SolCount": 3,
     "PoolObjBound": 2763,
     "PoolObjVal": [ 2763, 2763, 2763]},
  "Vars": [
     {"VTag": ["VTag7"], "X": 1, "ScenNX": [1, 0, 1e+101], "Xn": [ 1, 0, 1]},
     {"VTag": ["VTag466"], "X": 0, "ScenNX": [1, 1, 1e+101], "Xn": [ 1, 1, 1]},
     {"VTag": ["VTag925"], "X": 0, "ScenNX": [0, 0, 1e+101], "Xn": [ 0, 0, 0]},
     {"VTag": ["VTag1384"], "X": 0, "ScenNX": [2, 1, 1e+101], "Xn": [ 2, 1, 0]},
     {"VTag": ["VTag1843"], "X": 0, "ScenNX": [0, 2, 1e+101], "Xn": [ 0, 2, 1]},
     {"VTag": ["VTag2302"], "X": 0, "ScenNX": [0, 1, 1e+101], "Xn": [ 0, 1, 0]}]}

如果场景目标值 ScenNObjVal 是无限的 (对于最小化问题,GRB_INFINITY = 1e+100,对于最大化问题,-GRB_INFINITY = -1e+100), 那么该场景没有找到可行的解决方案。每个变量的相应 ScenNX 值将为 GRB_UNDEFINED = 1e+101。此外,如果 该场景的 ScenNObjBound 值也是无限的,这意味着该场景已被证明是不可行的。

MST格式#

MIP起始(MST)文件用于为混合整数规划模型指定初始解。该文件列出了模型中变量的赋值。如果在优化开始之前已将MIP起始导入MIP模型(例如使用GRBread),Gurobi优化器将尝试从指定的起始值构建可行解。一个好的初始解通常会加快MIP模型的求解速度,因为它提供了最优值的早期界限,并且指定的解可用于播种MIP求解器采用的局部搜索启发式方法。

MIP起始文件由变量-值对组成,每对占一行。任何以井号(#)开头的行都是注释行,会被忽略。以下是一个简单的示例:

# MIP start
x1  1
x2  0
x3  1

将MIP起始值导入模型等同于将每个列出的变量的开始属性设置为相关值。如果同一个变量在起始文件中出现多次,则使用最后一次赋值。导入多个起始文件等同于读取导入文件的连接。

请注意,起始文件不需要为所有变量指定值。 当变量值未指定时,Gurobi求解器将尝试将指定的值扩展为完整模型的可行解。

需要提到的是,当保存MST文件时,Gurobi不会保存连续变量的值。如果你想保存找到的最佳解决方案的完整描述,我们建议将其保存为解决方案文件(SOL格式)。这将确保你保存模型中每个变量的值。

BAS 格式#

LP基础(BAS)文件用于为连续模型指定初始基础。该文件提供了模型中每个变量和约束的基础状态信息。如果由Gurobi编写,为了减小文件大小,它只包括与松弛基础的差异。在松弛基础中,每行的对应松弛变量是基础的,而所有其他问题变量都在其下界。如果在优化开始之前已将基础导入连续模型(例如使用GRBread),并且如果已选择单纯形优化器(通过方法参数),Gurobi单纯形优化器将从指定的基础开始。

BAS文件以NAME行开始,并以ENDATA语句结束。这些行不提供任何信息,但格式要求必须存在。在这两行之间是基状态行,每行由两个或三个字段组成,并以一个空白字符开头。如果第一个字段是LLULBS,则第二个字段中命名的变量(不允许松弛变量)分别在其下界非基、上界非基或基。任何额外的字段都将被忽略。如果第一个字段是XLXU,则第二个字段中命名的变量是基,而第三个字段中命名的行表示相应的松弛变量分别在其下界或上界非基。

以下是一个简单的例子:

NAME  example.bas
 XL x1 c1
 XU x2 c2
 UL x3
 LL x4
ENDATA

将基础导入模型等同于为每个列出的变量和约束设置VBasisCBasis属性到指定的基础状态。

一个接近最优的基可以加速困难LP模型的求解。 然而,指定一个与最优解不太接近的起始基通常会减慢求解过程。在提供起始基时要谨慎。