MiniZinc 中的一般注释

General Annotations in MiniZinc

我对 MiniZinc 语言的一些通用注释的含义和用法有一些疑问。请说明何时应该使用它们,如果可能,请举例说明。

我从 MiniZinc 官方库中复制了我找到​​的定义以使问题更直接。

annotation is_defined_var

Declare the annotated variable as being functionally defined. This annotation is introduced into FlatZinc code by the compiler.

变量是函数定义的是什么意思?什么时候用?

annotation maybe_partial

Declare that expression may have undefined result (to avoid warnings)

表达式有未定义的结果是什么意思?有人可以举个例子吗?

annotation promise_total

Declare function as total, i.e. it does not put any constraints on its arguments.

这是什么意思?我很想看到这样的例子。是在引入自己的函数时这样,还是也可以用于已经定义好的Minizink函数?

annotation var_is_introduced

Declare a variable as being introduced by the compiler.

同样,编译器引入变量是什么意思?相反的说法是什么?变量不是编译器引入的?

annotation defines_var(var $t: c)

Declare variable: c as being functionally defined by the annotated constraint. This annotation is introduced into FlatZinc code by the compiler.

再说一次,c 是函数定义是什么意思,有人可以举个例子吗?

我知道这些是关于一个非常具体的库的很多问题,但我在任何地方都找不到任何好的解释。

首先让我说一下,您所询问的注释在 MiniZinc 中建模时通常不会使用。 (maybe_partial 可能是个例外,它可能有助于隐藏模型中的警告。)这些注释应该由 FlatZinc 求解器及其 MiniZinc 库的实现者使用。对于仍然感兴趣的任何人:这里遵循一些解释 + 这些注释的用法示例。

定义的变量

is_defined_vardefines_var(...) 是在函数定义变量时使用的注释。这些注释总是成对出现。当变量 x 具有 is_defined_var 注释时,则存在具有 defines_var(x).

的约束项

当一个变量的解值遵循单个 constraint/function 时,该变量在函数上定义。例如,我们可以键入 a * b = c,现在 c 的解值将从 a * b 得出。这意味着在生成的 FlatZinc 中我们会发现如下内容:

var int: a;
var int: b;
var int: c ::is_defined_var;
constraint int_times(a,b,c) ::defines_var(c);

请注意,这些函数定义经常出现在数学表达式和具体化中。

您可能永远不必添加这些注释。它们将由 MiniZinc 编译器自动添加。然后求解器可以使用这些注释来分析约束和变量之间的关系。例如,在某些情况下,求解器可能会使用视图而不是完整变量。

引入变量

MiniZinc 中的某些表达式不能用简单 约束联合表示。由于各种约束之间的关系,可能必须添加一个新变量才能在 FlatZinc 中具有与原始 MiniZinc 表达式等效的逻辑表达式。

以表达式a \/ (b /\ c)为例。此表达式至少需要两个约束,一个 bool_and 和一个 bool_or 约束。然而,在 FlatZinc 中,谓词调用不能包含除标识符或文字以外的任何内容。因此,为了在 FlatZinc 中表达我们的示例,我们必须具体化 and-expression 并在 or-expression 中使用真值。生成的 FlatZinc 将类似于:

var bool: a;
var bool: b;
var bool: c;
var bool: X_INTRODUCED_0_ ::var_is_introduced ::is_defined_var;
constraint bool_or(a,X_INTRODUCED_0_,true);
constraint bool_and(b,c,X_INTRODUCED_0_) ::defines_var(X_INTRODUCED_0_);

请注意,因为我们使用的是具体化,所以我们再次看到函数定义的变量。

注解 var_is_introduced 可以再次被求解器用来优化它的过程。它可以为变量使用视图,甚至可能在已知变量值后丢失它。

部分函数

有些函数,即使在纯数学中,也是部分函数,​​这意味着它们没有针对所有可能输入的定义结果。最常见的例子是除法:我们不能除以零,x / 0 == ??。在大多数编程语言中,这样写会产生编译错误。然而,在 MiniZinc 中,未定义的表达式将 "bubble up" 到它最近的父布尔上下文并将其定义为 false。有关此机制的更多信息,请参阅论文 "The Proper Treatment of Undefinedness in Constraint Languages",其中它被称为关系语义。

在 MiniZinc 中,最常见的可以未定义的函数是数组访问 a[i](越界时未定义)、除法和可选变量的值查找 deopt(x)(不存在时未定义) .

例如,给定一个范围为 1..1 的数组 a 和一个布尔变量 b,我可以编写一个表达式 b -> (a[0] == 1)。由于 a[0] 不存在,因此没有可与 1 进行比较的值。根据 MiniZinc 语义,这意味着 (a[0] == 1) 将被设置为 false.

尽管这是对 MiniZinc 的有效使用,但以这种方式使用部分函数很可能是错误的。 (当循环的边界太大时,通常会发生这种情况)。为了让建模者意识到这一点,MiniZinc 编译器将打印一条警告 WARNING: undefined result becomes false in Boolean context。然而,有时建模者知道他在做什么并且可能实际上想要使用这些语义。在那个表达式中可以用 maybe_partial 注释来告诉编译器建模者不需要被警告。对于我们的示例,我们可以使用 b -> (a[0] == 1)::maybe_partial

当必须使用此部分语义时,maybe_partial 注释主要用于 MiniZinc 库中。由于建模者不应该收到有关正确使用库函数的任何警告,因此这些注释很重要。

总函数

全函数与偏函数相反。 promise_total 向编译器发出信号,表明所提供的函数可用于该函数的所有可能输入。你可以在标准库的很多地方找到它。

由于这些承诺,我们的库函数可以为包含的函数实现 关系语义 (如论文 "The Proper Treatment of Undefinedness in Constraint Languages" 中所述)。通常,部分函数必须进行额外的检查,然后 post 基于该检查的约束。为了确保没有无穷无尽的检查,承诺在部分函数中调用的谓词是完整的。

在com如果使用 promise_total 的函数,则其行为就好像该语言将使用 严格语义 (如同一篇论文中所述),并且未定义的结果可能会导致编译或求解器错误.