C# Linear Programming Example

[TOC]

using System;

using CenterSpace.NMath.Core;
using CenterSpace.NMath.Analysis;

namespace CenterSpace.NMath.Analysis.Examples.CSharp
{
  class LinearProgrammingExample
  {
    /// <summary>
    /// A .NET example in C# showing how to solve a linear system using linear programming and
    /// the simplex method.
    /// </summary>
    static void Main(string[] args)
    {
      Console.WriteLine();

      // A farmer has 640 acres of farmland. It can be planted with wheat, barley, corn or a
      // combination of the three. The farmer wishes to maximize his profit subject to the
      // limits on land, fertilizer, and water.

      // Currently, wheat is $3.38/bushel. The farmer can expect a yield of 55 bushels/acre.
      double wheatPrice = 3.38;
      double wheatYield = 55.0;
      double wheatRevenuePerAcre = wheatPrice * wheatYield;

      // Currently, barley is $1.98/bushel. The farmer can expect a yield of 75 bushels/acre.
      double barleyPrice = 1.98;
      double barleyYield = 75.0;
      double barleyRevenuePerAcre = barleyPrice * barleyYield;

      // Currently, corn is $1.70/bushel. The farmer can expect a yield of 110 bushels/acre.
      double cornPrice = 1.70;
      double cornYield = 110.0;
      double cornRevenuePerAcre = cornPrice * cornYield;

      // Therefore, the objective function is:
      Console.Write("Maximize " + wheatRevenuePerAcre + "w + ");
      Console.WriteLine(barleyRevenuePerAcre + "b + " + cornRevenuePerAcre + "c");
      Console.WriteLine("where");
      Console.WriteLine();

      DoubleVector revenue = new DoubleVector(wheatRevenuePerAcre, barleyRevenuePerAcre, cornRevenuePerAcre);

      // Make a matrix big enough for 5 constraints and 3 variables.
      DoubleMatrix constraints = new DoubleMatrix(5, 3);

      // Make a vector of right-hand sides.
      DoubleVector rightHandSides = new DoubleVector(constraints.Rows);

      // The farmer has 8,000 lbs of nitrogen fertilizer. It's known that wheat requires
      // 12 lb/acre, barley 5 lb/acre and corn 22 lb/acre.
      Console.WriteLine("12w + 5b + 22c <= 8000");
      constraints[0, Slice.All] = new DoubleVector(12.0, 5.0, 22.0);
      rightHandSides[0] = 8000.0;

      // The farmer has 22,000 lbs of phosphate fertilizer. It's known that wheat requires
      // 30 lb/acre, barley 8 lb/acre and corn 50 lb/acre.
      Console.WriteLine("30w + 8b + 50c <= 22000");
      constraints[1, Slice.All] = new DoubleVector(30.0, 8.0, 50.0);
      rightHandSides[1] = 22000.0;

      // The farmer has a permit for 1,000 acre-feet of water. Wheat requires 1.5 ft of water, 
      // barley requires 0.7 and corn 2.2.
      Console.WriteLine("1.5w + 0.7b + 2.2c <= 1200");
      constraints[2, Slice.All] = new DoubleVector(1.5, 0.7, 2.2);
      rightHandSides[2] = 1200.0;

      // The farmer has a maximum of 640 acres for planting.
      Console.WriteLine("w + b + c <= 640");
      constraints[3, Slice.All] = new DoubleVector(1.0, 1.0, 1.0);
      rightHandSides[3] = 640.0;

      // Create an LP solver with an error tolerance of 0.001.
      SimplexLPSolver solver = new SimplexLPSolver(0.001);

      // Solve
      solver.Solve(revenue, constraints, rightHandSides, 5, 0, 0);

      // Was a finite solution found?
      Console.WriteLine();
      if (solver.IsGood)
      {
        Console.WriteLine("solution: " + solver.Solution.ToString("f0"));
        Console.WriteLine();
        Console.WriteLine("optimal value: " + solver.OptimalValue.ToString("f0"));
      }
      Console.WriteLine();

      // Let's say the farmer is also contractually obligated to farm at least 50 acres
      // of barley.
      Console.WriteLine("Add variable bound: b >= 10");
      DoubleVector lowerBounds = new DoubleVector(0.0, 10.0, 0.0);
      DoubleVector upperBounds = new DoubleVector(640.0, 640.0, 640.0);

      // Solve again
      solver.Solve(revenue, constraints, rightHandSides, 5, 0, 0, lowerBounds, upperBounds);

      // Good?
      Console.WriteLine();
      if (solver.IsGood)
      {
        Console.WriteLine("solution: " + solver.Solution.ToString("f0"));
        Console.WriteLine();
        Console.WriteLine("optimal value: " + solver.OptimalValue.ToString("f0"));
      }

      Console.WriteLine();

      Console.WriteLine();
      Console.WriteLine("Press Enter Key");
      Console.Read();

    }  // Main

  }  // class

} // namespace

[TOC]