F# Or-Tools Sat 求解器

问题描述

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

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

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

enter image description here

解决方法

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

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

  1. 运算符 != 在 C# 中作为 LinearExpr 类上的静态运算符重载(这是不寻常的)。
  2. 运算符 != 编译为 op_Inequality,但 F# 中的 op_Inequality<>,而不是 !=
  3. F# 已经将 <> 定义为通用运算符,它接受任何满足 equality 约束的成员,LinearExpr 确实如此
  4. 定义的运算符 <> 正确解析,并产生 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,"y")
let z = model.NewIntVar(0L,"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 这样的不同类型。

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