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

sz_w() of expanded function doesn't match codegen #3514

Closed
ghorn opened this issue Dec 20, 2023 · 3 comments
Closed

sz_w() of expanded function doesn't match codegen #3514

ghorn opened this issue Dec 20, 2023 · 3 comments
Labels

Comments

@ghorn
Copy link
Member

ghorn commented Dec 20, 2023

I'm code-generating a function. I'm checking that the work vector size sz_w() in python matches the code-generated sz_w. I noticed that when the function is expanded with Function::expand(), sz_w matches the unexpanded function, but the code-generated expanded function does not match.

Reproduction on casadi 3.6.4:

"""Reproduction for inconsistent sz_w."""

from pathlib import Path

import casadi


def test_casadi_function_generation() -> None:
    """Compare sz_w between python and codegen, for MX and expanded function."""
    x = casadi.MX.sym("x", 2)
    y = casadi.MX.sym("y")
    function = casadi.Function("f", [x, y], [x, casadi.sin(y) * x], ["x", "y"], ["r", "q"])

    # test the nominal function
    print("")
    print(f"function.sz_arg(): {function.sz_arg()}")
    print(f"function.sz_res(): {function.sz_res()}")
    print(f"function.sz_iw(): {function.sz_iw()}")
    print(f"function.sz_w(): {function.sz_w()}")
    assert function.sz_arg() == 4  # this passes
    assert function.sz_res() == 3  # this passes
    assert function.sz_iw() == 0   # this passes
    assert function.sz_w() == 3    # this passes

    # generate file
    filename1 = "gen1.c"
    function.generate(filename1)

    # open and print file
    with Path(filename1).open() as handle:
        lines = handle.readlines()
        line_index = _get_work_fun_line(lines)
        print("".join(lines[line_index : line_index + 7]))  # codegen consistent with above assertions

    # test the expanded function
    expanded_function = function.expand()
    print(f"expanded_function.sz_arg(): {expanded_function.sz_arg()}")
    print(f"expanded_function.sz_res(): {expanded_function.sz_res()}")
    print(f"expanded_function.sz_iw(): {expanded_function.sz_iw()}")
    print(f"expanded_function.sz_w(): {expanded_function.sz_w()}")
    assert expanded_function.sz_arg() == 2  # this passes
    assert expanded_function.sz_res() == 2  # this passes
    assert expanded_function.sz_iw() == 0   # this passes
    assert expanded_function.sz_w() == 3    # PASSES BUT IS INCONSISTENT WITH CODEGEN

    # generate file
    filename2 = "gen2.c"
    expanded_function.generate(filename2)

    # open and print file
    with Path(filename2).open() as handle:
        lines = handle.readlines()
        line_index = _get_work_fun_line(lines)
        print("".join(lines[line_index : line_index + 7]))  # codegen says sz_w == 0


def _get_work_fun_line(lines):
    """Get the line number that starts the work function."""
    start = (
        "CASADI_SYMBOL_EXPORT int f_work(casadi_int *sz_arg, casadi_int* sz_res, casadi_int *sz_iw, casadi_int *sz_w)"
    )
    for k, line in enumerate(lines):
        if start in line:
            return k
    err_msg = f"could not find '{start}' in file"
    raise ValueError(err_msg)

if __name__ == '__main__':
    test_casadi_function_generation()

Here are the results

function.sz_arg(): 4
function.sz_res(): 3
function.sz_iw(): 0
function.sz_w(): 3
CASADI_SYMBOL_EXPORT int f_work(casadi_int *sz_arg, casadi_int* sz_res, casadi_int *sz_iw, casadi_int *sz_w) {
  if (sz_arg) *sz_arg = 4;
  if (sz_res) *sz_res = 3;
  if (sz_iw) *sz_iw = 0;
  if (sz_w) *sz_w = 3;
  return 0;
}

expanded_function.sz_arg(): 2
expanded_function.sz_res(): 2
expanded_function.sz_iw(): 0
expanded_function.sz_w(): 3
CASADI_SYMBOL_EXPORT int f_work(casadi_int *sz_arg, casadi_int* sz_res, casadi_int *sz_iw, casadi_int *sz_w) {
  if (sz_arg) *sz_arg = 2;
  if (sz_res) *sz_res = 2;
  if (sz_iw) *sz_iw = 0;
  if (sz_w) *sz_w = 0;
  return 0;
}

notice that for the code generated function, sz_w is 0 but in python it's reported as 3

@jaeandersson
Copy link
Member

When evaluated in codegen, local variables will be allocated instead of using the work vector. So the work vector isn't needed for SX codegen. So it's not really a problem.

@jaeandersson
Copy link
Member

Closing as I think that this is expected behavior

@ghorn
Copy link
Member Author

ghorn commented Dec 20, 2023

Thank you!

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

No branches or pull requests

2 participants