I am experimenting with F# and want to do some constraint programming where I use Or-Tools. I have previously used the package together with Python, but I can’t get it to work with F#.
I follow the C# example: https://developers.google.com/optimization/cp/cp_solver#c_5
But get an error when try to add a constraint:

So this is kind of annoying, but it's how consuming operators that were overloaded in C# from F# works.
The reason why you couldn't use != like this is because:
!= is (and this is unusual) overloaded in C# as a static operator on the LinearExpr class.!= compiles down to op_Inequality, but op_Inequality in F# is <>, not !=<> as a generic operator that accepts any member that satisfies the equality constraint, which LinearExpr does<> resolves correctly, and produces a bool, which is incompatible with model.Add because it doesn't expect a boolThe solution is to explicitly qualify your access to the operator like so:
LinearExpr.(<>) (x, y)
Note that because it takes tupled arguments in its definition, you must also tuple your arguments and you can't use it like a "normal" operator.
Here is the full F# solution, with a few small tweaks to make it idiomatic:
#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)}"
A way to make this a bit nicer from F# is to define a module of operators that map to the LinearExpr operators like so:
module LinearExprOperators =
let ( ^<> ) (x: LinearExpr) (y: LinearExpr) = LinearExpr.(<>) (x, y)
let ( ^= ) (x: LinearExpr) (y: LinearExpr) = LinearExpr.(=) (x, y)
Then you can use those operators instead. Another annoyance is that it appears that + and - and * work just fine, because the F# type doesn't produce a different type like bool.
So in short, this particular API is a little annoying to use from F#.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With