WolframResearch / wstp-rs

Rust bindings to the Wolfram Symbolic Transport Protocol (WSTP)
Apache License 2.0
21 stars 3 forks source link

how to evaluate `Plus[1, 1]`? #59

Closed anandijain closed 1 year ago

anandijain commented 1 year ago

Thank you for the package, I'm learning about WSTP but I can't seem to get it to evaluate the expression (despite trying put_eval_packet and manually with put_function.

The below code, when run returns

warning: `wstp_tests` (bin "wstp_tests") generated 1 warning (run `cargo fix --bin "wstp_tests"` to apply 1 suggestion)
    Finished dev [unoptimized + debuginfo] target(s) in 0.28s
     Running `target/debug/wstp_tests`
Ok(70)
The result is: System`EvaluatePacket[System`Plus[1, 1]]

I'm definitely missing something about WSTP, how do I actually retrieve the evaluated code? Thanks!

use std::error::Error;
use wolfram_expr::{Expr, Symbol};
use wstp::Link;

fn main() -> Result<(), Box<dyn Error>> {
    // Create an expression
    let expr = Expr::normal(
        Symbol::new("System`Plus"),
        vec![Expr::from(1), Expr::from(1)],
    );

    // Initialize the link
    let mut link = Link::new_loopback()?;

    // Send an evaluate packet with the expression Plus[1, 1]
    link.put_function("System`EvaluatePacket", 1)?;
    link.put_function("System`Plus", 2)?;
    link.put_i64(1)?;
    link.put_i64(1)?;
    link.end_packet()?;
    link.flush()?;

    println!("{:?}", link.get_raw_type());

    // Retrieve and print the result
    let result_expr = link.get_expr()?;
    println!("The result is: {:?}", result_expr);

    Ok(())
}
ConnorGray commented 1 year ago

Hi @anandijain, the reason this isn't evaluating is that the the link you're creating is not connected to a Wolfram Kernel. WSTP is a generic protocol for transferring Wolfram Language expressions between arbitrary programs, so by default no Wolfram Kernel is involved.

In your example, your program is creating a special type of link called a 'Loopback' link, where any expression written to the link can be read back from the same link unmodified.

If you want to create a link to a Wolfram Kernel, you will need to create a WSTP link that "launches" the Kernel it will connect to. The wstp::kernel documentation shows an example of this:

use std::path::PathBuf;
use wstp::kernel::WolframKernelProcess;

let exe = PathBuf::from(
    "/Applications/Mathematica.app/Contents/MacOS/WolframKernel"
);

let kernel = WolframKernelProcess::launch(&exe).unwrap();

(The wstp::kernel documentation I linked to also shows an example of using wolfram-app-discovery so you don't have to hard-code the path to your WolframKernel executable.)

If you're trying to build a program that interacts with a running Kernel, you might be interested in this unofficial wolfram-client library I've been developing for use in wolfram-cli.

Let me know if you have any questions about any of this, or run into any problems.