Optimization domain specific language in F# with units of measure

In Solver Foundation CTP release, we shipped an optimization domain specific language (ODSL) in F#, which embedded Solver Foundation simplex solver for solving linear programming models. In the upcoming version 2 release, we will ship an enhanced version of this ODSL. Here are some of the highlights:

· Units of measure: in F# numerical quantities can be annotated by a unit such as kilogram, dollar per day. These annotations not only provide additional and explicit documentation on the nature of the quantities involved, but also allow F# to statically check that no mistake is made in the use of these quantities: adding Watt and Newton is incorrect for example.

Units of measures in F# are declared as follows:

[<Measure>] type Dollar

[<Measure>] type Barrel

[<Measure>] type Day

[<Measure>] type ProductionRate = Barrel/Day


The syntax for annotating a numerical value with its measure is shown below:

let dailyOutput = 9000.0<Barrel/Day>

let price = 140.0<Dollar/Barrel>

let dailyCost = dailyOutput * price


In our new ODSL, units of measures can be used in modeling a problem, which help modelers to catch errors in the model where incompatible quantities are used in the constraints or goal functions. Here is a simple example of the Petrochem problem.

let a = 20.0<Dollar/Barrel>

let b = 15.0<Dollar/Barrel>

let sa = var<Barrel/Day>()

let vz = var<_>()

minimise (a * sa + b * vz)



      0.3 * sa + 0.4 * vz >= 2000.<_>;

      0.4 * sa + 0.2 * vz >= 1500.<_>;

      0.2 * sa + 0.3 * vz >= 500.<_>;

sa <= 9000.<_>;

      vz <= 6000.<_>;

      sa >= 0.<_>;

      vz >= 0.<_>



Note that if quantities such as a were defined to have a measure other than Dollar/Barrel, F# would have caught the error in the goal function where b*vz had the measure Dollar/Day while a*sa did not.

· Solver Foundation wrapper in F#: this wrapper directly wraps Solver Foundation APIs and does not use F# quotations. With this wrapper, we also enabled units of measure in models that are written against Solver Foundation APIs. Here is the model of the same Petrochem problem written in this wrapper:

    [<Measure>] type Dollar

    [<Measure>] type Barrel

    [<Measure>] type Day

    [<Measure>] type ProductionRate = Barrel/Day

    // Initialization of the SFS model from the context

    // We use the SfsModel class that wraps the usual SFS Model class

    // and additionally keeps track of the F#-specific type information

    let context = SolverContext.GetContext()

    let petrochem = new SfsModel(context)

/// Optimization variable: Production in Saudi-Arabia

let buyfromSA = petrochem.CreateRealVariable<ProductionRate>()

/// Optimization variable: Production in Venezuela

let buyfromVZ = petrochem.CreateRealVariable<ProductionRate>()


    // Add the production constraints:

    // How much of gasoline, jet fuel and machine lubricants can

    // we refine from the oil provided by the two supplier countries?

    let c1 = petrochem.AddConstraint (

0.3*buyfromSA + 0.4*buyfromVZ >>== 2000.0<Barrel/Day>)

    let c2 = petrochem.AddConstraint (

0.4*buyfromSA + 0.2*buyfromVZ >>== 1500.0<Barrel/Day>)

    let c3 = petrochem.AddConstraint (

0.2*buyfromSA + 0.3*buyfromVZ >>== 500.0<Barrel/Day>)

    /// Maximum production in Saudi-Arabia

    let maxProductionSA = 9000.0<_>

    /// Maximum production in Venezuela

    let maxProductionVZ = 6000.0<_>

    // Add the maximum production constraints to the model

    petrochem.AddConstraints [|

        0.0<_> <<== buyfromVZ; buyfromVZ <<== maxProductionVZ;

        0.0<_> <<== buyfromSA ; buyfromSA <<== maxProductionSA


    /// Business goal: minimize the running costs

    let runningCost = petrochem.AddGoal (GoalKind.Minimize,

20.0<Dollar/Barrel>*buyfromSA +


    /// Solution to the petrochem example

    let petrochemSolution = petrochem.Solve()


The ODSL and the wrapper source code will be shipped in Solver Foundation version 2 as a sample on how to enable F# to solve optimization problems. More details will be available in the release doc. The essence here is that, being a complete .NET solution and CLS compliant, Solver Foundation can be easily embedded in other .NET environments to help our customers to solve their problems in the environment that they are most familiar with.

Version 2 of Solver Foundation contains a number of new features and enhancements. Please also check out Nathan’s blog on simulation and stochastic programming. For more information, please stay tuned for the actual release.