Message Boards Message Boards

0
|
2316 Views
|
6 Replies
|
2 Total Likes
View groups...
Share
Share this post:

Connecting to the Wolfram Engine from C++

Posted 1 year ago

I have created a test application to connect to the wolfram engine based on the documentation. I don't know if i'm right but reading LLU (Library Link Utilities) seems solve that problem by providing some WSTP capabilities with a WSStream class. My problem is i don't seem to understand how WSStream class should be used for example to calculate 2+2.

My program looks like the following:

int main()
{
    // WSTP Initialise
    WSENV env = WSInitialize((char*)0);
    if (env == (WSENV)0)
    {
       std::cout << "Unable to initialize!";
       return 1;
    }
    else
       std::cout << "Iniialized!";

    // WSTP Open a connection to the wolfram kernel
    int error;
    WSLINK link;
    link = WSOpenString(env, " -linklaunch \"C:\\Program Files\\Wolfram Research\\Wolfram Engine\\13.3\\mathkernel.exe\"", &error);

    if(link == (WSLINK)0 || error != WSEOK)
    {
       std::cout << "Unable to create link!";
       return 1;
    }
    else
       std::cout << "Link created!";

    // WSTP Activate link
    if (!WSActivate(link))
    {
       std::cout << "Link not activated!";
       return 1;
    }
    else
       std::cout << "Link activated!";
    // Data exchange -->> MyProblem
    std::cout << "Create the stream object" << std::endl;
    LLU::WSStream<LLU::WS::Encoding::UTF8, LLU::WS::Encoding::UTF8> test(link);
    std::cout << "Add 2+2 to the stream" << std::endl;
    test << (mint) 1 << LLU::WS::BeginExpr::BeginExpr("1") << "2+2" << LLU::WS::EndExpr();
    std::cout << "Wait for a reply" << std::endl;
    int result;
    test >> result;
    cout << "Hello CMake. Error : " << error << " Result : " << result << endl;
    std::cout << "Close the connection..." << std::endl;

    // WSTP Close gracefully
    WSClose(link);
    WSDeinitialize(env);
    return 0;
}

When I start I have to select the *.exe with the wolfram kernel. and it shows the link is activated. However the program get's stuck when receiving the result from the calculation, it exits. Probably because I'm not using the right call convention for the data exchange part. Does any one know how this should be done ?

POSTED BY: Bart R.
6 Replies
Posted 1 year ago

Thanks for you're reply. I changed the application a bit and found out that the function EnterTextPacket did the trick for me. But it was a long struggle in the documentation. Do you have some documentation on how the kernel behave's on the interface? For example a state diagram of the WSTP interface of the kernel? Which functions should be send and what to expect back. Or what if a function can't be evaluated ? What errors can occur ? Mainly which function packets are used and in what order ?

POSTED BY: Bart R.
Posted 1 year ago

I have been reading in the documentation a bit and wondered if binary data-exchange is also possible with WSTP. I want to do some image processing and to do that binary data-echange is the fastest way. I've been playing around with the command ImageData[] but it generates a lot of text for a small image. Secondly when you receive a reply is it also possible to get the metadata of the reply. I mean when the Engine sends a reply is it possible to get a message that the engine is going to send an array of 10.000 bytes for example. I saw you have the TypeOf command but that only works for simple datatypes.

POSTED BY: Bart R.
Posted 1 year ago

Thanks for responding. I've published a github with my application. You can find it: in my public repository. It contains a readme.md what I did to come to this point. I''d like to know if it's possible with the WSTP part inside the Library Link Utitlities to connect directly to the Wolfram Engine with the WSStream object. Thanks in advance.

POSTED BY: Bart R.

Thanks, I cloned your project and played with it for a while. Actually, you were really close to succeeding. Your setup and everything you do until sending the expression via WSTP is fine.

The problem in your code (I will refer to what you have on github, which is slightly different from what you posted here) is that you send a string "2+2+2". When WSStream sees a string it sends it as a String expression, which in WL evaluates to itself.

The expression that you want to send is Plus[2, 2, 2], which in WL evaluates to 6. So I modified your code as follows:

    // Write the expression to the stream
    std::cout << "Add 2+2+2 to the stream" << std::endl;
    LLU::WS::Function enterExpressionFunction {"EnterExpressionPacket", 1};

    test << enterExpressionFunction << LLU::WS::Function("Plus", 3) << 2 << 2 << 2;

    // Wait for output packet Out[1]:= and the computed results

And the output I get from your debug prints is:

(...)
Add 2+2+2 to the stream
Wait for output packet
Function head:OutputNamePacket Arguments :1 String : Out[1]= 
Function head:ReturnExpressionPacket Arguments :1 String : 6
(...)

So the result is 6, as expected.

POSTED BY: Rafal Chojna

Interesting. LLU was designed to be used in LibraryLink-based paclets and I'm not aware of any use in a standalone application but it might be possible.

Can you please share your entire code and build commands, e.g. as a github gist or even here?

POSTED BY: Rafal Chojna
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract