MBS
MBS

Reputation: 71

Is it possible to call a R statistics function to optimize C# function

I want to know if it's possible to call r statistics optimization function (here I want to use regnoud) from C# while the function to be optimized is written in C#. I found RDotNet library but with it i cannot evaluate the C# function from R. In other terms, the problem is that R while optimizing needs to evaluate the function but he cannot do it because the function is in the C# code.

is there any solution like using .dll or other libraries?
thanks.

Upvotes: 6

Views: 4070

Answers (3)

j-m
j-m

Reputation: 1539

If I understand your need clearly, you have a an optimisation problem with a C# calling R calling back C#.

I do not think there is a way to set up a callback function ("function pointer", "delegate" as they can be called depending on who you talk to) in R.NET currently. I am likely to have very similar needs and may contribute this to R.NET in the future, if I can allocate the time.

Meanwhile, if it is acceptable to have things such that you work from R calling C#, i.e. R is the entry point of your application, this is definitely doable using the rClr package. I have colleagues doing optimisation and MCMC analysis of a model written in C#. One tutorial is a very simplified but realistic case of optimisation from R using C#.

Upvotes: 1

user1625066
user1625066

Reputation:

I have done this before using a somewhat convoluted approach but it works!

First, you will need to create a C# DLL containing your function. You can do this in visual studio by selecting "class library" as the option when creating a new project. The code in the .cs file should look like this

namespace MyNamespace
{
    //expose an interface with functions to be called from R
    public interface MyInterface
    {
       string MyFunction(string name);
    }

    //create a class that implements the above interface
    public class MyClass : MyInterface
    {
      public string MyFunction(string name)
      {
         return "Hello " + name;
      }
    }

}

Now compile your project and you will get a C# DLL. This DLL is a managed DLL which is different from a native C/C++ DLL. It cannot be directly consumed from non .Net languages and so needs to be exposed as a COM object. You can do this in one of two ways

  1. In Visual Studio, you can go to the project properties, click on "Assembly information" button under "Application" tab and select the checkbox that says "Make assembly COM visible".
  2. Alternatively, you can use regasm.exe which can be found in the .net installation folder to register the DLL as a COM component. Here is a link describing this process. http://msdn.microsoft.com/en-us/library/tzat5yw6(v=vs.71).aspx. The command is usually "regasm myTest.dll /tlb:myTest.tlb"

The COM registration process will now have created a .tlb file in the same folder as your DLL. Keep this .tlb file. We will need it in the next step

The next step is to create a C++ DLL which can call the COM DLL. This step is needed because R can call a C++ DLL directly but cannot call COM directly (correct me if I am wrong or skip this step if you know a better way to call COM from R). The code for the C++ DLL in dllmain.cpp is shown below (make sure to scroll to see the full code)

#include "stdafx.h"
#include <iostream>

//import the .tlb file create by COM registration

#import "path_to_Dll\MyDll.tlb" named_guids raw_interfaces_only

    void _cdecl MyCPPFunction(char ** strName)
    {
        //Initialize COM
        HRESULT hr = CoInitialize(NULL);

        //create COM interface pointer
        MyNamespace::MyInterfacePtr myPtr;

        //create instance of COM class using the interface pointer
        HRESULT hr2 = myPtr.CreateInstance(MyNamespace::CLSID_MyClass);

       //create variable to hold output from COM.
       BSTR output;

       //call the COM function
       myPtr->MyFunction(_bstr_t(strName[0]), &output);

       //convert the returned BSTR from .net into char*
       int length = (int) SysStringLen(output);
       char *tempBuffer;
       tempBuffer = (char *) malloc(1 + length);
       WideCharToMultibyte(CP_ACP, 0, output, -1, tempBuffer, length, NULL, NULL);
       tempBuffer[length] = '\0';

       //release interface
       myPtr->Release();

       //uninitialize COM
       if(hr == S_OK)
         CoUninitialize();

       //set output in input for returning to R (this is weird but the only way I could make it work)
       strName[0] = tempBuffer;
    }

Now compile your project and you will get a C++ DLL. We are almost there now! Dont give up yet :). Now, you have a C# DLL exposed as a COM object and a C++ DLL that can call this COM object. The final step is to call the C++ function from R. Here is the R code to do that

#load C++ DLL
dyn.load("path_to_C++_DLL")

#call function in C++ DLL and pass in a test name.
# The C++ DLL will in turn call the C# function
output <- .C("MyCPPFunction", as.character("Peter"))

#print output
print(output)

And you should see "Hello Peter" displayed from C# in the R console! One very important point to note.

Always, compile the COM DLL using "any CPU" option. Always compile the C++ DLL to match your R installation! For example, if you have 32 bit R installed, then make sure you compile the C++ DLL as 32 bit DLL. If you have 64 bit R installed and want to use it, then make sure you compile your C++ DLL as a 64 bit DLL. Best of luck!

Upvotes: 12

Frank P.
Frank P.

Reputation: 513

http://www.codeproject.com/Articles/25819/The-R-Statistical-Language-and-C-NET-Foundations

Check out something like this. Now I don't know much about C# so if I say anything that is impossible please don't hurt me:

Try to save the function that you want optimized as a character in C#, and send it to R using this StatConnector library (I have some limited experience with it.) Let's say you saved the equation as 'z' within R, you can then call your R scripts with 'get(z)' as one of the variables.

Upvotes: 0

Related Questions