Difference between revisions of "Example 1: Beer Distribution LP, Base Case"

 
(21 intermediate revisions by 2 users not shown)
Line 1: Line 1:
==Example 1: Beer Distribution LP, Base Case==
+
[[Category: Analytica Optimizer Guide]]
 +
[[Category: Beer Distribution model]]
  
===Model Description===
+
<breadcrumbs> Analytica Optimizer Guide > Optimizing with Arrays > {{PAGENAME}}</breadcrumbs>
 +
<br />
 +
We start with an adaptation of a classic Linear Programming (LP) example.
  
We start with an adaptation of a classic Linear Programming (LP) example: A large brewing company operates five breweries nationwide. Each brewery distributes product among four regions. Routes include all combinations of Breweries and Market regions. The challenge is to find the shipping pattern that minimizes distribution cost while a) meeting demand in each region, and b) observing production limits at each brewery. We assume that distribution cost per case of beer is proportional to the distance between the brewery and the region.
+
==Model Description==
  
===Setting up the Model===
+
A large brewing company operates five breweries nationwide. Each brewery distributes product among four regions. Routes include all combinations of Breweries and Market regions. The challenge is to find the shipping pattern that minimizes distribution cost while
 +
<ol type="a">
 +
<li> meeting demand in each region, and
 +
<li> observing production limits at each brewery.</ol><br />We assume that distribution cost per case of beer is proportional to the distance between the brewery and the region.
  
To explore and follow this example in Analytica, find the '''Beer Distribution LP1.ana''' model in the Optimizer Examples folder.
+
==Setting up the Model==
  
====Brewery and Market (indexes)====
+
To explore and follow this example in Analytica, run the <code>Beer Distribution LP1.ana</code> model in the Optimizer Examples folder.
 +
 
 +
'''Brewery and Market (indexes)'''
  
 
There are five '''Breweries''' and four '''Market''' regions:
 
There are five '''Breweries''' and four '''Market''' regions:
  
<nowiki>Index Brewery :=  
+
<pre style="background:white; border:white; margin-left: 1em;">
      ['Fairfield','Fort Collins','Jacksonville','Merrimack','St Louis']  
+
Index Brewery := ['Fairfield', 'Fort Collins', 'Jacksonville', 'Merrimack', 'St Louis']  
Index Market := ['North','South','East','West']</nowiki>
+
Index Market := ['North', 'South', 'East', 'West']
 +
</pre>
 +
'''Distance (input array)'''
  
==== Distance (input array) ====
+
'''Distance''' between breweries and markets is represented as a table dimensioned by '''Brewery''' and '''Market'''. Units are thousands of miles:
Distance between breweries and markets is represented as a table dimensioned by Brewery and Market. Units are thousands of miles:
 
  
Variable Distance := Table(Brewery,Market)(1.8,2.2,3.4,0.1,0.3,1.2,2.4,1,2.9,1.8,0.6,3.3, 1.2,2.1,0.2,3.5,0.5,1.1,0.8,2.5)
+
<pre style="background:white; border:white; margin-left: 1em;">
 +
Variable Distance :=  
 +
      Table(Brewery, Market)(1.8, 2.2, 3.4, 0.1, 0.3,1.2, 2.4, 1, 2.9,1.8, 0.6, 3.3, 1.2, 2.1, 0.2, 3.5, 0.5, 1.1, 0.8, 2.5)
 +
</pre>
  
[[File:4-3.png|400px]]
+
:[[File:4-3.png|400px]]
  
==== Freight Price (input scalar value) ====
+
'''Freight Price (input scalar value)'''
Freight Price is a simple scalar value of $5 per 1,000 miles per case of beer.
 
  
Variable Freight_price := 5
+
'''Freight Price''' is a simple scalar value of $5 per 1,000 miles per case of beer.
 +
:<code>Variable Freight_price := 5</code>
 +
 
 +
'''Production Limits (input array)'''
  
==== Production Limits (input array) ====
 
 
'''Production Limits''' indicate maximum capacity for each brewery in cases of beer:  
 
'''Production Limits''' indicate maximum capacity for each brewery in cases of beer:  
Variable Production_limits := Table(Brewery)(600K,250K,450K,300K,240K)
+
:<code>Variable Production_limits := Table(Brewery)(600K, 250K, 450K, 300K, 240K)</code>
 +
 
 +
:[[File:4-4.png|400px]]
 +
 
 +
'''Delivery Targets (input array)'''
 +
 
 +
'''Delivery Targets''' indicate the minimum quota that each Market region must receive:
 +
:<code>Variable Delivery_target := Table(Market)(240K, 280K, 700K, 500K)</code>
  
[[File:4-4.png|400px]]
+
:[[File:4-5.png|400px]]
  
==== Delivery Targets (input array) ====
+
'''Distribution Cost (intermediate array)'''
Delivery Targets indicate the minimum quota that each Market region must receive:
 
Variable Delivery_target := Table(Market)(240K,280K,700K,500K)
 
  
[[File:4-5.png|400px]]
+
'''Distribution Cost per Case''' is Freight Price multiplied by Distance:  
 +
:<code>Variable Dist_per_case := Freight_price*Distance</code>
  
==== Distribution Cost (intermediate array) ====
+
'''Shipment Quantities (input decision array)'''
Distribution Cost per Case is Freight Price multiplied by Distance:
 
Variable Dist_per_case := Freight_price * Distance
 
  
==== Shipment Quantities (input decision array) ====
+
The input decision array represents '''Shipment Quantities''' from each brewery to each region. It is a two-dimensional array indexed by '''Brewery''' and '''Market'''. The non-optimized values are not used anywhere else in the model so we can simply insert 1 as a dummy value across the array.(Initial guesses do not apply since this is a Linear Program.)
The input decision array represents Shipment Quantities from each brewery to each region. It is a two-dimensional array indexed by Brewery and Market. The non-optimized values are not used anywhere else in the model so we can simply insert 1 as a dummy value across the array.(Initial guesses do not apply since this is a Linear Program.)
 
  
 
Units are cases of beer.
 
Units are cases of beer.
  
====Staying Positive ====
+
'''Staying Positive'''
  
 
We set the Lower Bound attribute to zero to disallow negative shipping values, along with the undesirable implication of turning perfectly good beer back into barley and hops.
 
We set the Lower Bound attribute to zero to disallow negative shipping values, along with the undesirable implication of turning perfectly good beer back into barley and hops.
  
====Set Brewery and Market as intrinsic indexes====
+
'''Set Brewery and Market as intrinsic indexes'''
  
Finally and perhaps most importantly, we consider the index status for this array. The optimized solution should be in the same form as this table. It should also be integrated such that every array element has simultaneous influence over all other elements. Brewery and Market are both intrinsic indexes in this case.
+
Finally and perhaps most importantly, we consider the index status for this array. The optimized solution should be in the same form as this table. It should also be integrated such that every array element has simultaneous influence over all other elements. '''Brewery''' and '''Market''' are both ''intrinsic'' indexes in this case.
  
Decision Shipment_Quantity := Array([Brewery, Market],1)
+
<pre style="background:white; border:white; margin-left: 1em;">
 +
Decision Shipment_Quantity := Array([Brewery, Market], 1)
 +
Shipment_Quantity attribute Lower Bound := 0
 +
Shipment_Quantity attribute Intrinsic Indexes := [Brewery, Market]
 +
</pre>
  
Shipment_Quantity attribute Lower Bound := 0
+
:[[File:4-6.png|400px]]
 +
 
 +
'''Total Distribution (Objective)'''
 +
 
 +
Our goal is to minimize the total distribution cost. For each route, distribution cost is the '''Distribution Cost per Case''' multiplied by the '''Shipment Quantity''' for each route. The final objective is the sum for all routes:
  
Shipment_Quantity attribute Intrinsic Indexes := [Brewery, Market]
+
<pre style="background:white; border:white; margin-left: 1em;">
 +
Objective Total_dist_cost :=  
 +
      Sum(Shipment_Quantity*Dist_per_case, Brewery, Market)
 +
</pre>
  
[[File:4-6.png|400px]]
+
Summing over '''Brewery''' and '''Market''' makes the objective a scalar value. This is a necessary condition for the optimization.
  
==== Total Distribution (Objective) ====
+
<Tip Title="Tip">Tip Every minimizing or maximizing optimization is based on a scalar objective value. In other words, intrinsic dimensions are not allowed in the Objective. If the Objective is not scalar, Analytica assumes the dimensions are extrinsic and performs independent optimizations for each scalar element in the Objective array. (For some optimization problems, the challenge is simply to find a solution that satisfies all constraints. This type of optimization has no objective at all.)</Tip>
Our goal is to minimize the total distribution cost. For each route, distribution cost is the Distribution Cost per Case multiplied by the Shipment Quantity for each route. The final objective is the sum for all routes:
 
Objective Total_dist_cost := Sum(Shipment_Quantity * Dist_per_case, Brewery, Market)
 
  
Summing over  Brewery and Market makes the objective a scalar value. This is a necessary condition for the optimization.
+
'''Supply Constraint'''
  
<Tip="Tip">Tip Every minimizing or maximizing optimization is based on a scalar objective value. In other words, intrinsic dimensions are not allowed in the Objective. If the Objective is not scalar, Analytica assumes the dimensions are extrinsic and performs independent optimizations for each scalar element in the Objective array. (For some optimization problems, the challenge is simply to find a solution that satisfies all constraints. This type of optimization has no objective at all.)</Tip>
+
The '''Supply Constraint''' ensures that shipment quantities from a single brewery to all available markets do not exceed the production limit for the brewery.  
  
==== Supply Constraint ====
+
The '''Production Limit''' array is already dimensioned by '''Brewery.''' Since this array is an input to '''Supply Constraint''', we expect '''Brewery''' to be a dimension of '''Supply Constraint''' as well, even though we don’t explicitly mention the index in the defining expression. This is the basic principle of array abstraction in Analytica.  
The Supply Constraint ensures that shipment quantities from a single brewery to all available markets do not exceed the production limit for the brewery.  
 
  
The Production Limit array is already dimensioned by Brewery. Since this array is an input to Supply Constraint, we expect Brewery to be a dimension of Supply Constraint as well, even though we don’t explicitly mention the index in the defining expression. This is the basic principle of array abstraction in Analytica.  
+
The '''Supply Constraint''' array actually defines five constraints; one for each '''Brewery'''.
  
The Supply Constraint array actually defines five constraints; one for each Brewery.
+
'''Set Brewery as an intrinsic index'''
  
==== Set Brewery as an intrinsic index ====
+
Is '''Brewery''' an intrinsic index for the '''Supply Constraint''' array? The answer is YES because we need to enforce the respective Supply Constraints on all breweries simultaneously. Make sure to include '''Brewery''' in the Intrinsic Indexes list for the '''Supply Constraint''' node.
Is Brewery an intrinsic index for the Supply Constraint array? The answer is YES because we need to enforce the respective Supply Constraints on all breweries simultaneously. Make sure to include Brewery in the Intrinsic Indexes list for the Supply Constraint node.
 
  
 +
<pre style="background:white; border:white; margin-left: 1em;">
 
Constraint Supply_constraint :=
 
Constraint Supply_constraint :=
Sum(Shipment_Quantity, Market)<=Production_Limits
+
    Sum(Shipment_Quantity, Market) <= Production_Limits
 +
 
 
Supply_constraint attribute Intrinsic Indexes := [Brewery]
 
Supply_constraint attribute Intrinsic Indexes := [Brewery]
 +
</pre>
  
Is Market an intrinsic index for the Supply Constraint? The answer is NO because Market is not a dimension of the array at all. The Sum() function eliminates it, leaving the array with only one dimension.
+
Is '''Market''' an intrinsic index for the '''Supply Constraint'''? The answer is NO because '''Market''' is not a dimension of the array at all. The [[Sum]]() function eliminates it, leaving the array with only one dimension.
  
==== Demand Constraint ====
+
'''Demand Constraint'''
The Demand Constraint ensures that each market region receives a total quantity from all breweries greater than or equal to the market demand. The input array Delivery Targets is dimensioned by Market, and therefore the Demand Constraint will also have this dimension.
 
The Demand Constraint array defines four constraints; one for each Market.
 
  
==== Set Market as an intrinsic index ====
+
The '''Demand Constraint''' ensures that each market region receives a total quantity from all breweries greater than or equal to the market demand. The input array '''Delivery Targets''' is dimensioned by ''Market'', and therefore the '''Demand Constraint''' will also have this dimension.
Market is an intrinsic index for the Demand Constraint because the solution should meet quotas for all markets. Make sure to include Market in the Intrinsic Indexes list for the Demand Constraint node.
 
  
 +
The '''Demand Constraint''' array defines four constraints; one for each '''Market.'''
 +
 +
'''Set Market as an intrinsic index'''
 +
 +
'''Market''' is an intrinsic index for the Demand Constraint because the solution should meet quotas for all markets. Make sure to include '''Market''' in the Intrinsic Indexes list for the '''Demand Constraint''' node.
 +
 +
<pre style="background:white; border:white; margin-left: 1em;">
 
Constraint Demand_constraint :=
 
Constraint Demand_constraint :=
Sum(Shipment_Quantity, Brewery) >= Delivery_Target
+
    Sum(Shipment_Quantity, Brewery) >= Delivery_Target
 
Demand_constraint attribute Intrinsic Indexes := [Market]
 
Demand_constraint attribute Intrinsic Indexes := [Market]
 +
</pre>
  
The Sum() function eliminates Brewery from the array.
+
The [[Sum]]() function eliminates '''Brewery''' from the array.
  
==== Optimization Node ====
+
'''Optimization Node'''
Remembering required attributes of the DefineOptimization() function as described in Chapter 1, we need to identify Decisions, Constraints, and the Objective to be minimized/maximized.
+
 
 +
Remembering required attributes of the [[DefineOptimization]]() function as described in the [[Quick Start]], we need to identify Decisions, Constraints, and the Objective to be minimized/maximized.
 +
<pre style="background:white; border:white; margin-left: 1em;">
 
Variable Optimization := DefineOptimization
 
Variable Optimization := DefineOptimization
(Decision:Shipment_Quantity,
+
    (Decision: Shipment_Quantity,
Constraints:Supply_Constraint, Demand_Constraint,
+
    Constraints: Supply_Constraint, Demand_Constraint,
Minimize: Total_Dist_Cost)
+
    Minimize: Total_Dist_Cost)
 +
</pre>
 +
'''Solution Node'''
  
==== Solution Node ====
+
We obtain the solution using the [[OptSolution]]() function. The first parameter identifies the optimization node. The second parameter (optional) identifies a specific Decision for which the solution should be represented.
We obtain the solution using the OptSolution() function. The first parameter identifies the optimization node. The second parameter (optional) identifies a specific Decision for which the solution should be represented.
 
  
 +
<pre style="background:white; border:white; margin-left: 1em;">
 
Decision Optimized_Solution :=
 
Decision Optimized_Solution :=
OptSolution(Optimization, Shipment_Quantity)
+
    OptSolution(Optimization, Shipment_Quantity)
 +
</pre>
 +
'''Optimized Objective'''
  
==== Optimized Objective ====
+
The [[OptObjective]]() function calculates the minimized or maximized quantity. In this case, it represents the total distribution cost.
The OptObjective() function calculates the minimized or maximized quantity. In this case, it represents the total distribution cost.
+
:<code>Variable Optimized_Objective := OptObjective(Optimization)</code>
  
Variable Optimized_Objective := OptObjective(Optimization)
+
'''Status'''
  
==== Status ====
 
 
Status text will confirm that the optimizer has found a solution
 
Status text will confirm that the optimizer has found a solution
 +
:<code>Variable Status := OptStatusText(Optimization)</code>
  
Variable Status := OptStatusText(Optimization)
+
:[[File:4-7.png|400px]]
  
[[File:4-7.png|400px]]
+
==Verifying the Optimization Setup==
 +
'''Evaluate the Optimization node'''
  
===Verifying the Optimization Setup===
+
It is always a good idea to evaluate the Optimization node to confirm that the optimization is interpreting your problem as intended. The [[DefineOptimization]]() function evaluates as a special symbol, or array of symbols, indicating the type of optimization problem presented. In this case, '''«LP»''' confirms that this is a Linear Program as expected. Furthermore, the result shows only a single '''«LP»''' symbol. This confirms that the solution is the result of a single optimization run.
  
====Evaluate the Optimization node====
+
'''Evaluate Status'''
  
It is always a good idea to evaluate the Optimization node to confirm that the optimization is interpreting your problem as intended. The DefineOptimization() function evaluates as a special symbol, or array of symbols, indicating the type of optimization problem presented. In this case, «LP» confirms that this is a Linear Program as expected. Furthermore, the result shows only a single «LP» symbol. This confirms that the solution is the result of a single optimization run.  
+
The [[OptStatusText]]() function confirms that the optimizer has found a feasible solution satisfying all constraints.
  
====Evaluate Status ====
+
==Checking the Result==
 +
'''Optimized Solution as an Array'''
  
The OptStatusText() function confirms that the optimizer has found a feasible solution satisfying all constraints.
+
Evaluate the Optimized Solution array to check the final result.
 
 
===Checking the Result===
 
  
====Optimized Solution as an Array====
+
:[[File:4-9.png|400px]]
  
Evaluate the Optimized Solution array to check the final result.
+
In this example, we used the optional second parameter of the [[OptSolution]]() function to reference the '''Shipment Quantities''' array. This formats the output to match the same dimensions as the Decision input array. It is a two-dimensional table indexed by '''Market''' and '''Brewery.'''
  
[[File:4-9.png|400px]]
+
'''Optimized Solution as a List'''
  
In this example we used the optional second parameter of the OptSolution() function to reference the Shipment Quantities array. This formats the output to match the same dimensions as the Decision input array. It is a two-dimensional table indexed by Market and Brewery.
+
If you omit the second parameter of [[OptSolution]](), Analytica creates a local index called <tt>.DecisionVector</tt> and presents the result as a one-dimensional array. You can experiment with this output format by removing the second parameter from the [[OptSolution]]() function.  
 +
:<code>Variable Optimized_solution := OptSolution(Optimization)</code>
  
====Optimized Solution as a List====
+
:[[File:4-10.png|400px]][[File:4-10.png|400px]]
  
If you omit the second parameter of OptSolution(), Analytica creates a local index called DecisionVector and presents the result as a one-dimensional array. You can experiment with this output format by removing the second parameter from the OptSolution() function.
+
==Summary: Basic Beer Distribution LP==
  
Variable Optimized_solution := OptSolution(Optimization)
+
The basic beer distribution example demonstrates a simple Linear Program with a two-dimensional decision array. There are two one-dimensional Constraint arrays, each over a different index. The model has only two indexes overall: '''Brewery''' and '''Market'''. Both indexes are intrinsic to the optimization. The example does not include any extrinsic indexes.
  
[[File:4-10.png|400px]][[File:4-10.png|400px]]
+
==See Also==
 +
* [[DefineOptimization]]
 +
* [[OptObjective]]
 +
* [[OptSolution]]
 +
* [[Table]]
 +
* [[Sum]]
 +
* [[Index..Do]]
  
===Summary: Basic Beer Distribution LP===
 
  
The basic beer distribution example demonstrates a simple Linear Program with a twodimensional decision array. There are two one-dimensional Constraint arrays, each over a different index. The model has only two indexes overall: Brewery and Market. Both indexes are intrinsic to the optimization. The example does not include any extrinsic indexes.
+
<footer> Arrays in Optimization Models and Array Abstraction / {{PAGENAME}} / Example 2: Beer Distribution with Added Scenario</footer>

Latest revision as of 17:44, 24 May 2016



We start with an adaptation of a classic Linear Programming (LP) example.

Model Description

A large brewing company operates five breweries nationwide. Each brewery distributes product among four regions. Routes include all combinations of Breweries and Market regions. The challenge is to find the shipping pattern that minimizes distribution cost while

  1. meeting demand in each region, and
  2. observing production limits at each brewery.


We assume that distribution cost per case of beer is proportional to the distance between the brewery and the region.

Setting up the Model

To explore and follow this example in Analytica, run the Beer Distribution LP1.ana model in the Optimizer Examples folder.

Brewery and Market (indexes)

There are five Breweries and four Market regions:

Index Brewery := ['Fairfield', 'Fort Collins', 'Jacksonville', 'Merrimack', 'St Louis'] 
Index Market := ['North', 'South', 'East', 'West']

Distance (input array)

Distance between breweries and markets is represented as a table dimensioned by Brewery and Market. Units are thousands of miles:

Variable Distance := 
      Table(Brewery, Market)(1.8, 2.2, 3.4, 0.1, 0.3,1.2, 2.4, 1, 2.9,1.8, 0.6, 3.3, 1.2, 2.1, 0.2, 3.5, 0.5, 1.1, 0.8, 2.5)
4-3.png

Freight Price (input scalar value)

Freight Price is a simple scalar value of $5 per 1,000 miles per case of beer.

Variable Freight_price := 5

Production Limits (input array)

Production Limits indicate maximum capacity for each brewery in cases of beer:

Variable Production_limits := Table(Brewery)(600K, 250K, 450K, 300K, 240K)
4-4.png

Delivery Targets (input array)

Delivery Targets indicate the minimum quota that each Market region must receive:

Variable Delivery_target := Table(Market)(240K, 280K, 700K, 500K)
4-5.png

Distribution Cost (intermediate array)

Distribution Cost per Case is Freight Price multiplied by Distance:

Variable Dist_per_case := Freight_price*Distance

Shipment Quantities (input decision array)

The input decision array represents Shipment Quantities from each brewery to each region. It is a two-dimensional array indexed by Brewery and Market. The non-optimized values are not used anywhere else in the model so we can simply insert 1 as a dummy value across the array.(Initial guesses do not apply since this is a Linear Program.)

Units are cases of beer.

Staying Positive

We set the Lower Bound attribute to zero to disallow negative shipping values, along with the undesirable implication of turning perfectly good beer back into barley and hops.

Set Brewery and Market as intrinsic indexes

Finally and perhaps most importantly, we consider the index status for this array. The optimized solution should be in the same form as this table. It should also be integrated such that every array element has simultaneous influence over all other elements. Brewery and Market are both intrinsic indexes in this case.

Decision Shipment_Quantity := Array([Brewery, Market], 1)
Shipment_Quantity attribute Lower Bound := 0
Shipment_Quantity attribute Intrinsic Indexes := [Brewery, Market]
4-6.png

Total Distribution (Objective)

Our goal is to minimize the total distribution cost. For each route, distribution cost is the Distribution Cost per Case multiplied by the Shipment Quantity for each route. The final objective is the sum for all routes:

Objective Total_dist_cost := 
      Sum(Shipment_Quantity*Dist_per_case, Brewery, Market)

Summing over Brewery and Market makes the objective a scalar value. This is a necessary condition for the optimization.

Tip
Tip Every minimizing or maximizing optimization is based on a scalar objective value. In other words, intrinsic dimensions are not allowed in the Objective. If the Objective is not scalar, Analytica assumes the dimensions are extrinsic and performs independent optimizations for each scalar element in the Objective array. (For some optimization problems, the challenge is simply to find a solution that satisfies all constraints. This type of optimization has no objective at all.)

Supply Constraint

The Supply Constraint ensures that shipment quantities from a single brewery to all available markets do not exceed the production limit for the brewery.

The Production Limit array is already dimensioned by Brewery. Since this array is an input to Supply Constraint, we expect Brewery to be a dimension of Supply Constraint as well, even though we don’t explicitly mention the index in the defining expression. This is the basic principle of array abstraction in Analytica.

The Supply Constraint array actually defines five constraints; one for each Brewery.

Set Brewery as an intrinsic index

Is Brewery an intrinsic index for the Supply Constraint array? The answer is YES because we need to enforce the respective Supply Constraints on all breweries simultaneously. Make sure to include Brewery in the Intrinsic Indexes list for the Supply Constraint node.

Constraint Supply_constraint :=
     Sum(Shipment_Quantity, Market) <= Production_Limits

Supply_constraint attribute Intrinsic Indexes := [Brewery]

Is Market an intrinsic index for the Supply Constraint? The answer is NO because Market is not a dimension of the array at all. The Sum() function eliminates it, leaving the array with only one dimension.

Demand Constraint

The Demand Constraint ensures that each market region receives a total quantity from all breweries greater than or equal to the market demand. The input array Delivery Targets is dimensioned by Market, and therefore the Demand Constraint will also have this dimension.

The Demand Constraint array defines four constraints; one for each Market.

Set Market as an intrinsic index

Market is an intrinsic index for the Demand Constraint because the solution should meet quotas for all markets. Make sure to include Market in the Intrinsic Indexes list for the Demand Constraint node.

Constraint Demand_constraint :=
     Sum(Shipment_Quantity, Brewery) >= Delivery_Target
Demand_constraint attribute Intrinsic Indexes := [Market]

The Sum() function eliminates Brewery from the array.

Optimization Node

Remembering required attributes of the DefineOptimization() function as described in the Quick Start, we need to identify Decisions, Constraints, and the Objective to be minimized/maximized.

Variable Optimization := DefineOptimization
    (Decision: Shipment_Quantity,
    Constraints: Supply_Constraint, Demand_Constraint,
    Minimize: Total_Dist_Cost)

Solution Node

We obtain the solution using the OptSolution() function. The first parameter identifies the optimization node. The second parameter (optional) identifies a specific Decision for which the solution should be represented.

Decision Optimized_Solution :=
     OptSolution(Optimization, Shipment_Quantity)

Optimized Objective

The OptObjective() function calculates the minimized or maximized quantity. In this case, it represents the total distribution cost.

Variable Optimized_Objective := OptObjective(Optimization)

Status

Status text will confirm that the optimizer has found a solution

Variable Status := OptStatusText(Optimization)
4-7.png

Verifying the Optimization Setup

Evaluate the Optimization node

It is always a good idea to evaluate the Optimization node to confirm that the optimization is interpreting your problem as intended. The DefineOptimization() function evaluates as a special symbol, or array of symbols, indicating the type of optimization problem presented. In this case, «LP» confirms that this is a Linear Program as expected. Furthermore, the result shows only a single «LP» symbol. This confirms that the solution is the result of a single optimization run.

Evaluate Status

The OptStatusText() function confirms that the optimizer has found a feasible solution satisfying all constraints.

Checking the Result

Optimized Solution as an Array

Evaluate the Optimized Solution array to check the final result.

4-9.png

In this example, we used the optional second parameter of the OptSolution() function to reference the Shipment Quantities array. This formats the output to match the same dimensions as the Decision input array. It is a two-dimensional table indexed by Market and Brewery.

Optimized Solution as a List

If you omit the second parameter of OptSolution(), Analytica creates a local index called .DecisionVector and presents the result as a one-dimensional array. You can experiment with this output format by removing the second parameter from the OptSolution() function.

Variable Optimized_solution := OptSolution(Optimization)
4-10.png4-10.png

Summary: Basic Beer Distribution LP

The basic beer distribution example demonstrates a simple Linear Program with a two-dimensional decision array. There are two one-dimensional Constraint arrays, each over a different index. The model has only two indexes overall: Brewery and Market. Both indexes are intrinsic to the optimization. The example does not include any extrinsic indexes.

See Also


Comments


You are not allowed to post comments.