ortools cp-sat cp_model Proto h头文件cpp源码分析
描述约束规划问题的Proto。
IntegerVariableProto
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";
message IntegerVariableProto {
string name = 1;
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
message TableConstraintProto {
repeated int32 vars = 1;
repeated int64 values = 2;
bool negated = 3;
}
InverseConstraintProto
message InverseConstraintProto {
repeated int32 f_direct = 1;
repeated int32 f_inverse = 2;
}
AutomatonConstraintProto
message AutomatonConstraintProto {
int64 starting_state = 2;
repeated int64 final_states = 3;
repeated int64 transition_tail = 4;
repeated int64 transition_head = 5;
repeated int64 transition_label = 6;
repeated int32 vars = 7;
}
ListOfVariablesProto
message ListOfVariablesProto {
repeated int32 vars = 1;
}
ConstraintProto
message ConstraintProto {
string name = 1;
repeated int32 enforcement_literal = 2;
oneof constraint {
BoolArgumentProto bool_or = 3;
BoolArgumentProto bool_and = 4;
BoolArgumentProto at_most_one = 26;
BoolArgumentProto exactly_one = 29;
BoolArgumentProto bool_xor = 5;
LinearArgumentProto int_div = 7;
LinearArgumentProto int_mod = 8;
LinearArgumentProto int_prod = 11;
LinearArgumentProto lin_max = 27;
LinearConstraintProto linear = 12;
AllDifferentConstraintProto all_diff = 13;
ElementConstraintProto element = 14;
CircuitConstraintProto circuit = 15;
RoutesConstraintProto routes = 23;
TableConstraintProto table = 16;
AutomatonConstraintProto automaton = 17;
InverseConstraintProto inverse = 18;
ReservoirConstraintProto reservoir = 24;
IntervalConstraintProto interval = 19;
NoOverlapConstraintProto no_overlap = 20;
NoOverlap2DConstraintProto no_overlap_2d = 21;
CumulativeConstraintProto cumulative = 22;
ListOfVariablesProto dummy_constraint = 30;
}
}
CpObjectiveProto
message CpObjectiveProto {
repeated int32 vars = 1;
repeated int64 coeffs = 4;
double offset = 2;
double scaling_factor = 3;
repeated int64 domain = 5;
bool scaling_was_exact = 6;
int64 integer_before_offset = 7;
int64 integer_after_offset = 9;
int64 integer_scaling_factor = 8;
}
FloatObjectiveProto
message FloatObjectiveProto {
repeated int32 vars = 1;
repeated double coeffs = 2;
double offset = 3;
bool maximize = 4;
}
DecisionStrategyProto
message DecisionStrategyProto {
repeated int32 variables = 1;
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;
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;
repeated IntegerVariableProto variables = 2;
repeated ConstraintProto constraints = 3;
CpObjectiveProto objective = 4;
FloatObjectiveProto floating_point_objective = 9;
repeated DecisionStrategyProto search_strategy = 5;
PartialVariableAssignment solution_hint = 6;
repeated int32 assumptions = 7;
SymmetryProto symmetry = 8;
}
enum CpSolverStatus {
UNKNOWN = 0;
MODEL_INVALID = 1;
FEASIBLE = 2;
INFEASIBLE = 3;
OPTIMAL = 4;
}
message CpSolverSolution {
repeated int64 values = 1;
}
message CpSolverResponse {
CpSolverStatus status = 1;
repeated int64 solution = 2;
double objective_value = 3;