问题描述
我正在试验 F# 并希望在使用 Or-Tools 的地方进行一些约束编程。我之前曾将该包与 Python 一起使用,但我无法使其与 F# 一起使用。
我遵循 C# 示例:https://developers.google.com/optimization/cp/cp_solver#c_5
解决方法
所以这有点烦人,但这就是在 C# 中从 F# 重载的消耗运算符的工作原理。
您不能像这样使用 !=
的原因是:
- 运算符
!=
在 C# 中作为LinearExpr
类上的静态运算符重载(这是不寻常的)。 - 运算符
!=
编译为op_Inequality
,但 F# 中的op_Inequality
是<>
,而不是!=
- F# 已经将
<>
定义为通用运算符,它接受任何满足equality
约束的成员,LinearExpr
确实如此 - 定义的运算符
<>
正确解析,并产生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# 中使用起来有点烦人。