.Net coding guidelines for operations research

Writing code, whether in C++, AMPL, GAMS, SAS, .Net, or whatever*, is a part of operations research for most of us. Here are a few thoughts on writing good .Net code. This advice is aimed especially at optimizers with a research background, who don’t have lots of experience writing “production” code.

  • Give things sensible names. In particular, start with Guidelines for Names on MSDN. This guideline is actually pretty important, because good naming and organization leads to fewer bugs and more maintainable code. My experience working with code by “optimization people” is that a lot of it is poorly organized. You’d never write a poorly organized paper (would you?) so why write disorganized code. The first step in good organization is to use good names. (Tip: In Visual Studio Use the F2 key (or right click and “Rename”) instead of find/replace.)
  • Exception: math code can and should use good math notation. Code that implements an optimization model should have a backing whitepaper. The whitepaper should include the full mathematical formulation of the problem. It should be possible to go back and forth between the documentation and code without too much trouble. So if in your doc you have a variable x with subscripts p, g, and a, then it is totally okay for the code to have the same names. Don’t artificially name x something like “amountToProduce” just to satisfy some MSDN guideline. For this reason I tend to avoid Greek letters, hats, and bars in my whitepapers. Careful choice of notation is important.
  • Get in the habit of writing small programs to test your assumptions. Are multidimensional arrays or jagged arrays faster in .Net? How much more expensive is a hashtable lookup than an array lookup? Is it better to use SOS2 constraints or dummy integer variables for piecewise linear constraints? How much memory does a solver use for a model? These things can be empirically tested.
  • Write tests for your code. In my experience, any code that does not have tests is probably wrong. Start with very simple tests that test basic, but important things.
  • Document your code. Help others understand what you are doing (and more importantly) why.
  • Public APIs should be designed for the person using it, not the person writing it. For example, an input data structure for a production planning module might talk about capacities, facilities, and availability. Constraints, knots, and duals wouldn’t make much sense to a user, even though they make perfect sense to us.
  • Consider refactoring any function over a page long. It is probably too confusing. You can highlight a section of code, right click, and do “Extract Function” in Visual Studio.
  • If you don’t understand the performance characteristics of a data structure, avoid using it until you do. The .Net framework provides TONS of built in methods and data structures. This makes it very, very easy to write correct but horribly inefficient code. For example, finding an element in List<> takes linear time, but accessing an element by key from a Dictionary<> is nearly constant time. The Count() method on an IEnumerable<> is linear time, but .Length on an array is constant time. Most of the time, arrays are great for what we do. It’s okay to use more, just understand why.
  • Package complicated data in data structures. A small caveat to the last point: optimization people tend to go crazy with multidimensional arrays when an array of simple data structure is usually more appropriate. This results in self-documenting code.
  • Be careful with memory. Just because .Net has garbage collection doesn’t mean you can forget about how you manage memory. Don’t unnecessarily allocate arrays inside a loop if you don’t need to. If you are careless with memory, it will kill your performance.
  • Don’t reinvent the wheel. You don’t need to write any sorting code – use Array.Sort. You don’t need to scan through strings for commas – use String.Split. You don’t need to write 3.14159 – use Math.PI.

The Design Guidelines for Developing Class Libraries page on MSDN is filled with lots of good suggestions.

* I think F# and other functional programming languages could actually be great for optimization. I guess that’s why Python is catching on.

Advertisements

Getting solution values using Solver Foundation Services

Please note that Solver Foundation is no longer supported.

There was a question on the Solver Foundation forum about iterating through the results in a Decision. Here’s a code sample of how to do it in two simple cases.

Decision objects are either indexed or scalar. A decision with one index set is essentially a vector, two means matrix. You supply the Sets in the Decision constructor. In the code below, x is an indexed decision. If you don’t supply any sets then you have a non-indexed scalar Decision – that’s what we’re doing with y.

Once you solve the model you can use two different methods to pull out the results. The GetValues method returns an array: one for each value in an indexed decision. In this case, we have one index set that has 10 values, so GetValues will return 10 items. Each item is an array. The first element in the array is the value for the decision for the specific index. The remaining entries are the index values themselves. By running the program below you will get the idea.

Getting the values for non-indexed decisions is easy: just call the GetDouble method.

Here’s the code:

using System;
using System.Linq;
using Microsoft.SolverFoundation.Services;

namespace DecisionTest {
  class Program {
    static void Main(string[] args) {
      SolverContext context = SolverContext.GetContext();
      Model model = context.CreateModel();
      // Let's create an indexed parameter.
      Set s = new Set(Domain.Real, "s");
      Parameter p = new Parameter(Domain.Real, "p", s);
      // Here's some dummy data.
      var input = Enumerable.Range(1, 10).Select(item => new { Id = item, Value = item });
      p.SetBinding(input, "Value", "Id");
      model.AddParameter(p);

      // Let's create an indexed decision.
      Decision x = new Decision(Domain.Real, "x", s);
      model.AddDecision(x);

      // Here's a scalar decision.
      Decision y = new Decision(Domain.Real, "y");
      model.AddDecision(y);

      // Here are some dummy constraints to tie everything together. Just for fun.
      model.AddConstraint("c1", Model.ForEach(s, i => p[i] == x[i]));
      model.AddConstraint("c2", Model.Sum(Model.ForEach(s, i => x[i])) == y);

      // Extract data from the indexed decision.
      context.Solve();
      foreach (object[] value in x.GetValues()) {
        Console.WriteLine("x[{0}] = {1}", value[1], value[0]);
      }
      // Extract data from the scalar decision.
      Console.WriteLine("y = {0}", y.GetDouble());
    }
  }
}

Converting an Access DB to XML using C#

I recently needed to import an Access database into a C# program for a sample that I will be blogging about soon. My objective was to convert the data into a more convenient form for use with my “real” application. Nothing here will be very cutting edge! A quick and dirty way to get the job done seemed to be to read the data into a DataSet and export it to XML. Access MDB files can be read using the Jet OLDB provider with OleDbConnection. Once the connection is established, the GetOleDbSchemaTable method can be used to get the table names. Then each table can be read using a select. Writing the data out to XML is easy using the built-in DataSet.WriteToXml() method. I also write out the schema file so that the columns will have the correct types when I read the data back in.

One last hitch: in .Net 4/VS2010 the OLEDB component works only with a 32-bit build. So change the Platform target in the Project properties as follows:

AccessToDataSet

Here’s the code. I’ve made even less of an effort than usual to make the code “production quality”, but note that a couple of the classes I use are IDisposable so I’m taking care to wrap them in a “using” block.

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.Linq;
using System.Text;

// None of this is foolproof...caveat emptor.
namespace AccessToDataSet {
  class Program {
    static void Main(string[] args) {
      if (args.Length == 0 || !args[0].EndsWith(".mdb", StringComparison.InvariantCultureIgnoreCase)) {
        Console.WriteLine("Please specify the path to an MDB file.");
        return;
      }

      DataSet dataSet = new DataSet();
      using (var conn = new OleDbConnection(@"Provider=Microsoft.JET.OLEDB.4.0;" + @"data source=" + args[0])) {
        conn.Open();
        // Retrieve the schema
        DataTable schemaTable = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
        // Fill the DataTables.
        foreach (DataRow dataTableRow in schemaTable.Rows) {
          string tableName = dataTableRow["Table_Name"].ToString();
          // I seem to get an extra table starting with ~. I can't seem to screen it out based on information in schemaTable,
          // hence this hacky check.
          if (!tableName.StartsWith("~", StringComparison.InvariantCultureIgnoreCase)) {
            FillTable(dataSet, conn, tableName);
          }
        }
      }

      string name = args[0].ToLowerInvariant();
      dataSet.WriteXmlSchema(name.Replace(".mdb", ".schema.xml"));
      dataSet.WriteXml(name.Replace(".mdb", ".xml"));
    }

    private static void FillTable(DataSet dataSet, OleDbConnection conn, string tableName) {
      DataTable dataTable = dataSet.Tables.Add(tableName);
      using (OleDbCommand readRows = new OleDbCommand("SELECT * from " + tableName, conn)) {
        OleDbDataAdapter adapter = new OleDbDataAdapter(readRows);
        adapter.Fill(dataTable);
      }
    }
  }
}

Which is faster: Regex.IsMatch or String.Contains?

On an internal message board here at work somebody asked:

Is there any difference in speed/memory usage for these two equivalent expressions:

Regex.IsMatch(Message, "1000");
Message.Contains("1000");

My guess is that Message.Contains() is faster because it likely involves less machinery. Let’s try it and see.

using System;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;

namespace TryItAndSee {
  class Program {
    static void Main(string[] args) {
      string message = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "
      + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in"
      + " reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt"
      + " in culpa qui officia deserunt mollit anim id est laborum.";
      Stopwatch s = new Stopwatch();
      int trials = 1000000;
      
      s.Start();
      for (int i = 0; i < trials; i++) {
        bool isMatch = Regex.IsMatch(message, "nulla");
      }
      s.Stop();
      Console.WriteLine("regex = " + s.Elapsed);
      
      s.Reset();
      s.Start();
      for (int i = 0; i < trials; i++) {
        bool isMatch = message.Contains("nulla");
      }
      s.Stop();
      Console.WriteLine("contains = " + s.Elapsed);
    }
  }
}

The output appears to confirm my guess, at least on this input:

regex    = 00:00:01.2446435
contains = 00:00:00.5458883

UPDATE:

Niels Kuhnel reports the following:

Sure. But if you’re using RegexOptions.Compiled then IsMatch is actually faster.

Try putting:

Regex nulla = new Regex("nulla", RegexOptions.Compiled);

// Normally we have a static Regex so it isn't fair to time the initialization 
// (although it doesn't make a difference in this case)
s.Start(); 
for (int i = 0; i < trials; i++) {
 bool isMatch = nulla.IsMatch(message);
}

I got:

regex = 00:00:00.6902234

contains = 00:00:00.8815885

(during 10 trials it was consistently faster)

Lesson must be that if you’re searching for the same thing a lot, the dynamically compiled state machine provided by RegexOptions.Compiled is actually faster. Even if just searching for a simple string.”

Writing high performance code

During Scott Hanselman’s podcast we briefly discussed managed code performance.  Here are a few of my thoughts about writing high performance code. In the spirit of a cheesy business book (or motivational speaker), I will give away my main points in the form of controversial-sounding statements before proceeding to flog them to death:

    • Don’t trust anyone.
    • Managed is better.

Some background: before I came to Microsoft I built solvers for both discrete and continuous optimization problems, primarily in C/C++, with a bit of Fortran thrown in.  Back in 2002 when I was on the Project Server team we were faced with the decision of whether to rebuild our scheduling engine in C++ or C#.  For the past year or so I have worked on the Solver Foundation team, which is pure C#.  We build solvers that solve a range of large-scale optimization problems, and they are “industrial grade”:  tens or hundreds of thousands of constraints are not uncommon.

Don’t trust anyone.  Rico Mariani says the first rule of performance is to measure.  Listen to Rico.  There are many reasons for this. The first is that nobody has ever written code that is doing exactly what you are trying to do.  Otherwise (being a smart programmer) you should just call their code or (being a smart business person) you should just buy their code, try to do it better, or do something different entirely (perhaps mixed martial arts).  So you should seek to understand how the code behaves, otherwise you will never find out – until it is too late.

The second is that you know your scenarios and priorities better than others do.  You should already have an idea of how fast the code is supposed to be. Now sometimes the requirement truly is “make it as fast as possible”.  For numerical libraries this is often the case because many problems can be made to be arbitrarily complicated.  For example, if you are modeling fluid dynamics you could use tighter meshes and get more accurate results.  In most other cases (perhaps in a user interface) you have a hard number you need to hit. Of course, there are some simple guidelines that may apply in most situations.  If you never go to the database, your server app will be fast. If you never allocate memory, your numeric code will fly. True or false? Well…measure.

The third is that even if someone else has measured code that seems to be similar to yours, their results may be misleading.  For example, you depend on different collection classes, or you are running on a different processor.  Or your input data is different in some subtle way.  To take a very simple example, suppose you want to sort lists of 1 million integers, and somebody says, “hey, I measured different sorting algorithms on arrays of 1 million integers and quicksort is best.”  And they hand over the code and all of their results.  Well, what do those arrays look like?  Because if the data is mostly sorted then something like insertion sort may work better.

If you follow this advice you may end up with more questions: doesn’t this take a lot of time and effort? How do I know when to stop measuring, or stop optimizing my code?  If you start profiling at the very start of development, and build some simple skills, it’s not too bad (and you learn a lot).  If, for example, you are considering whether to use managed or unmanaged code for a project, prototype a couple of key sections in C++ and C# and measure.  I did this on the Project Server team and that was the best way to settle the argument.  These things often get way too philosophical – just try it and see.  I did standard critical path scheduling in both C# and C++ and found that the C# version was only 10-15% slower.  We went with C# and in the course of development we were able to find algorithmic improvements that resulted in a faster implementation that the original C++ codebase. Get good at writing simple programs that answer one specific performance question.  For example: should I use a list or an array?  How should I read this data set?  Be a scientist and seek to answer specific questions by controlling the conditions and varying only one thing at a time.  And pick the right thing based on your knowledge of the customer scenario.

Managed or unmanaged? My blunt opinion is: unless your computation is dominated by BLAS-style computations you are better off using C# because of productivity, stability, and maintainability concerns.

Here are a couple of “pros” for C#:

  • There are clear performance differences, but in many cases when you look at the overall system performance they can be washed away due to other factors: I/O, a webservice call, DB access, etc.
  • Many programmers (myself included) are much more productive writing C# code.  This gives me more time to investigate possible algorithmic improvements, write good unit tests, etc. There are opportunity costs!
  • I think it is easier to make use of multiple cores. For example, the parallel extensions available for .Net 3.5 (and built into 4.0) are very easy to use.

There are also some clear downsides:

  • It is easy to get lazy, or to unintentionally use constructs that are not efficient.  People start using List<> and Dictionary<> when a good ol’ array will do.  It’s also easy to miss unnecessary memory allocations, because everything is garbage collected.  So you need to be vigilant about profiling the code.
  • There is a lot of unnecessary array bounds checking that slows things down.  In particular, with LAPACK-style routines with tight, nested loops.
  • As far as I know, the managed code compilers do not make use of SSE2 instructions.

Others have different opinions and I’m not saying they’re wrong – so long as they have measured.  Otherwise they are bullshitting you.

Solving traveling salesman problems using Solver Foundation

Update: see the comments below for some helpful hints. If you are unable to run this with your version of Solver Foundation and Gurobi, consider installing the lp_solve plugin for MSF. More details on this thread.

Here’s an example that I walked through during yesterday’s INFORMS session.  Erwin has two blog postings about Solver Foundation and the traveling salesman problem, but I want to throw in my two cents because I want to emphasize a couple of points:

  1. By combining C# and Solver Foundation Services it is possible to express complex models clearly and succinctly.
  2. It is very easy to build powerful, reusable model libraries using C# and Solver Foundation Services.
  3. Solver Foundation Services code can be used in many different application environments (ASP.Net, silverlight, DB, command line apps, WPF, …) with minimal changes.

The traveling salesman problem is a classical problem in computer science, and you should bow your head in shame if you don’t know about it (and turn in your conference badge if you happen to be in Phoenix). William Cook’s book on the traveling salesman problem is a wonderful read. A salesperson needs to make a tour of a number of cities.  The restrictions are that she wants to visit each city once and only once, and she wants to minimize the distance travelled.  This is perhaps the definitive example of an NP-hard problem.

TSP can be solved using mixed integer programming – optimizing a linear goal with linear constraints, where some of the decision variables are integer.  In this first post I will show how to formulate and solve a TSP model using Solver Foundation Services.  In my second post I will show how to use the Gurobi MIP solver using SFS.   There are many different ways to model the TSP – here is a nice introduction.  My goal is to provide a clear, complete example – not build a “production level” TSP model, so I am going to choose a model formulation that dates back to 1960!  First, I need to establish a couple of building blocks that will help me construct the data for the model.  We need to know the distances between each pair of cities.  Typically we are provided the coordinates of the cities and need to derive the distances.  So I will introduce a Coordinate class that contains properties for the (x, y) coordinates, and properties to convert to latitude and longitude.  Finally, a method that computes the distance between points.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SolverFoundation.Services;

namespace Microsoft.SolverFoundation.Samples {
  class TravelingSalesman {
    // TSP coordinate.
    public class Coordinate {
      public int Name { get; set; }

      // X-coordinate (from TSPLIB)
      public double X { get; set; }

      // Y-coordinate (from TSPLIB)
      public double Y { get; set; }

      public Coordinate(int name, double x, double y) {
        Name = name;
        X = x;
        Y = y;
      }

      // Latitude in radians.
      public double Latitude {
        get { return Math.PI * (Math.Truncate(X) + 5 * (X - Math.Truncate(X)) / 3) / 180; }
      }

      // Longitude in radians.
      public double Longitude {
        get { return Math.PI * (Math.Truncate(Y) + 5 * (Y - Math.Truncate(Y)) / 3) / 180; }
      }

      // Geographic distance between two points (as an integer).
      public int Distance(Coordinate p) {
        double q1 = Math.Cos(Longitude - p.Longitude);
        double q2 = Math.Cos(Latitude - p.Latitude);
        double q3 = Math.Cos(Latitude + p.Latitude);
        // There may rounding difficulties her if the points are close together...just sayin'.
        return (int)(6378.388 * Math.Acos(0.5 * ((1 + q1) * q2 - (1 - q1) * q3)) + 1);
      }
    }

    // TSP city-city arc.
    public class Arc {
      public int City1 { get; set; }
      public int City2 { get; set; }
      public double Distance { get; set; }
    }

    // Burma14 from TSPLIB. Optimal tour = 3323.
    private static Coordinate[] data = new Coordinate[] {
      new Coordinate(0, 16.47, 96.10),
      new Coordinate(1, 16.47, 94.44),
      new Coordinate(2, 20.09, 92.54),
      new Coordinate(3, 22.39, 93.37),
      new Coordinate(4, 25.23, 97.24),
      new Coordinate(5, 22.00, 96.05),
      new Coordinate(6, 20.47, 97.02),
      new Coordinate(7, 17.20, 96.29),
      new Coordinate(8, 16.30, 97.38),
      new Coordinate(9, 14.05, 98.12),
      new Coordinate(10, 16.53, 97.38),
      new Coordinate(11, 21.52, 95.59),
      new Coordinate(12, 19.41, 97.13),
      new Coordinate(13, 20.09, 94.55)
    };
}

(The data for this 14-city problem comes from the TSPLIB library). If you’ve been following my blog you know that the building blocks of a Solver Foundation model are: sets, parameters, decisions, goals, and constraints. I am going to implement a simple formulation that is centered around the following (indexed) decisions:

  • Assign[i,j]: this is equal to 1 if the optimal tour contains a trip (or arc) from city i to city j.
  • Rank[i]: this is equal to the number of cities visited after arriving at city i.

We have one parameter in our model:

  • Distance[I,j]: the distance from city i to city j.

With that in mind, here’s the model.  Explanation of the goals and constraints follow.

    
public static void Run() {
      SolverContext context = SolverContext.GetContext();
      context.ClearModel();
      Model model = context.CreateModel();

      // ------------
      // Parameters
      Set city = new Set(Domain.IntegerNonnegative, "city");
      Parameter dist = new Parameter(Domain.Real, "dist", city, city);
      var arcs = from p1 in data
                 from p2 in data
                 select new Arc { City1 = p1.Name, City2 = p2.Name, Distance = p1.Distance(p2) };
      dist.SetBinding(arcs, "Distance", "City1", "City2");
      model.AddParameters(dist);

      // ------------
      // Decisions
      Decision assign = new Decision(Domain.IntegerRange(0, 1), "assign", city, city);
      Decision rank = new Decision(Domain.RealNonnegative, "rank", city);
      model.AddDecisions(assign, rank);

      // ------------
      // Goal: minimize the length of the tour.
      Goal goal = model.AddGoal("TourLength", GoalKind.Minimize,
        Model.Sum(Model.ForEach(city, i => Model.ForEachWhere(city, j => dist[i, j] * assign[i, j], j => i != j))));

      // ------------
      // Enter and leave each city only once.
      int N = data.Length;
      model.AddConstraint("assign1",
        Model.ForEach(city, i => Model.Sum(Model.ForEachWhere(city, j => assign[i, j],
          j => i != j)) == 1));
      model.AddConstraint("assign2",
        Model.ForEach(city, j => Model.Sum(Model.ForEachWhere(city, i => assign[i, j], i => i != j)) == 1));

      model.AddConstraint("A1", Model.ForEach(city, i => Model.Sum(Model.ForEachWhere(city, j => assign[i, j], j => i != j)) == 1));
      model.AddConstraint("A2", Model.ForEach(city, j => Model.Sum(Model.ForEachWhere(city, i => assign[i, j], i => i != j)) == 1));

      // Forbid subtours (Miller, Tucker, Zemlin - 1960...)
      model.AddConstraint("nosubtours",
        Model.ForEach(city,
          i => Model.ForEachWhere(city,
            j => rank[i] + 1 <= rank[j] + N * (1 - assign[i, j]),
            j => Model.And(i != j, i >= 1, j >= 1)
          )
        )
      );

      Solution solution = context.Solve();

      // Retrieve solution information.
      Console.WriteLine("Cost = {0}", goal.ToDouble());
      Console.WriteLine("Tour:");
      var tour = from p in assign.GetValues() where (double)p[0] > 0.9 select p[2];
      foreach (var i in tour.ToArray()) {
        Console.Write(i + " -> ");
      }
      Console.WriteLine();
    }

In my humble opinion, the “Parameter data =” line is an awesome example of the power of LINQ data binding in Solver Foundation.  We generate the 2D matrix of distances using a single LINQ expression. It would be incredibly easy to change the code to retrieve the coordinate data from a database (perhaps using a LINQ expression once again), a file, or even a user application.

The goal is straightforward: minimize the distance traveled.  This is a product of the selected arcs and the distance matrix.   We have two types of constraints:

  • Assignment constraints: these ensure that we enter and leave each city only once.
  • Subtour constraints: these ensure that we do not have any subtours. In a four city problem {A, B, C, D}, for example, we cannot have two cycles (A, B), (C, D). We need to have one tour that contains all the cities.

The assignment constraints are easy using the ForEach and ForEachWhere operations.  I use ForEachWhere because I want to disallow arcs that enter and leave the same city – that doesn’t make sense.  The subtour constraint is a little more complicated. It relates the “assign” and “rank” decisions. The key fact is that if there is an arc from city i to city j, rank[i] + 1 == j. Of course, if the (i, j) arc is not part of the optimal tour then all bets are off. Last note: notice that I can mix parameters, decisions, and C# variables in my expressions.

Getting the cost is very easy using goal.ToDouble().  We can get the tour using either Assign or Rank.  I have chosen to use Assign because it gives me another opportunity to use LINQ.  When you call GetValues() on a decision, you get arrays that contain the value along with the indexes for each decision.  In this case, the last entry in the array is the one we are interested in. There are other ways to conveniently query decsision results, I’ll save that for another time.

The next post will show how we can use Solver Foundation’s plug-in model to tune the behavior of the Gurobi MIP solver.

Two way data binding using LINQ and Solver Foundation Services

Recently on the Microsoft Solver Foundation discussion boards there was a question about two-way data binding and Solver Foundation Services.  The MSF-SFS Programming Primer has plenty of examples for helping you learn to use Solver Foundation Services in your .Net applications.  Sample 5 is about binding output values – user “detond” from our discussion boards extended the example to go against a SQL DB, and I have cleaned up the code.  A few notes:

    1. You’ll need to create a table named “ProductionCapacity” with nvarchar(max) Country, int MaxProduction, float Output columns.
    2. Create rows for Venezuela and SaudiArabia, with MaxProduction = 9000, 6000 to reproduce sample 5.
    3. The using() statement is necessary to prevent a SQL connection from leaking.
    4. db.SubmitChanges() is necessary to commit the changes back to the DB.  Otherwise only your in-memory copy is modified.
using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Text;
using Microsoft.SolverFoundation.Services;

namespace OutputBindings {

  [Table(Name = "ProductionCapacity")]
  public class Production {
    [Column(IsPrimaryKey = true)]
    public string Country;

    private int _MaxProduction;

    [Column(Storage = "_MaxProduction")]
    public int MaxProduction {
      get { return this._MaxProduction; }
      set { this._MaxProduction = value; }
    }

    private double _Output;

    [Column(Storage = "_Output")]
    public double Output {
      get { return this._Output; }
      set { this._Output = value; }
    }
  }

  class Program {
    static void Main(string[] args) {

      Decision vz, sa;
      Solution solution = null;
      using (DataContext db = new DataContext(@"Data Source=xxx\yyy; Initial Catalog=MSF; Integrated Security=True")) {
        db.Log = Console.Out; // Let's see what's happening.

        // Get a typed table to run queries
        Table<Production> Productions = db.GetTable<Production>();

        // Get the context and creating a new model.
        SolverContext context = SolverContext.GetContext();
        Model model = context.CreateModel();

        // Create two decision variables representing the number of barrels to
        // purchase from two countries.
        // AddDecisions tells the model about the two variables.
        vz = new Decision(Domain.RealNonnegative, "barrels_venezuela");
        sa = new Decision(Domain.RealNonnegative, "barrels_saudiarabia");

        vz.SetBinding(from row in Productions where row.Country == "Venezuela"
           select row, "Output");
        sa.SetBinding(from row in Productions where row.Country == "SaudiArabia"
           select row, "Output");
        model.AddDecisions(vz, sa);

        Parameter maxvz = new Parameter(Domain.RealNonnegative, 
           "maxproduction_venezuela");
        Parameter maxsa = new Parameter(Domain.RealNonnegative,   
           "maxproduction_saudiarabia");

        // To get the same results as in the sample, set MaxProduction=9000 for  
        // Venezuela, MaxProduction=6000 for SaudiArabia in your DB table.
        maxvz.SetBinding(from row in Productions where row.Country == "Venezuela" 
            select row, "MaxProduction");
        maxsa.SetBinding(from row in Productions where row.Country == "SaudiArabia" 
            select row, "MaxProduction");
        model.AddParameters(maxvz, maxsa);

        // Adding five contraints. The first line is two contraints giving the
        // allowable range for the two decision varibles. The other contraints put
        // minimums on the total yield of three products.
        model.AddConstraints("limits",
        0 <= vz <= maxvz,
        0 <= sa <= maxsa);
        model.AddConstraints("production",
        0.3 * sa + 0.4 * vz >= 2000,
        0.4 * sa + 0.2 * vz >= 1500,
        0.2 * sa + 0.3 * vz >= 500);

        model.AddGoal("cost", GoalKind.Minimize, 20 * sa + 15 * vz);
        solution = context.Solve(new SimplexDirective());

        context.PropagateDecisions(); // Propagate values to the in-memory rep.
        db.SubmitChanges(); // Commit to DB.
      }

      if (solution != null) {
        Report report = solution.GetReport();
        Console.WriteLine("vz: {0}, sa: {1}", vz, sa);
        Console.Write("{0}", report);
      }
    }
  }
}