【ortools源码系列1】 cp-sat cp_model Proto h头文件cpp源码分析

本文深入分析了ortools库中cp-sat模块的cp_model Proto头文件,详细介绍了IntegerVariableProto、LinearConstraintProto等约束类型,以及BoolVar、IntVar、LinearExpr等核心数据结构。同时,探讨了DoubleLinearExpr的加减乘运算实现。
摘要由CSDN通过智能技术生成

ortools cp-sat cp_model Proto h头文件cpp源码分析

描述约束规划问题的Proto。

IntegerVariableProto

// 描述约束规划问题的Proto。

syntax = "proto3";

package operations_research.sat;

option csharp_namespace = "Google.OrTools.Sat";
option java_package = "com.google.ortools.sat";
option java_multiple_files = true;
option java_outer_classname = "CpModelProtobuf";

// 一个整数变量。
//
// 它将被一个与其在CpModelProto variables字段中的索引相对应的int32值所引用。
//
// 根据上下文,对于定义域在[0,1]范围内的变量,也可以视为布尔值,如果变量值为1,则为true,否则为false。
// 当以这种上下文使用时,字段名将始终包含“literal”一词。
//
// 负引用(高级用法):为了简化模型的创建并提高效率,所有的“literal”或“variable”字段也可以包含负索引。
// 负索引i将引用索引-i-1处的整数变量的否定,或者引用相同索引处的字面值的非。 
//
// 例如:变量索引4将引用整数变量model.variables(4),索引为-5将引用相同变量的否定。
// 字面值索引4将引用逻辑事实model.variable(4) == 1,字面值索引为-5将引用逻辑事实model.variable(4) == 0。
message IntegerVariableProto {
   
  // 仅用于调试/记录。可以为空。
  string name = 1;

  // 变量域表示为一组n个不相交区间[min, max],并编码为[min_0, max_0, ..., min_{n-1}, max_{n-1}]的形式。
  //
  // 最常见的例子是[min, max]。
  // 如果min == max,则这是一个常量变量。
  //
  // 我们有:
  //  - domain_size()始终为偶数。
  //  - min == domain.front();
  //  - max == domain.back();
  //  - 对于所有i < n:      min_i <= max_i
  //  - 对于所有i < n-1:  max_i + 1 < min_{i+1}。
  //
  // 注意,在验证时我们检查变量域是否足够小,以确保在算法中不会遇到整数溢出。因此,
  // 您不能只使用“无界”变量,例如[0, kint64max],应尽量指定更紧密的变量域。
  repeated int64 domain = 2;
}

BoolArgumentProto

// 约束参数,形如OP(literals)。
message BoolArgumentProto {
  repeated int32 literals = 1;
}

LinearExpressionProto

// 一些约束支持线性表达式,而不仅仅是对变量的引用。这在缩减模型大小时特别有用。
message LinearExpressionProto {
  repeated int32 vars = 1;
  repeated int64 coeffs = 2;
  int64 offset = 3;
}

LinearArgumentProto

message LinearArgumentProto {
  LinearExpressionProto target = 1;
  repeated LinearExpressionProto exprs = 2;
}

AllDifferentConstraintProto

 // 所有的互异约束必须具有不同的值。
message AllDifferentConstraintProto {
  repeated LinearExpressionProto exprs = 1;
}

LinearConstraintProto

 // 线性和vars[i] * coeffs[i]必须在给定域内。域与IntegerVariableProto中的域格式相同。
//
// 注意,验证代码目前使用变量的域来检查和计算求和是否会导致整数溢出,并在出现溢出时抛出错误。
message LinearConstraintProto {
  repeated int32 vars = 1;
  repeated int64 coeffs = 2;  // 与vars大小相同。
  repeated int64 domain = 3;
}

ElementConstraintProto

 // 约束target = vars[index]。这强制要求index在[0, vars_size())范围内。
message ElementConstraintProto {
  int32 index = 1;
  int32 target = 2;
  repeated int32 vars = 3;
}

IntervalConstraintProto

 
// 这实际上不是一个约束。它存在于此,以便其他约束可以使用此“间隔”概念进行引用。
//
// 重要提示:当前,此约束不对组件之间的关系进行任何强制,并且客户端需要添加以下内容到模型中:
// - 强制 => start + size == end。
// - 强制 => size >= 0  // 如果size尚未>= 0,则只在size不为0时需要。
//
// 重要提示:目前,我们仅支持仿射关系。我们可以很容易地创建一个中间变量以支持完整的线性表达式,
// 但目前尚未这样做。
message IntervalConstraintProto {
  LinearExpressionProto start = 4;
  LinearExpressionProto end = 5;
  LinearExpressionProto size = 6;
}

NoOverlapConstraintProto

 // 所有区间(IntervalConstraintProto的索引)必须不相交。
// 更正式地说,必须存在一个序列,使得对于每个连续的区间,我们都有end_i <= start_{i+1}。
// 特别地,大小为零的区间对于此约束很重要。
// 这在调度中也被称为“分离”约束。
message NoOverlapConstraintProto {
  repeated int32 intervals = 1;
}

NoOverlap2DConstraintProto

// [start_x, end_x) * [start_y, end_y)定义的盒子不能重叠。
// 此外,如果x或y间隔中至少有一个为可选,则一个盒子是可选的。
message NoOverlap2DConstraintProto {
  repeated int32 x_intervals = 1;
  repeated int32 y_intervals = 2;  // 与x_intervals大小相同。
  bool boxes_with_null_area_can_overlap = 3;
  // TODO:添加重复的LinearExpressionProto作为可选区域。
}

CumulativeConstraintProto

// 在每个时间点,各个时间点上区间的需求之和不能超过容量。注意,对于这个约束,间隔被解释为[start, end),
// 因此对于这个约束来说,[2,3)和[3,4)在逻辑上不重叠。此外,大小为零的区间被忽略。
//
// 所有需求都不能在其域中包含任何负值。这在验证时进行检查。容量目前可以包含负值,但会立即传播到>= 0。
message CumulativeConstraintProto {
  LinearExpressionProto capacity = 1;
  repeated int32 intervals = 2;
  repeated LinearExpressionProto demands = 3;  // 与intervals大小相同。
}

ReservoirConstraintProto

// 在界限内保持水位。
// 水位从0开始,在任何时候,它必须在[min_level, max_level]之间。
//
// 如果变量active_literals[i]为true,并且表达式time_exprs[i]赋予一个值t,
// 那么当前水平在时间t发生变化,变化量为level_changes[i]。因此,在任何时间t:
//
// sum(level_changes[i] * active_literals[i] if time_exprs[i] <= t)
//   in [min_level, max_level]
//
// 注意:最小水位必须<= 0,最大水位必须>= 0。使用固定的level_changes来模拟初始状态。
//
// 布尔变量数组'actives'(如果定义)指示哪些操作实际执行。
// 如果未定义此数组,则假定所有操作都将执行。
message ReservoirConstraintProto {
  int64 min_level = 1;
  int64 max_level = 2;
  repeated LinearExpressionProto time_exprs = 3;  // 仿射表达式。
  // 目前,我们只支持常量水位变化。
  repeated LinearExpressionProto level_changes = 6;  // 仿射表达式。
  repeated int32 active_literals = 5;
  reserved 4;
}

CircuitConstraintProto

// 约束是在由文字控制的有向图上定义的。每个弧由tails/heads/literals列表中的索引给出,
// 这些列表必须具有相同的大小。
//
// 目前,我们忽略没有关联弧的节点。所有其他节点必须恰好有一个传入和一个传出的选定弧(即真值文字)。
// 所有未自循环的选定弧必须形成一个单一的回路。请注意,多重弧是允许的,但同一时间只能有一个弧为true。 
// 但是不允许多重自循环。
message CircuitConstraintProto {
  repeated int32 tails = 3;
  repeated int32 heads = 4;
  repeated int32 literals = 5;
}

RoutesConstraintProto

// "VRP"(车辆路径问题)约束。
//
// 弧 #i(从tails[i]到head[i])存在(由文字表示的弧存在)当且仅当满足以下一组属性的直接图:
// - #入弧 == 1,除了节点0。
// - #出弧 == 1,除了节点0。
// - 对于节点零,#入弧 == #出弧。
// - 没有重复的弧。
// - 自弧允许,但节点0除外。
// - 图中没有循环,除了通过节点0。
//
// 注意:当前,此约束期望[0, num_nodes)中的所有节点至少有一个入射弧。如果不是这种情况,则该模型将被认为无效。
// 如果需要,可以添加一个固定为1的自弧来忽略某些节点。
//
// TODO(用户):可能可以将此约束推广到一般图中的无环或具有sum incoming <= 1和sum outgoing <= 1的无环
// (更高效的实现)。另一方面,具有特定约束使我们能够向VRP问题添加特定的“割”。
message RoutesConstraintProto {
  repeated int32 tails = 1;
  repeated int32 heads = 2;
  repeated int32 literals = 3;

  // 实验性。每个节点的需求以及每条路径的最大容量。请注意,目前仅用于LP松弛,并且需要在LP之外添加相应的约束来强制执行此约束。
  //
  // 用户备注:理想情况下,我们应该能够从编码中自动提取任何维度,例如容量、路径长度等。经典的编码方式是沿着路径添加"current_capacity"变量,
  // 并使用以下形式的线性方程:
  //   arc_literal => (current_capacity_tail + demand <= current_capacity_head)
  repeated int32 demands = 4;
  int64 capacity = 5;
}

TableConstraintProto


// 变量的值只能是values中列出的n元组之一。n元组以平铺方式编码:
//     [tuple0_v0, tuple0_v1, ..., tuple0_v{n-1}, tuple1_v0, ...]。
message TableConstraintProto {
   
  repeated int32 vars = 1;
  repeated int64 values = 2;

  // 如果为true,则意味着"否定",即我们禁止任何可行赋值中的给定n元组。
  bool negated = 3;
}

InverseConstraintProto

// 两个变量数组分别表示一个函数,第二个变量数组表示第一个变量数组的逆:f_direct[i] == j <=> f_inverse[j] == i。
message InverseConstraintProto {
   
  repeated int32 f_direct = 1;
  repeated int32 f_inverse = 2;
}

AutomatonConstraintProto

// 这个约束强制一系列变量被自动机接受。

message AutomatonConstraintProto {
   
  // 状态由非负数标识。最好保持所有状态在[0, num_states)范围内连续。自动机从starting_state开始,并必须在任意一个final state结束。
  int64 starting_state = 2;
  repeated int64 final_states = 3;

  // 转移列表(三个向量的大小相同)。tail和head都是状态,label是任何变量值。同一个状态的两个出站转移不能有相同的label。
  repeated int64 transition_tail = 4;
  repeated int64 transition_head = 5;
  repeated int64 transition_label = 6;

  // 变量序列。自动机在vars_size()个“步骤”上运行,vars[i]的值对应于第i个步骤的转移标签。
  repeated int32 vars = 7;
}

ListOfVariablesProto

// 一个没有任何语义的变量列表。
message ListOfVariablesProto {
   
  repeated int32 vars = 1;
}

ConstraintProto

// 下一个ID: 31
message ConstraintProto {
   
  // 仅用于调试/日志记录。可以为空。
  string name = 1;

  // 当且仅当这里列出的所有文字为真时,该约束才会生效。如果此列表为空,则该约束将始终生效。必须满足强制约束,并且未强制的约束将被简单地忽略。

  // 这也被称为半重合。要使文字和约束(完全重合)之间具有等价关系,必须同时添加一个由文字l控制的约束和它的否定(由l的否定控制)。

  // 重要提示:截至2018年9月,只有少数约束支持强制执行:
  // - bool_or、bool_and、linear:完全支持。
  // - interval:只支持单个强制文字。
  // - 其他:不支持(但可以按需添加)。
  repeated int32 enforcement_literal = 2;

  // 实际的约束及其参数。
  oneof constraint {
   
    // bool_or约束要求至少一个文字为真。
    BoolArgumentProto bool_or = 3;

    // bool_and约束要求所有文字都为真。
    //
    // 从技术上讲,这是一个“冗余”约束,因为可以使用许多bool_or或at_most_one来编码。只是在空间效率上更高,并在内部处理稍有不同。
    BoolArgumentProto bool_and = 4;

    // at_most_one约束强制在同一时间最多只有一个文字为真。
    //
    // 注意,长度为n的at most one约束可以用n个右边项为n-1的bool_and约束来编码。因此,在某种意义上,该约束直接对模型的“蕴含图”或2-SAT部分起作用。
    //
    // 此约束不支持enforcement_literal。如果需要强制执行,请使用线性约束。您也不需要直接使用它,我们将在大多数情况下从模型中提取它。
    BoolArgumentProto at_most_one = 26;

    // exactly_one约束要求恰好一个文字为真。
    //
    // 每当将bool_or(它可以被称为at_least_one)包括在at_most_one中时,bool_or实际上是一个exactly one约束,并且在at_most_one中的额外文字可以设置为false。因此,在这种意义上,该约束实际上并不是必需的。它只是为了更好地描述问题结构和方便某些算法而存在。
    //
    // 此约束不支持enforcement_literal。如果需要强制执行,请使用线性约束。您也不需要直接使用它,我们将在大多数情况下从模型中提取它。
    BoolArgumentProto exactly_one = 29;

    // bool_xor约束要求奇数个文字为真。
    BoolArgumentProto bool_xor = 5;

    // int_div约束要求目标等于exprs[0] / exprs[1]。特别地,exprs[1]永远不能取值为0。同时,目前我们不支持exprs[1]跨越0。
    LinearArgumentProto int_div = 7;

    // int_mod约束要求目标等于exprs[0] % exprs[1]。exprs[1]的域必须严格为正。目标的符号与exprs[0]的符号相同。
    LinearArgumentProto int_mod = 8;

    // int_prod约束要求目标等于所有变量的乘积。按照惯例,因为我们可以只删除等于1的项,空乘积要求目标为1。
    //
    // 注意,求解器会检查潜在的整数溢出。因此,建议限制变量的域,使得乘积适合[INT_MIN + 1..INT_MAX - 1]。
    //
    // TODO(用户):支持多于两个项的乘积。
    LinearArgumentProto int_prod = 11;

    // lin_max约束要求目标等于所有线性表达式的最大值。
    // 注意,通过取反所有表达式,这可以模拟最小值。
    LinearArgumentProto lin_max = 27;

    // linear约束在变量之间强制线性不等式关系,例如0 <= x + 2y <= 10。
    LinearConstraintProto linear = 12;

    // all_diff约束要求所有变量取不同的值。
    AllDifferentConstraintProto all_diff = 13;

    // element约束要求给定索引的变量等于目标。
    ElementConstraintProto element = 14;

    // circuit约束接受图并要求存在(由文字指示)的弧构成唯一的环。
    CircuitConstraintProto circuit = 15;

    // routes约束实现车辆路径问题。
    RoutesConstraintProto routes = 23;

    // table约束要求元组的变量取值符合规定。
    TableConstraintProto table = 16;

    // automaton约束要求一系列变量被自动机接受。
    AutomatonConstraintProto automaton = 17;

    // inverse约束要求两个数组彼此互为逆:一个的值是另一个的索引,反之亦然。
    InverseConstraintProto inverse = 18;

    // reservoir约束要求一组活动需求的总和在特定时间内始终在指定的最小值和最大值之间。
    ReservoirConstraintProto reservoir = 24;

    // 区间约束。

    // 第一个约束定义了“区间”的含义,其他约束使用对它的引用。所有强制文字设置为false的区间都会被这些约束忽略。

    // TODO(用户):解释大小为零的区间会发生什么。某些约束忽略它们;其他则考虑它们。

    // interval约束采用开始、结束和大小,并要求开始+大小==结束。
    IntervalConstraintProto interval = 19;

    // no_overlap约束防止一组区间重叠;在调度中,这称为禁止约束。
    NoOverlapConstraintProto no_overlap = 20;

    // no_overlap_2d约束防止一组矩形框重叠。
    NoOverlap2DConstraintProto no_overlap_2d = 21;

    // cumulative约束确保对于任何整数点,包含该点的区间的需求之和不超过容量。
    CumulativeConstraintProto cumulative = 22;

    // 此约束不适用,求解器将拒绝它。它用于在测试presolve代码时标记变量。
    ListOfVariablesProto dummy_constraint = 30;
  }
}

CpObjectiveProto

// 优化目标。

message CpObjectiveProto {
   
  // 目标最小化的线性项。
  // 对于最大化问题,可以取反所有系数,并将scaling_factor设置为-1。
  repeated int32 vars = 1;
  repeated int64 coeffs = 4;

  // 显示的目标始终是:
  //   scaling_factor * (sum(coefficients[i] * objective_vars[i]) + offset)。
  // 这是在presolve之后或者当将一个双精度问题缩放为使用整数表示时,具有一致的目标所必需的。

  // 请注意,如果scaling_factor为零,则假定为1,因此默认情况下这些字段不起作用。
  double offset = 2;
  double scaling_factor = 3;

  // 如果非空,则仅在给定域中寻找目标值。
  // 请注意,这不依赖于offset或scaling factor,它只是目标项总和的域。
  repeated int64 domain = 5;

  // 内部字段。不要设置。当我们将FloatObjectiveProto缩放为整数版本时,如果缩放是精确的(例如,所有原始系数都是整数),则将此字段设置为true。
  //
  // TODO(用户):是否放置我们计算的误差界限?
  bool scaling_was_exact = 6;

  // 从presolved目标中恢复到原始整数目标的边界的内部字段。基本上,最初的整数目标适合int64,并且在[Initial_lb, Initial_ub]范围内。在presolve期间,我们可能会更改线性表达式以具有新域[Presolved_lb, Presolved_ub],这也总是适合int64。
  //
  // 这两个区间总是与两者之间的仿射变换相关:
  //   old = (new + before_offset) * integer_scaling_factor + after_offset。
  // 请注意,我们使用两个偏移量以始终能够在int64域内进行计算。特别地,after_offset始终在(-integer_scaling_factor,integer_scaling_factor)范围内。
  int64 integer_before_offset = 7;
  int64 integer_after_offset = 9;
  int64 integer_scaling_factor = 8;
}

FloatObjectiveProto

// 线性浮点数目标:sum(coeffs[i] * vars[i]) + offset。
// 请注意,变量只能采用整数值。
message FloatObjectiveProto {
   
  repeated int32 vars = 1;
  repeated double coeffs = 2;
  double offset = 3;

  // 优化方向。默认是最小化。
  bool maximize = 4;
}

DecisionStrategyProto

// 在求解器需要做出新决策时,定义要遵循的策略。请注意,该策略仅定义在变量的子集上。

message DecisionStrategyProto {
   
  // 下一个决策要考虑的变量。顺序很重要,并且始终作为变量选择策略的排序准则使用。
  repeated int32 variables = 1;

  // 考虑上面列出的变量的顺序。请注意,仅考虑尚未固定的变量。
  //
  // TODO(用户):根据需要扩展。
  enum VariableSelectionStrategy {
   
    CHOOSE_FIRST = 0;
    CHOOSE_LOWEST_MIN = 1;
    CHOOSE_HIGHEST_MAX = 2;
    CHOOSE_MIN_DOMAIN_SIZE = 3;
    CHOOSE_MAX_DOMAIN_SIZE = 4;
  }
  VariableSelectionStrategy variable_selection_strategy = 2;

  // 一旦选择了一个变量,此枚举描述对其域采取的决策。
  //
  // TODO(用户):根据需要扩展。
  enum DomainReductionStrategy {
   
    SELECT_MIN_VALUE = 0;
    SELECT_MAX_VALUE = 1;
    SELECT_LOWER_HALF = 2;
    SELECT_UPPER_HALF = 3;
    SELECT_MEDIAN_VALUE = 4;
  }
  DomainReductionStrategy domain_reduction_strategy = 3;

  // 高级用法。上面列出的某些变

SparsePermutationProto

// 一个稀疏格式的整数排列,以循环列表的形式编码。元素cycle[i]的映射是cycle[(i + 1) % cycle_length]。
message SparsePermutationProto {
  // 每个循环按顺序列在support字段中。
  // 每个循环的大小按顺序在cycle_sizes字段中给出。
  repeated int32 support = 1;
  repeated int32 cycle_sizes = 2;
}

DenseMatrixProto

// 以扁平方式编码的稠密矩阵。
// 即 matrix[i][j] = entries[i * num_cols + j];
message DenseMatrixProto {
  int32 num_rows = 1;
  int32 num_cols = 2;
  repeated int32 entries = 3;
}

SymmetryProto

// 实验性质的。目前,这是供求解器使用的,不由客户端填充。
//
// 存储关于可行解集合的对称信息。如果我们使用这里描述的置换之一对任何可行解的变量值进行置换,
// 我们应该始终得到另一个可行解。
//
// 我们通常还要求新解的目标值保持不变。
//
// 这里编码的置换群通常是从模型的编码计算出来的,因此它不是完整的可行解对称性的表示,
// 只是一个有效的子群。
message SymmetryProto {
  // 在使解空间的可行解保持不变的变量索引置换列表。
  // 通常,我们只编码一组生成元。
  repeated SparsePermutationProto permutations = 1;

  // Orbitope是解空间的特殊对称结构。如果变量索引排列在矩阵中(没有重复项),
  // 那么任何列的置换都将是可行解的有效置换。
  //
  // 这种情况经常发生。典型的例子是图着色问题,
  // 对于每个节点i,您有j个布尔值来指示其颜色。如果变量color_of_i_is_j
  // 在矩阵[i][j]中排列,那么任何列的置换都会保持问题不变。
  repeated DenseMatrixProto orbitopes = 2;
}

CpModelProto

// 约束规划问题。
message CpModelProto {
   
  // 仅用于调试/日志记录。可以为空。
  string name = 1;

  // 相关Protos应通过它们在这些字段中的索引进行引用。
  repeated IntegerVariableProto variables = 2;
  repeated ConstraintProto constraints = 3;

  // 要最小化的目标。对于纯决策问题可以为空。
  CpObjectiveProto objective = 4;

  // 高级用法。
  // 具有目标和浮点数目标同时存在无效。
  //
  // 模型的浮点格式的目标。求解器将在扩展过程中自动将其缩放为整数,
  // 并将其转换为正常的CpObjectiveProto。请参阅mip*参数以控制此缩放方式。
  // 在大多数情况下,精度将足够好,但您可以查看日志以了解在转换为定点表示时所保证的精度。
  //
  // 请注意,即使精度不好,返回的目标值和最佳目标界限也将计算正确。
  // 因此,在求解结束时,如果只想要精确的最优解,可以检查间隙。
  FloatObjectiveProto floating_point_objective = 9;

  // 定义搜索_branching参数设置为FIXED_SEARCH时求解器应遵循的策略。
  // 请注意,当我们不处于固定搜索状态时,此策略也用作启发式方法。
  //
  // 高级用法:如果不是所有变量都出现,并且参数"instantiate_all_variables"设置为false,
  // 则求解器将不会尝试实例化未出现的变量。因此,在搜索结束时,可能不是所有变量都被固定。
  // 目前,我们将它们设置为解中的下界。
  repeated DecisionStrategyProto search_strategy = 5;

  // 解的提示。
  //
  // 如果已经知道问题的一个可行或几乎可行解,则将其传递给求解器可能有助于使用它。
  // 求解器将尝试使用此信息创建其初始可行解。
  //
  // 请注意,将此类提示提供给求解器并不总是更快。也不能保证求解器将使用此提示,
  // 或者在存在多个最优解的情况下尝试返回与此分配“接近”的解。
  PartialVariableAssignment solution_hint = 6;

  // 文字列表。模型将被假定所有这些文字都为真。与仅修复这些文字的域相比,使用此机制较慢,
  // 但可以在模型为INFEASIBLE的情况下获取一个可能的小子集,用于解释不可行性。
  //
  // 类似于(IIS),除非您只关心所提供的假设。这很强大,因为它允许将一组逻辑相关的约束
  // 组合在一个强制文字下,该文字可能会为您提供一个好且可解释的不可行性解释。
  //
  // 这种不可行解释将在sufficient_assumptions_for_infeasibility响应字段中可用。
  repeated int32 assumptions = 7;

  // 目前,这不是由编写模型的客户端填充的,而是由我们的预处理步骤填充的。
  //
  // 关于可行解空间的对称性信息。
  // 这些通常会使目标保持不变。
  SymmetryProto symmetry = 8;
}

// 求解CpModelProto时求解器返回的状态。
enum CpSolverStatus {
   
  // 模型的状态仍未知。在确定以下任何状态之前,已达到搜索限制。
  UNKNOWN = 0;

  // 给定的CpModelProto未通过验证步骤。您可以通过调用ValidateCpModel(model_proto)来获取详细错误信息。
  MODEL_INVALID = 1;

  // 找到了一个可行解。但是,在能够证明最优性之前或在枚举可行性问题的所有解之前停止了搜索(如果被要求)。
  FEASIBLE = 2;

  // 问题已被证明不可行。
  INFEASIBLE = 3;

  // 找到了最优的可行解。
  //
  // 更一般地说,此状态表示成功。因此,如果我们找到纯可行性问题的解,
  // 或者指定了间隙限制并返回在此限制内的解,则还会返回OPTIMAL。
  // 如果需要返回所有可行解,则仅当我们枚举了所有可行解时才返回此状态;
  // 如果在之前停止,则返回FEASIBLE。
  OPTIMAL = 4;
}

// 只是用于存储稠密解的消息。
// 这由additional_solutions字段使用。
message CpSolverSolution {
   
  repeated int64 values = 1;
}

// 求解CpModelProto时求解器返回的响应。
//
// TODO(user):支持返回多个解。查看Stubby流API,因为我们可能希望在找到它们时获取它们。
// 下一个ID:30
message CpSolverResponse {
   
  // 求解的状态。
  CpSolverStatus status = 1;

  // 给定问题的可行解。根据返回的状态,它可能是最优的或只是可行的。
  // 这与CpModelProto::variables重复字段一一对应,并列出所有变量的值。
  repeated int64 solution = 2;

  // 仅对于优化问题有意义。如果非空,则为返回解的目标值。
  // 如果没有解,则对于最小化问题,这将是任何可行解的目标的上界,
  // 对于最大化问题,则是下界。
  double objective_value = 3;

  // 仅对于优化问题有意义。对于最小化问题,这是目标的已证明下界,
  
  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值