用于F#的LP DSL,其中Clp作为解算器

时间:2013-01-26 00:28:03

标签: f# clr dsl linear-programming clp

由于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

1 个答案:

答案 0 :(得分:6)

  

在重新发明轮子之前:有人知道一个已经为LP提供DSL的好库吗?

不,除了ODSL from Microsoft SolverFoundation本身,我什么都不知道。

  

否则,你将如何在F#中构建这样的DSL?

  1. 决定语言的语法。虽然您想构建一个内部DSL,但您必须决定允许哪些内容以及您的语言中无法表达的内容。

  2. 使用F# quotations获取AST。你为什么需要反思?首先,创建一组变量并将它们与浮点常量组合以形成线性约束。稍后,您将使用适当的值填充这些变量。 Reflection允许您创建占位符并稍后计算结果。

  3. 将AST转换为CLP中的线性程序并求解。似乎CLP没有.NET API;你可以通过命令行与解算器通信,但它不是很方便和健壮。 最好在创建DSL之前开始构建低级API。

  4. (可选)在F#3.0中,您可以为DSL创建查询语法。您可以查看内置a convincing examplequery expression

  5.   

    由于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