Monday, September 8, 2014

Compile C# Code

In today's post I want to show, how one can compile C# code with C# and that way create and execute new programs during runtime.
This is relatively easy, amonst others .Net offers the class CodeDomProvider, with which directly code can be compiled. More can be found on MSDN, from there I also took the example.
The following program compiles the C# code entered in a textbox, creates out of it an .exe file and eventually runs it. The code should be self explaining, I will first list it and after that explain the important parts. There are 2 textboxes, in the one the source code is entered, in the other the compile result (success or the found errors) is shown. Furthermore there are 2 buttons, one compiles the code, the other executes the created program:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.IO;
using System.CodeDom.Compiler;

namespace CodeCompiler
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        public void CompileExecutable(String[] sourceName)
        {
            CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");

            CompilerParameters cp = new CompilerParameters();

            cp.GenerateExecutable = true;
            cp.OutputAssembly = "Compiled.exe";
            cp.GenerateInMemory = false;
            cp.TreatWarningsAsErrors = false;

            CompilerResults cr = provider.CompileAssemblyFromSource(cp, sourceName);

            if (cr.Errors.Count > 0)
            {
                textBox2.Text = "Errors: " + Environment.NewLine;
                foreach (CompilerError ce in cr.Errors)
                {
                    textBox2.Text += ce.ToString() + Environment.NewLine;
                }
            }
            else
            {
                textBox2.Text = "Success";
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string[] SourceCode = new string[1];
            SourceCode[0] = textBox1.Text;
            CompileExecutable(SourceCode);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("Compiled.exe");
        }
    }
}

In the first line of the function CompileExecutable() a new code provider for C# is created. Then 4 compiling options are defined: Via GenerateExecutable = true we tell the program, that we want to create an executable file and not, for example, a class library. Via the next lines we define, that we want to create a file and set the output path, furthermore the handling of warnings.
Via CompileAssemblyFromSource() we eventually compile the code. To this function we have to pass over the created compiling arguments and an array of strings, which contains the source codes - so multiple programs can be compiled at once.
Afterwards the number of errors is checked, and if this is greater than 0, these are outputted.
Via System.Diagnostics.Process.Start() we then simply start the program.

Wednesday, September 3, 2014

Gurobi for Windows 64-bit: System.BadImageFormatException - Gurobi56.NET.dll

When trying to use the Gurobi Optimizer in the 64 bit version with C# .Net I came across an error. When executing the program code the following error was thrown:  System.BadImageFormatException in Gurobi56.NET.dll. As one can read here, this is beause a DLL for ASP .Net is compiled for 32 Bit, which forces the other DLLs to run in 32 bit. That means, the 64 bit version does not seem to work for now in .Net. So install the 32 bit version to avoid the error. If the 64 bit version starts to run, I would be happy about a comment.

Tuesday, September 2, 2014

(Linear) Optimization with C# and Gurobi

Today I want to write about the Gurobi Optimizer, with which optimization problems can be solved, more specifically linear and quadratical programs.
In principle Gurobi does cost anything, however members of an academical institution (like students of a university) can acquire a free license, for all others there are trial licenses. For many different programming languages, for example the .Net languages, interfaces are offered.
First Gurobi has to be downloaded, which can be done here. Attention: For .Net the 64 Bit version does not seem to work, but the 32 Bit version runs on all systems - see the next post.
After that a Gurobi license has to be aquired. For that you have to select the desired license under Downloads - Licenses on the Gurobi website and click "Request License". On the new page you find a command in the form "grbgetkey e7300a11-...", which has to be executed via Start - Run. Then the Gurobi server is contacted, the license aquired and saved on the computer. Now the solver is ready to go.
Now I want to give an example on the usage of it, for which I will use the same example as in the Gurobi Quickstart Guide.
We want to optimize the following model:

Maximize x + y + 2z
s.t. x + 2y + 3z <= 4
x + y >= 1
x, y ∈ {0, 1}

To be able to use Gurobi in .Net, we first have to add a reference to the library Gurobi56.NET.dll to our project. In my case this is located in the folder C:\gurobi563\win32\bin.
The C# code for a console application, which models the above example, is then:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Gurobi;

namespace GurobiConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                GRBEnv env = new GRBEnv("mip1.log");
                GRBModel model = new GRBModel(env);

                // Create variables

                GRBVar x = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "x");
                GRBVar y = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "y");
                GRBVar z = model.AddVar(0.0, 1.0, 0.0, GRB.BINARY, "z");

                // Integrate new variables

                model.Update();

                // Set objective: maximize x + y + 2 z

                model.SetObjective(x + y + 2 * z, GRB.MAXIMIZE);

                // Add constraint: x + 2 y + 3 z <= 4

                model.AddConstr(x + 2 * y + 3 * z <= 4.0, "c0");

                // Add constraint: x + y >= 1

                model.AddConstr(x + y >= 1.0, "c1");

                // Optimize model

                model.Optimize();

                Console.WriteLine(x.Get(GRB.StringAttr.VarName)
                                   + " " + x.Get(GRB.DoubleAttr.X));
                Console.WriteLine(y.Get(GRB.StringAttr.VarName)
                                   + " " + y.Get(GRB.DoubleAttr.X));
                Console.WriteLine(z.Get(GRB.StringAttr.VarName)
                                   + " " + z.Get(GRB.DoubleAttr.X));

                Console.WriteLine("Obj: " + model.Get(GRB.DoubleAttr.ObjVal));

                // Dispose of model and env

                model.Dispose();
                env.Dispose();

                string Dummy = Console.ReadLine();

            }
            catch (GRBException ex)
            {
                Console.WriteLine("Error code: " + ex.ErrorCode + ". " + ex.Message);
            }
        }
    }
}

Let's walk this through step by step. First we create a Gurobi environment and a model, as a parameter we pass the path to the log file, in which outputs of the program are printed. Then we create the 3 needed variables x, y and z. The first two parameters are upper and lower bounds for them, the third describes their coefficient in the target funtion. We here pass 0, because we define the objective later. GRB.BINARY says, that the variable is binary. Other possible values are GRB.INTEGER and GRB.CONTINOUS. The following commands should be self-explanatory, via SetObjective() we define the objective, via AddConstr() we add constraints. The found solution is eventually outputted in the console.
If the LP has no solution or is unbound, an error is thrown when trying to obtain the variable values, namely "Error at GRBVar.Get".