F# Or-Tools Sat 求解器

F# Or-Tools Sat Solver

我正在试验 F#,想在我使用 Or-Tools 的地方进行一些约束编程。我以前曾将此包与 Python 一起使用,但我无法使其与 F# 一起使用。

我遵循 C# 示例:https://developers.google.com/optimization/cp/cp_solver#c_5

但是在尝试添加约束时出现错误:

所以这有点烦人,但这就是在 C# 中从 F# 重载的消耗运算符的工作原理。

你不能像这样使用!=的原因是:

  1. 运算符 != 在 C# 中作为 LinearExpr class.
  2. 上的静态运算符重载(这很不寻常)
  3. 运算符 != 编译为 op_Inequality,但 F# 中的 op_Inequality<>,而不是 !=
  4. F# 已经将 <> 定义为通用运算符,它接受满足 equality 约束的任何成员,而 LinearExpr
  5. 定义的运算符 <> 正确解析,并生成 bool,这与 model.Add 不兼容,因为它不期望 bool

解决方案是明确限定您对运算符的访问权限,如下所示:

LinearExpr.(<>) (x, y)

请注意,因为它在其定义中采用元组参数,所以您还必须对参数进行元组处理,并且不能像“普通”运算符那样使用它。

这是完整的 F# 解决方案,经过一些小的调整以使其符合习惯:

#r "nuget: Google.OrTools"

open Google.OrTools.Sat

let model = CpModel()

// Creates the variables.
let num_vals = 3L;

let x = model.NewIntVar(0L, num_vals - 1L, "x")
let y = model.NewIntVar(0L, num_vals - 1L, "y")
let z = model.NewIntVar(0L, num_vals - 1L, "z")

// Creates the constraints.
model.Add(LinearExpr.(<>) (x, y))

// Creates a solver and solves the model.
let solver = CpSolver();
let status = solver.Solve(model)

if status = CpSolverStatus.Optimal then
    printfn $"x = {solver.Value(x)}"
    printfn $"y = {solver.Value(y)}"
    printfn $"z = {solver.Value(z)}"

一种通过 F# 使它变得更好的方法是定义一个映射到 LinearExpr 运算符的运算符模块,如下所示:

module LinearExprOperators =
    let ( ^<> ) (x: LinearExpr) (y: LinearExpr) = LinearExpr.(<>) (x, y)
    let ( ^= ) (x: LinearExpr) (y: LinearExpr) = LinearExpr.(=) (x, y)

那么您可以改用这些运算符。另一个烦恼是 +-* 似乎工作得很好,因为 F# 类型不会产生像 bool.[=33= 这样的不同类型]

简而言之,这个特殊的 API 在 F# 中使用有点烦人。