Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust Codegen doesn't generate public functions #26562

Open
AJMC2002 opened this issue May 4, 2024 · 6 comments
Open

Rust Codegen doesn't generate public functions #26562

AJMC2002 opened this issue May 4, 2024 · 6 comments

Comments

@AJMC2002
Copy link

AJMC2002 commented May 4, 2024

I'm trying to generate functions to import them in my code. I haven't managed to get the code generator to make the functions pub. If there's a way to do this automatically rather than manually, it'd be of great help.

I have a script generating code to src/functions.rs, then using mod functions, I'm trying to import them but they are not visible for src/main.rs.

@sylee957
Copy link
Member

sylee957 commented May 5, 2024

Can you take some example of function? Also are you using rust_code or codegen or RustCodegen?

@AJMC2002
Copy link
Author

AJMC2002 commented May 6, 2024

I'm using RustCodegen with it's dump_rs function

from sympy import exp, sin, cos, diff
from sympy.abc import x
from sympy.utilities.codegen import make_routine, RustCodeGen


with open("src/functions.rs", "w") as fout:
    functions = {}
    functions["y"] = exp(-x) * sin(x)
    functions["y_prime"] = diff(functions["y"], x, 1)
    functions["p"] = x**2
    functions["q"] = cos(x)
    functions["f"] = (
        diff(functions["y"], x, 2)
        + functions["p"] * diff(functions["y"], x, 1)
        + functions["q"] * functions["y"]
    )
    c = RustCodeGen()
    c.dump_rs(
        [make_routine(name, expr) for name, expr in functions.items()], fout, ""
    )

generating the following code:

/*
 *                       Code generated with SymPy 1.12
 *
 *              See http://www.sympy.org/ for more information.
 *
 *                       This file is part of 'project'
 */

fn y(x: f64) -> f64 {

    let result_2048249359719250003 = (-x).exp()*x.sin();
    result_2048249359719250003

}

fn y_prime(x: f64) -> f64 {

    let result_54348404940285614 = -(-x).exp()*x.sin() + (-x).exp()*x.cos();
    result_54348404940285614

}

fn p(x: f64) -> f64 {

    let result_1966259434947152376 = x.powi(2);
    result_1966259434947152376

}

fn q(x: f64) -> f64 {

    let result_7659997875259276922 = x.cos();
    result_7659997875259276922

}

fn f(x: f64) -> f64 {

    let result_2450520253889769909 = x.powi(2)*(-(-x).exp()*x.sin() + (-x).exp()*x.cos()) + (-x).exp()*x.sin()*x.cos() - 2*(-x).exp()*x.cos();
    result_2450520253889769909

}

There's an error with an int multiplying floats in f(x), but that's in #25173. Apart from that, here it doesn't seem possible to make all generated functions visible with pub.

@AJMC2002
Copy link
Author

AJMC2002 commented May 7, 2024

As an extra error I found using this method was when importing pi from sympy and using it in the functions. It correctly gets transformed to PI but the outputted file doesn't import std::f64::consts::PI.

@AJMC2002
Copy link
Author

Coming back to this problem, adding "fn ..." to "pub fn .." in the get_prototype function of RustCodeGen at sympy/utilities/codegen.py would solve that.

Nonetheless, I don't know the scope and intention behind the code generators in sympy. Making all generated code pub might affect the expected results for someone just generating a prototype to copy and paste, which wouldn't need the pub keyword. Maybe adding an option for the code generator constructor to indicate if it outputs public functions or not might be an idea, ofc also a method that changes that behavior of the codegen object would be good.

I'd do a PR but depending on what would be more suitable to do, I'd prefer not making someone waste time reading code first before knowing what would be better for this lib.

@sylee957
Copy link
Member

sylee957 commented May 17, 2024

I'm okay with replacing fn to pub fn anywhere it can be used, and it may not be that much fragile, because visibility and privacy is not very important in automatically generated code, or optimizing automatically generated code.
The reason is that everything can just be public, and unlike human generated codes, machine generated codes don't have to distinguish private and public for semantical reasons, and also naming conflicts can be avoided by assigning lots of arbitrary generated names.
And there may be no compiler optimizations that can do better with pub, similar with aformented reasons, however, I'm not entirely sure about it, because I'm not sure about Rust compiler.

I'd prefer not making someone waste time reading code first before knowing what would be better for this lib.

However, such expressions is not necessary to add to, because it is immature way of speaking, in general life advices. If your statements are not very 'genius', then please don't communicate in this format.

Technically speaking, replacing fn to pub fn is not the solution that can be fundamental,
because there are more combinations of keywords (such as const, async),
and also because pub can be parameterized (such as pub(crate)),
if you change fn to pub fn straightforward, it may be difficult in the future to extend SymPy to work that direction.

(References)
https://doc.rust-lang.org/reference/items/functions.html
https://doc.rust-lang.org/reference/visibility-and-privacy.html

@AJMC2002
Copy link
Author

Since changing fn to pub fn isn't the best thing here, why not then edit the methods that take in Routine objects like get_prototype and dump_rs to also take in tuples of (str, Routine) type where the first element is a string containing the function's traits (e.g. pub, const)

Giving the possibility to generate code ready for it's inclusion in a crate as soon as it's generated would be ideal. Since Rust's functions are private by default, having to add to every function the pub isn't good.

The limitation of this approach would be:

  • Possibility of inserting custom functions from the string inserted; code injection
    The impact of adding custom functions though, is debatible since those functions aren't getting called.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants