How to: Bind Data Tables to Parameters and Output
You can use linear programming to minimize or maximize functions. In this data binding example, an oil refinery must procure crude oil from two sources. The objective is to minimize the purchase cost of crude oils of varying quality and to meet minimum production levels of 2,000 barrels of gasoline, 1,500 barrels of jet fuel, and 500 barrels of machine lubricant. Meanwhile, the suppliers cannot exceed their maximum daily production of crude oil. The following table shows the costs and capabilities of the two different crude oils.
|
Source |
Saudi Arabia refining |
Venezuela refining |
|---|---|---|
|
Cost |
$20 per barrel |
$15 per barrel |
|
Maximum daily production |
9,000 barrels |
6,000 barrels |
|
Refining percentages |
30% gasoline 40% jet fuel 20% lubricant 10% waste |
40% gasoline 20% jet fuel 30% lubricant 10% waste |
The following example demonstrates how to use Solver Foundation to create and solve the refining model by using the Solver Foundation Services layer.
To bind data tables to input parameters and output variables
-
Create a console application named PetroChem.
-
Add a reference to Microsoft Solver Foundation on the .NET tab.
-
Add the following Imports or using statements to the top of the Program code file.
-
Create a class that defines the information used to describe a country or region, a class that defines the production capabilities, and a class that defines the petroleum yield output.
Class CountryDef Public Property Country() As String Get Return m_Country End Get Set(ByVal value As String) m_Country = value End Set End Property Private m_Country As String Public Property MaxProduction() As Double Get Return m_MaxProduction End Get Set(ByVal value As Double) m_MaxProduction = value End Set End Property Private m_MaxProduction As Double Public Property Price() As Double Get Return m_Price End Get Set(ByVal value As Double) m_Price = value End Set End Property Private m_Price As Double Public Property Yield() As Double Get Return m_Yield End Get Set(ByVal value As Double) m_Yield = value End Set End Property Private m_Yield As Double Public Property Production() As Double Get Return m_Production End Get Set(ByVal value As Double) m_Production = value End Set End Property Private m_Production As Double Public Sub New(ByVal country As String, ByVal maxProduction As Double, ByVal price As Double, ByVal yield As Double) m_Country = country m_MaxProduction = maxProduction m_Price = price m_Yield = yield m_Production = -42 End Sub End Class Class ProductionDef Public Property Product() As String Get Return m_Product End Get Set(ByVal value As String) m_Product = value End Set End Property Private m_Product As String Public Property MinBuy() As Double Get Return m_MinBuy End Get Set(ByVal value As Double) m_MinBuy = value End Set End Property Private m_MinBuy As Double Public Sub New(ByVal product As String, ByVal minBuy As Double) product = product minBuy = minBuy End Sub End Class Class YieldDef Public Property Country() As String Get Return m_Country End Get Set(ByVal value As String) m_Country = value End Set End Property Private m_Country As String Public Property Product() As String Get Return m_Product End Get Set(ByVal value As String) m_Product = value End Set End Property Private m_Product As String Public Property Yield() As Double Get Return m_Yield End Get Set(ByVal value As Double) m_Yield = value End Set End Property Private m_Yield As Double Public Sub New(ByVal country As String, ByVal product As String, ByVal yield As Double) m_Country = country m_Product = product m_Yield = yield End Sub End Class
-
In the Main method, add the following code to instantiate the classes and define the data that describes the country or region, production capabilities, and petroleum yield output.
Dim ProductionCapacity As CountryDef() = { New CountryDef("Venezuela", 9000, 15, 0.4), New CountryDef("Saudi Arabia", 6000, 20, 0.3) } Dim ProductionYield As YieldDef() = { New YieldDef("Venezuela", "Gasoline", 0.4), New YieldDef("Venezuela", "JetFuel", 0.2), New YieldDef("Venezuela", "Lubricant", 0.3), New YieldDef("Saudi Arabia", "Gasoline", 0.3), New YieldDef("Saudi Arabia", "JetFuel", 0.4), New YieldDef("Saudi Arabia", "Lubricant", 0.2) } Dim ProductionRequirements As ProductionDef() = { New ProductionDef("Gasoline", 2000), New ProductionDef("JetFuel", 1500), New ProductionDef("Lubricant", 500) }
-
Add the following code to get the context environment for a solver and create a new model.
-
Create sets to hold the data for the country/region and products.
-
Create a decision that determines how much oil to buy from each country or region, and then bind the production capabilities data table to the decision. Finally, add the decision to the model.
-
Create parameters that represent columns of input data, and then bind data to the parameters. Then add the parameters to the model.
Dim max As New Parameter(Domain.RealNonnegative, "max", countries) Dim price As New Parameter(Domain.RealNonnegative, "price", countries) Dim yield As New Parameter(Domain.RealNonnegative, "yield", countries, products) Dim min As New Parameter(Domain.RealNonnegative, "min", products) max.SetBinding(ProductionCapacity, "MaxProduction", "Country") price.SetBinding(ProductionCapacity, "Price", "Country") yield.SetBinding(ProductionYield, "Yield", "Country", "Product") min.SetBinding(ProductionRequirements, "MinBuy", "Product") model.AddParameters(max, price, yield, min)
-
Create and add a constraint for the production capabilities. In the following code, the data is specified algebraically in a way that ensures that the amount of oil purchased is less than or equal to the country or region's maximum production capabilities.
-
Create and add a constraint for the petroleum yield output, which varies depending on the refining capabilities of each crude oil.
-
Add a goal that minimizes the cost of the products that are purchased.
-
Solve the model, call the PropagateDecisions method to save the results, and get the report.
-
Press F5 to build and run the code.
The Command window shows the following results.
===Solver Foundation Service Report===
Date: Date
Version: Version
Model Name: Default
Capabilities Applied: LP
Solve Time (ms): 152
Total Time (ms): 288
Solve Completion Status: Optimal
Solver Selected: Microsoft.SolverFoundation.Solvers.SimplexSolver
Directives:
Simplex(TimeLimit = -1, MaximumGoalCount = -1, Arithmetic = Default, Pricing = Default, IterationLimit = -1, Algorithm = Default, Basis = Default, GetSensitivity = False)
Algorithm: Primal
Arithmetic: Double
Variables: 2 -> 2 + 4
Rows: 6 -> 4
Nonzeros: 10
Eliminated Slack Variables: 0
Pricing (double): SteepestEdge
Basis: Slack
Pivot Count: 3
Phase 1 Pivots: 3 + 0
Phase 2 Pivots: 0 + 0
Factorings: 4 + 0
Degenerate Pivots: 0 (0.00 %)
Branches: 0
===Solution Details===
Goals:
cost: 92500
Decisions:
barrels_venezuela: 3500
barrels_saudiarabia: 2000