由于Microsoft Solver Foundation已被弃用,我试图找到一种替代或合理的方法来创建我自己的DSL。
我正在寻找的是在F#中描述LP的DSL必不可少的,用Clp解决它并评估结果。
在重新发明轮子之前:有人知道一个已经为LP提供DSL的好库吗?
否则,你将如何在F#中构建这样的DSL?基本上,我希望能够写出像
这样的东西let xs = createVars 100 in 0..1
let ys = [| 1 .. 100 |]
let f i x = i*x
let lp =
minimize sumprod(xs, ys) subjectTo [
xs.[0] + xs.[1] = 1
sum(xs) <= 1
sum({for i in 1..100 -> f i xs.[i]}) <= 100
// ...
]
let solver = Clp()
let result = solver.solve lp
答案 0 :(得分:6)
在重新发明轮子之前:有人知道一个已经为LP提供DSL的好库吗?
不,除了ODSL from Microsoft SolverFoundation本身,我什么都不知道。
否则,你将如何在F#中构建这样的DSL?
决定语言的语法。虽然您想构建一个内部DSL,但您必须决定允许哪些内容以及您的语言中无法表达的内容。
使用F# quotations获取AST。你为什么需要反思?首先,创建一组变量并将它们与浮点常量组合以形成线性约束。稍后,您将使用适当的值填充这些变量。 Reflection允许您创建占位符并稍后计算结果。
将AST转换为CLP中的线性程序并求解。似乎CLP没有.NET API;你可以通过命令行与解算器通信,但它不是很方便和健壮。 最好在创建DSL之前开始构建低级API。
(可选)在F#3.0中,您可以为DSL创建查询语法。您可以查看内置a convincing example的query expression。
由于Microsoft Solver Foundation已被弃用,我试图找到一种替代或合理的方法来创建自己的DSL。
无论如何,无国界医生将为您的工作提供有价值的范例。您可以浏览ODSL源代码in this codebase。实际上,从代码库中你可以看到ODSL已经完成了三个第一步。我正在ODSL之上构建一个优化查询语言(步骤4),并且只完成了表面语法。例如,这个原始的例子
<@
let sa = var<Barrel/Day>()
let vz = var<Barrel/Day>()
minimise (20.0<Dollar/Barrel> * sa + 15.0<Dollar/Barrel> * vz)
where
[
0.3 * sa + 0.4 * vz >= 2000.<Barrel/Day>;
0.4 * sa + 0.2 * vz >= 1500.<Barrel/Day>;
0.2 * sa + 0.3 * vz >= 500.<Barrel/Day>;
sa <= 9000.<Barrel/Day>;
vz <= 6000.<Barrel/Day>;
sa >= 0.<Barrel/Day>;
vz >= 0.<Barrel/Day>
]
@>
将转换为
opt { let! sa = var<Barrel/Day>()
let! vz = var<_>()
assume (0.3 * sa + 0.4 * vz >= 2000.<_>)
assume (0.4 * sa + 0.2 * vz >= 1500.<_>)
assume (0.2 * sa + 0.3 * vz >= 500.<_>)
assume (sa <= 9000.<_> && sa >= 0.<_>)
assume (vz <= 6000.<_> && vz >= 0.<_>)
minimise (20.0<Dollar/Barrel> * sa + 15.0<_> * vz)
}
如果您有兴趣,我还翻译了许多DSL示例here。