Saturday, May 30, 2009

MS Solver Foundation Data Binding problem

This program gives an exception I don't understand:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Data.OleDb;
using System.Data.Linq;
using System.Text;
using Microsoft.SolverFoundation.Services;
using System.IO;

namespace
OML1
{
    class Test 
   
        /// <summary> 
        /// Called by the OS 
        /// </summary> 
        /// <param name="args"></param> 
        static void Main(string[] args) 
       
            Test t = new Test(); 
            t.Solve(); 
        }

        /// <summary> 
        /// Holds the OML model 
        /// </summary> 
        string strModel = @"Model[ 
              Parameters[Sets,I], 
              Parameters[Reals,p[I]], 

              Decisions[Reals[0,Infinity],x[I]],  

 
             Constraints[ 
                 Foreach[{i,I}, x[i]==p[i]] 
             
           ]"

        /// <summary> 
        ///  SFS 
        /// </summary> 
        SolverContext context; 

        /// <summary> 
        ///  Constructor 
        /// </summary> 
        public Test() 
       
            context = SolverContext.GetContext(); 
       

        /// <summary> 
        /// Solve the problem 
        /// </summary> 
        public void Solve() 
       
            context.LoadModel(FileFormat.OML, new StringReader(strModel)); 

            DataTable dt = new DataTable(); 
            dt.Columns.Add("index", System.Type.GetType("System.String")); 
            dt.Columns.Add("value", System.Type.GetType("System.Double")); 
            dt.Rows.Add("a", 1); 
            dt.Rows.Add("b", 2); 

 
           DataTable dt2 = new DataTable(); 
            dt2.Columns.Add("index", System.Type.GetType("System.String")); 
            dt2.Columns.Add("value", System.Type.GetType("System.Double")); 
            dt2.Rows.Add("a", -1); 
            dt2.Rows.Add("b", -1); 
 
 
           Parameter p = context.CurrentModel.Parameters.First(q => q.Name == "p"); 
            p.SetBinding(dt.AsEnumerable(), "value", new string[] { "index" }); 

            Decision x = context.CurrentModel.Decisions.First(d => d.Name == "x"); 

            // next statement gives: 
            // The property or field 'value' was not found 
>>>>>>>     x.SetBinding(dt2.AsEnumerable(), "value", new string[] { "index" }); <<<<<<<<<<<<

            Solution solution = context.Solve(); 
 
           Console.Write("{0}", solution.GetReport()); 

            context.PropagateDecisions(); 
       
   
}

The exception is

columnNotFound

The data binding on the parameter p works fine. But the same data binding on the variable x fails. I am afraid I don’t understand this. The error message is not helping me: there is actually a column ‘value’.

I have fired off a question to this effect in the forum at http://code.msdn.microsoft.com/solverfoundation/.

Note that I easily can bind the decision to a List, and then move the data in the List to the DataTable myself.

3 comments:

  1. You will want to replace your binding to x with the following code:
    x.SetBinding(dt2.AsEnumerable().Select(dr => new { value = dr["value"], index = dr["index"] }), "value", "index");

    In fact binding on decisions requires that the name that you specify as value (or index) property exists in the object as either a field or a property, and not as an index of some collection.
    After fixing that your code still hangs on
    context.PropagateDecisions()
    because I've used an anonymous type, which apparently doesn't include property setters, but implementing a concrete type (a struct?) should be enough to get your code to run as expected.

    ReplyDelete
  2. Thanks. Yes, I understand that. However look at the parameter binding. I believe that if using an index is allowed in parameter binding it should also be allowed in decision binding.

    ReplyDelete
  3. That's a problem of API consistency. While I totally agree with you, the problem is at design level and not code-wise :)

    ReplyDelete