Tim-Salzmann / l4casadi

Use PyTorch Models with CasADi and Acados in Python, C(++) or Matlab
MIT License
290 stars 17 forks source link

acados.py library loading issue #21

Closed jy-cds closed 5 months ago

jy-cds commented 5 months ago

Hi Tim,

Much thanks for your help with setting up both Acados and l4casadi! I was trying to run the acados.py example with l4casadi, but ran into some library-not-found error regarding liblearned_dyn.dylib. I double checked that I had set the PATH and DIR for acados in the terminal:

export DYLD_LIBRARY_PATH=/Users/jing/acados/lib export ACADOS_SOURCE_DIR=/Users/jing/acados

I also ran some ocp examples from the acados packacge and they all ran successfully. Moreover, I installed the latest l4casadi version and can successfully run the naive examples.

The error message from running acados.py in the examples folder is as follows:

Traceback (most recent call last): File "/Users/jing/l4casadi/examples/acados.py", line 219, in run() File "/Users/jing/l4casadi/examples/acados.py", line 185, in run solver = MPC(model=model.model(), N=N, File "/Users/jing/l4casadi/examples/acados.py", line 85, in solver return AcadosOcpSolver(self.ocp()) File "/Users/jing/acados/interfaces/acados_template/acados_template/acados_ocp_solver.py", line 987, in init self.shared_lib = CDLL(self.shared_lib_name) File "/Users/jing/opt/anaconda3/envs/building_mpc/lib/python3.9/ctypes/init.py", line 374, in init self._handle = _dlopen(self._name, mode) OSError: dlopen(/Users/jing/l4casadi/c_generated_code/libacados_ocp_solver_wr.dylib, 0x0006): Library not loaded: liblearned_dyn.dylib Referenced from: <7A2E692D-5D49-3F79-B0FC-336276534C04> /Users/jing/l4casadi/c_generated_code/libacados_ocp_solver_wr.dylib Reason: tried: '/Users/jing/acados/lib/liblearned_dyn.dylib' (no such file), 'liblearned_dyn.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OSliblearned_dyn.dylib' (no such file), 'liblearned_dyn.dylib' (no such file), '/Users/jing/acados/lib/liblearned_dyn.dylib' (no such file), '/Users/jing/l4casadi/liblearned_dyn.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/Users/jing/l4casadi/liblearned_dyn.dylib' (no such file), '/Users/jing/l4casadi/liblearned_dyn.dylib' (no such file)

Any pointers to try to resolve this problem is much appreciated!

Tim-Salzmann commented 5 months ago

Hi,

As a first step, can you please verify that liblearned_dyn.dylib exists in examples/_l4c_generated and that learned_dyn_model.shared_lib_dir in line 181 points to the same folder.

Best Tim


Edit Also could you please post the full output preceeding the traceback.

jy-cds commented 5 months ago

Hi Tim,

There is currently no folder named _l4c_generated in the examples folder. Should it have been generated when the acados.py ran? Or perhaps I should manucally make that folder? The full output looks like this:

Couldn't import dot_parser, loading of dot files will not be possible. rm -f libacados_ocp_solver_wr.dylib rm -f acados_solver_wr.o cc -fPIC -std=c99 -O2 -I/Users/jing/acados/include -I/Users/jing/acados/include/acados -I/Users/jing/acados/include/blasfeo/include -I/Users/jing/acados/include/hpipm/include -c -o acados_solver_wr.o acados_solver_wr.c cc -fPIC -std=c99 -O2 -I/Users/jing/acados/include -I/Users/jing/acados/include/acados -I/Users/jing/acados/include/blasfeo/include -I/Users/jing/acados/include/hpipm/include -c -o wr_model/wr_expl_ode_fun.o wr_model/wr_expl_ode_fun.c cc -fPIC -std=c99 -O2 -I/Users/jing/acados/include -I/Users/jing/acados/include/acados -I/Users/jing/acados/include/blasfeo/include -I/Users/jing/acados/include/hpipm/include -c -o wr_model/wr_expl_vde_forw.o wr_model/wr_expl_vde_forw.c cc -fPIC -std=c99 -O2 -I/Users/jing/acados/include -I/Users/jing/acados/include/acados -I/Users/jing/acados/include/blasfeo/include -I/Users/jing/acados/include/hpipm/include -c -o wr_model/wr_expl_vde_adj.o wr_model/wr_expl_vde_adj.c cc -shared acados_solver_wr.o wr_model/wr_expl_ode_fun.o wr_model/wr_expl_vde_forw.o wr_model/wr_expl_vde_adj.o -o libacados_ocp_solver_wr.dylib -L/Users/jing/acados/lib -lacados -lhpipm -lblasfeo -lm \ -L /Users/jing/l4casadi/examples/_l4c_generated -l learned_dyn ld: warning: search path '/Users/jing/l4casadi/examples/_l4c_generated' not found ld: library 'learned_dyn' not found clang: error: linker command failed with exit code 1 (use -v to see invocation) make: *** [ocp_shared_lib] Error 1 acados was compiled without OpenMP. Traceback (most recent call last): File "/Users/jing/l4casadi/examples/acados.py", line 219, in run() File "/Users/jing/l4casadi/examples/acados.py", line 185, in run solver = MPC(model=model.model(), N=N, File "/Users/jing/l4casadi/examples/acados.py", line 85, in solver return AcadosOcpSolver(self.ocp()) File "/Users/jing/acados/interfaces/acados_template/acados_template/acados_ocp_solver.py", line 987, in init self.shared_lib = CDLL(self.shared_lib_name) File "/Users/jing/opt/anaconda3/envs/building_mpc/lib/python3.9/ctypes/init.py", line 374, in init self._handle = _dlopen(self._name, mode) OSError: dlopen(/Users/jing/l4casadi/examples/c_generated_code/libacados_ocp_solver_wr.dylib, 0x0006): tried: '/Users/jing/acados/lib/libacados_ocp_solver_wr.dylib' (no such file), '/Users/jing/l4casadi/examples/c_generated_code/libacados_ocp_solver_wr.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OS/Users/jing/l4casadi/examples/c_generated_code/libacados_ocp_solver_wr.dylib' (no such file), '/Users/jing/l4casadi/examples/c_generated_code/libacados_ocp_solver_wr.dylib' (no such file)

Thank you!!

Tim-Salzmann commented 5 months ago

Hi Jing,

Yes, like with other L4CasADi examples, this folder should be auto-generated, including the dylib file.

Judging from the traceback, you seem to have changed the acados.py example. Is this correct?

If so, please post the full file content here.

Thanks Tim

jy-cds commented 5 months ago

Yes, I changed two things in the acados.py file:

  1. I added the following two lines in the beginning (Otherwise I consistently get errors OMP errors, where it says OMP: Error #15: Initializing libiomp5.dylib, but found libomp.dylib already initialized, which I think has something to do with Torch ):

    import os os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"

  2. Instead of the original instantiation of learned_dyn_model with

    learned_dyn_model = l4c.L4CasADi(MultiLayerPerceptron(), model_expects_batch_dim=True, name='learned_dyn'),

I replaced it with naive_mlp

naive_mlp = l4c.naive.MultiLayerPerceptron(2, 128, 1, 2, 'Tanh') learned_dyn_model = l4c.L4CasADi(naive_mlp, model_expects_batch_dim=True, name='learned_dyn')

because running the original file gives me an error about jit:

/Users/jing/opt/anaconda3/envs/building_mpc/lib/python3.9/site-packages/torch/jit/_check.py:178: UserWarning: The TorchScript type system doesn't support instance-level annotations on empty non-base types in __init__. Instead, either 1) use a type annotation in the class body, or 2) wrap the type in torch.jit.Attribute.

Thank! Jing

Tim-Salzmann commented 5 months ago

Hi Jing,

I replaced it with naive_mlp.

This is the culprit. If you use Naive L4CasADi, you will have to drop lines 156 and following in the original acados.py as there will be no generated dylib for Naive.

because running the original file gives me an error about jit

This is weird - it works fine for me. Could you tell me which PyTorch version you are using and getting this error for?

I pushed a minor change just now, which could possibly fix this problem. Let me know

Thanks Tim

jy-cds commented 5 months ago

Hi Tim,

I pulled the latest version. The jit problem persists. My PyTorch versions are

torch 2.0.1 pypi_0 pypi torchaudio 2.0.2 pypi_0 pypi torchvision 0.15.2 pypi_0 pypi

When I perform python -c "import torch; print(torch.__version__)" in the terminal in the l4casadi conda environment, I get 2.1.0.

Thanks, Jing

Tim-Salzmann commented 5 months ago

Hi Jing,

I am on 2.1.0 too. Can you send me the exact file contents you are getting the jit error for?

Also there is something weird going on: Your first statement suggests you are on torch 2.0.1 while your second statement suggests you are on 2.1.0.

Thanks Tim

jy-cds commented 5 months ago

Hi Tim,

I just added a version check in the code and indeed when the file runs it is suing 2.1.0. I'm not sure why when I do conda list it returns me other version of the torch.. I also want to mention that none of the other examples in the folder worked for me (they all throw the same jit error) as long as MultiLayerPerceptron(torch.nn.Module) was called.

The file that gives the jit error is pasted below:

import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"

import casadi as cs
import numpy as np
import torch
import l4casadi as l4c
from acados_template import AcadosOcpSolver, AcadosOcp, AcadosModel
import time
print(torch.__version__)

COST = 'LINEAR_LS'  # NONLINEAR_LS

class MultiLayerPerceptron(torch.nn.Module):
    def __init__(self):
        super().__init__()

        self.input_layer = torch.nn.Linear(2, 512)

        hidden_layers = []
        for i in range(2):
            hidden_layers.append(torch.nn.Linear(512, 512))

        self.hidden_layer = torch.nn.ModuleList(hidden_layers)
        self.out_layer = torch.nn.Linear(512, 1)

        # Model is not trained -- setting output to zero
        with torch.no_grad():
            self.out_layer.bias.fill_(0.)
            self.out_layer.weight.fill_(0.)

    def forward(self, x):
        x = self.input_layer(x)
        for layer in self.hidden_layer:
            x = torch.tanh(layer(x))
        x = self.out_layer(x)
        return x

class DoubleIntegratorWithLearnedDynamics:
    def __init__(self, learned_dyn):
        self.learned_dyn = learned_dyn

    def model(self):
        s = cs.MX.sym('s', 1)
        s_dot = cs.MX.sym('s_dot', 1)
        s_dot_dot = cs.MX.sym('s_dot_dot', 1)
        u = cs.MX.sym('u', 1)
        x = cs.vertcat(s, s_dot)
        x_dot = cs.vertcat(s_dot, s_dot_dot)

        res_model = self.learned_dyn(x)

        f_expl = cs.vertcat(
            s_dot,
            u
        ) + res_model

        x_start = np.zeros((2, ))

        # store to struct
        model = cs.types.SimpleNamespace()
        model.x = x
        model.xdot = x_dot
        model.u = u
        model.z = cs.vertcat([])
        model.p = cs.vertcat([])
        model.f_expl = f_expl
        model.x_start = x_start
        model.constraints = cs.vertcat([])
        model.name = "wr"

        return model

class MPC:
    def __init__(self, model, N, external_shared_lib_dir, external_shared_lib_name):
        self.N = N
        self.model = model
        self.external_shared_lib_dir = external_shared_lib_dir
        self.external_shared_lib_name = external_shared_lib_name

    @property
    def solver(self):
        return AcadosOcpSolver(self.ocp())

    def ocp(self):
        model = self.model

        t_horizon = 1.
        N = self.N

        # Get model
        model_ac = self.acados_model(model=model)
        model_ac.p = model.p

        # Dimensions
        nx = 2
        nu = 1
        ny = 1

        # Create OCP object to formulate the optimization
        ocp = AcadosOcp()
        ocp.model = model_ac
        ocp.dims.N = N
        ocp.dims.nx = nx
        ocp.dims.nu = nu
        ocp.dims.ny = ny
        ocp.solver_options.tf = t_horizon

        if COST == 'LINEAR_LS':
            # Initialize cost function
            ocp.cost.cost_type = 'LINEAR_LS'
            ocp.cost.cost_type_e = 'LINEAR_LS'

            ocp.cost.W = np.array([[1.]])

            ocp.cost.Vx = np.zeros((ny, nx))
            ocp.cost.Vx[0, 0] = 1.
            ocp.cost.Vu = np.zeros((ny, nu))
            ocp.cost.Vz = np.array([[]])
            ocp.cost.Vx_e = np.zeros((ny, nx))

            l4c_y_expr = None
        else:
            ocp.cost.cost_type = 'NONLINEAR_LS'
            ocp.cost.cost_type_e = 'NONLINEAR_LS'

            x = ocp.model.x

            ocp.cost.W = np.array([[1.]])

            # Trivial PyTorch index 0
            l4c_y_expr = l4c.L4CasADi(lambda x: x[0], name='y_expr', model_expects_batch_dim=False)

            ocp.model.cost_y_expr = l4c_y_expr(x)
            ocp.model.cost_y_expr_e = x[0]

        ocp.cost.W_e = np.array([[0.]])
        ocp.cost.yref_e = np.array([0.])

        # Initial reference trajectory (will be overwritten)
        ocp.cost.yref = np.zeros(1)

        # Initial state (will be overwritten)
        ocp.constraints.x0 = model.x_start

        # Set constraints
        a_max = 10
        ocp.constraints.lbu = np.array([-a_max])
        ocp.constraints.ubu = np.array([a_max])
        ocp.constraints.idxbu = np.array([0])

        # Solver options
        ocp.solver_options.qp_solver = 'FULL_CONDENSING_HPIPM'
        ocp.solver_options.hessian_approx = 'GAUSS_NEWTON'
        ocp.solver_options.integrator_type = 'ERK'
        ocp.solver_options.nlp_solver_type = 'SQP_RTI'
        ocp.solver_options.model_external_shared_lib_dir = self.external_shared_lib_dir
        if COST == 'LINEAR_LS':
            ocp.solver_options.model_external_shared_lib_name = self.external_shared_lib_name
        else:
            ocp.solver_options.model_external_shared_lib_name = self.external_shared_lib_name + ' -l' + l4c_y_expr.name

        return ocp

    def acados_model(self, model):
        model_ac = AcadosModel()
        model_ac.f_impl_expr = model.xdot - model.f_expl
        model_ac.f_expl_expr = model.f_expl
        model_ac.x = model.x
        model_ac.xdot = model.xdot
        model_ac.u = model.u
        model_ac.name = model.name
        return model_ac

def run():
    N = 10
    # naive_mlp = l4c.naive.MultiLayerPerceptron(2, 128, 1, 2, 'Tanh') 
    # learned_dyn_model = l4c.L4CasADi(naive_mlp, model_expects_batch_dim=True, name='learned_dyn')
    learned_dyn_model = l4c.L4CasADi(MultiLayerPerceptron(), model_expects_batch_dim=True, name='learned_dyn')

    model = DoubleIntegratorWithLearnedDynamics(learned_dyn_model)
    solver = MPC(model=model.model(), N=N,
                 external_shared_lib_dir=learned_dyn_model.shared_lib_dir,
                 external_shared_lib_name=learned_dyn_model.name).solver

    x = []
    x_ref = []
    ts = 1. / N
    xt = np.array([1., 0.])
    opt_times = []

    for i in range(50):
        now = time.time()
        t = np.linspace(i * ts, i * ts + 1., 10)
        yref = np.sin(0.5 * t + np.pi / 2)
        x_ref.append(yref[0])
        for t, ref in enumerate(yref):
            solver.set(t, "yref", ref)
        solver.set(0, "lbx", xt)
        solver.set(0, "ubx", xt)
        solver.solve()
        xt = solver.get(1, "x")
        x.append(xt)

        x_l = []
        for i in range(N):
            x_l.append(solver.get(i, "x"))

        elapsed = time.time() - now
        opt_times.append(elapsed)

    print(f'Mean iteration time: {1000*np.mean(opt_times):.1f}ms -- {1/np.mean(opt_times):.0f}Hz)')

if __name__ == '__main__':
    run()
Tim-Salzmann commented 5 months ago

Hi Jing,

The script you posted works for me on OSX with the latest L4CasADi and torch==2.1.0. Given that you seem to have some mixup within your virtual environments, are you sure that when you run the script, the latest L4CasADi version is used and not one you installed previously?

Could you add the following lines to the script and post the respective output:

import inspect
lines = inspect.getsource(l4c.L4CasADi)
print(lines)

Best Tim

jy-cds commented 5 months ago

Hi Tim,

I just checked and indeed for some reason my terminal environment is different from the vscode "run" button environment..! I tried to run all the examples and they all seem to run correctly (thank you!!), with one exception - naive/readme.py, where it now throws an error that says AttributeError: module 'l4casadi' has no attribute 'naive'. I made sure to perform a git pull in the correct environment. Putting the inspect lines you posted above in the naive/readme.py, I get the following output:


    def __init__(self,
                 model: Callable[[torch.Tensor], torch.Tensor],
                 model_expects_batch_dim: bool = True,
                 device: Union[torch.device, Text] = 'cpu',
                 name: Text = 'l4casadi_f',
                 build_dir: Text = './_l4c_generated'):
        """
        :param model: PyTorch model.
        :param model_expects_batch_dim: True if the PyTorch model expects a batch dimension. This is commonly True
            for trained PyTorch models.
        :param device: Device on which the PyTorch model is executed.
        :param name: Unique name of the generated L4CasADi model. This name is used for autogenerated files.
            Creating two L4CasADi models with the same name will result in overwriting the files of the first model.
        """
        self.model = model
        if isinstance(self.model, torch.nn.Module):
            self.model.eval().to(device)
            for parameters in self.model.parameters():
                parameters.requires_grad = False
        self.name = name
        self.has_batch = model_expects_batch_dim
        self.device = device if isinstance(device, str) else f'{device.type}:{device.index}'

        self.build_dir = pathlib.Path(build_dir)

        self._cs_fun: Optional[cs.Function] = None
        self._built = False

    def __call__(self, *args):
        return self.forward(*args)

    @property
    def shared_lib_dir(self):
        return self.build_dir.absolute().as_posix()

    def forward(self, inp: Union[cs.MX, cs.SX, cs.DM]):
        if self.has_batch:
            if not inp.shape[-1] == 1:   # type: ignore[attr-defined]
                raise ValueError("For batched PyTorch models only vector inputs are allowed.")

        if not self._built:
            self.build(inp)

        out = self._cs_fun(inp)  # type: ignore[misc]

        return out

    def maybe_make_generation_dir(self):
        if not os.path.exists(self.build_dir):
            os.makedirs(self.build_dir)

    def build(self, inp: Union[cs.MX, cs.SX, cs.DM]) -> None:
        """Builds the L4CasADi model as dynamic library.

        1. Exports the traced PyTorch model to TorchScript.
        2. Fills the C++ template with model parameters and paths to TorchScript.
        3. Compiles the C++ template to a dynamic library.
        4. Loads the dynamic library as CasADi external function.

        :param inp: Symbolic model input. Used to infer expected input shapes.
        """
        rows, cols = inp.shape  # type: ignore[attr-defined]

        self.maybe_make_generation_dir()
        has_jac, has_hess = self.export_torch_traces(rows, cols)

        if not has_jac:
            print('Jacobian trace could not be generated. First-order sensitivities will not be available in CasADi.')
        if not has_hess:
            print('Hessian trace could not be generated. Second-order sensitivities will not be available in CasADi.')

        self.generate_cpp_function_template(rows, cols, has_jac, has_hess)
        self.compile_cs_function()

        self._cs_fun = cs.external(
            f'{self.name}',
            f"{self.build_dir / f'lib{self.name}'}{dynamic_lib_file_ending()}"
        )
        self._built = True

    def generate_cpp_function_template(self, rows: int, cols: int, has_jac: bool, has_hess: bool):
        if self.has_batch:
            rows_out = self.model(torch.zeros(1, rows).to(self.device)).shape[-1]
            cols_out = 1
        else:
            out_shape = self.model(torch.zeros(rows, cols).to(self.device)).shape
            if len(out_shape) == 1:
                rows_out = out_shape[0]
                cols_out = 1
            else:
                rows_out, cols_out = out_shape[-2:]

        gen_params = {
            'model_path': self.build_dir.absolute().as_posix(),
            'device': self.device,
            'name': self.name,
            'rows_in': rows,
            'cols_in': cols,
            'rows_out': rows_out,
            'cols_out': cols_out,
            'has_jac': 'true' if has_jac else 'false',
            'has_hess': 'true' if has_hess else 'false',
            'model_expects_batch_dim': 'true' if self.has_batch else 'false',
        }

        render_casadi_c_template(
            variables=gen_params,
            out_file=(self.build_dir / f'{self.name}.cpp').as_posix()
        )

    def compile_cs_function(self):
        file_dir = files('l4casadi')
        include_dir = files('l4casadi') / 'include'
        lib_dir = file_dir / 'lib'

        # call gcc
        soname = 'install_name' if platform.system() == 'Darwin' else 'soname'
        os_cmd = ("gcc"
                  " -fPIC -shared"
                  f" {self.build_dir / self.name}.cpp"
                  f" -o {self.build_dir / f'lib{self.name}'}{dynamic_lib_file_ending()}"
                  f" -I{include_dir} -L{lib_dir}"
                  f" -Wl,-{soname},lib{self.name}{dynamic_lib_file_ending()}"
                  " -ll4casadi -lstdc++ -std=c++17"
                  " -D_GLIBCXX_USE_CXX11_ABI=0")

        status = os.system(os_cmd)
        if status != 0:
            raise Exception(f'Compilation failed!\n\nAttempted to execute OS command:\n{os_cmd}\n\n')

    def _trace_jac_model(self, inp):
        if self.has_batch:
            return make_fx(vmap(jacrev(self.model)))(inp)
        else:
            return make_fx(jacrev(self.model))(inp)

    def _trace_hess_model(self, inp):
        if self.has_batch:
            return make_fx(vmap(hessian(self.model)))(inp)
        else:
            return make_fx(hessian(self.model))(inp)

    def export_torch_traces(self, rows: int, cols: int) -> Tuple[bool, bool]:
        if self.has_batch:
            d_inp = torch.zeros((1, rows))
        else:
            d_inp = torch.zeros((rows, cols))
        d_inp = d_inp.to(self.device)

        out_folder = self.build_dir

        torch.jit.trace(self.model, d_inp).save((out_folder / f'{self.name}_forward.pt').as_posix())

        jac_model = self._trace_jac_model(d_inp)
        hess_model = self._trace_hess_model(d_inp)

        exported_jacrev = self._jit_compile_and_save(
            jac_model,
            (out_folder / f'{self.name}_jacrev.pt').as_posix(),
            d_inp
        )
        exported_hess = self._jit_compile_and_save(
            hess_model,
            (out_folder / f'{self.name}_hess.pt').as_posix(),
            d_inp
        )

        return exported_jacrev, exported_hess

    @staticmethod
    def _jit_compile_and_save(model, file_path: str, dummy_inp: torch.Tensor):
        # Try tracing
        try:
            torch.jit.trace(model, dummy_inp).save(file_path)
        except:  # noqa
            # Try scripting
            try:
                ts_compile(model).save(file_path)
            except:  # noqa
                return False
        return True

Traceback (most recent call last):
  File "/Users/jing/l4casadi/examples/naive/readme.py", line 11, in <module>
    naive_mlp = l4c.naive.MultiLayerPerceptron(2, 128, 1, 2, 'Tanh')
AttributeError: module 'l4casadi' has no attribute 'naive' ```
Tim-Salzmann commented 5 months ago

Hi Jing,

Your environment is still mixed up, where your scripts include an old version of L4CasADi (apparently, one before I added Naive L4CasADi). You can check the location of the old L4CasADi installation the scripts are using by adding the following line in one of them.

print(l4c.l4casadi.__file__)

Best Tim

jy-cds commented 5 months ago

Hi Tim,

The output is /Users/jing/opt/anaconda3/envs/new_l4casadi/lib/python3.9/site-packages/l4casadi/l4casadi.py, which looks correct to me (correct conda env name). Searching a bit around the internet I do not see any other way to update the package other than activating the correct conda env then perform git pull. The only other way it seems is to delete the current github package and reinstall with git clone. Do you suggest I do this?

Thank you! Jing

Tim-Salzmann commented 5 months ago

Hi Jing,

Pulling the git within an activated conda environment will not update the installed package in the environment. To update the installed package, you will have to re-run pip install . --no-build-isolation within the activated environment after you pulled the latest version.

Best Tim

jy-cds commented 5 months ago

I see! I'm running into weird errors when I performed your line as pip3 install l4casadi --no-build-isolation, with #egg=l4casadi fragments error:

Defaulting to user installation because normal site-packages is not writeable
Collecting l4casadi
  Using cached l4casadi-1.3.0.tar.gz (11.6 MB)
  Preparing metadata (pyproject.toml) ... done
  WARNING: Generating metadata for package l4casadi produced metadata for project name unknown. Fix your #egg=l4casadi fragments.
Discarding https://files.pythonhosted.org/packages/57/89/f3e71bdb49554dca5784630ffd323f1ea62e11471b0c8f1bcbb74533e028/l4casadi-1.3.0.tar.gz (from https://pypi.org/simple/l4casadi/) (requires-python:>=3.9): Requested unknown from https://files.pythonhosted.org/packages/57/89/f3e71bdb49554dca5784630ffd323f1ea62e11471b0c8f1bcbb74533e028/l4casadi-1.3.0.tar.gz has inconsistent name: expected 'l4casadi', but metadata has 'unknown'
  Using cached l4casadi-1.2.0.tar.gz (23 kB)
  Preparing metadata (pyproject.toml) ... done
  WARNING: Generating metadata for package l4casadi produced metadata for project name unknown. Fix your #egg=l4casadi fragments.
Discarding https://files.pythonhosted.org/packages/61/31/c46b81a6d3b238adc5587186195a4453e12275e161e26808bc46b45722e2/l4casadi-1.2.0.tar.gz (from https://pypi.org/simple/l4casadi/) (requires-python:>=3.9): Requested unknown from https://files.pythonhosted.org/packages/61/31/c46b81a6d3b238adc5587186195a4453e12275e161e26808bc46b45722e2/l4casadi-1.2.0.tar.gz has inconsistent name: expected 'l4casadi', but metadata has 'unknown'
  Using cached l4casadi-1.1.1.tar.gz (24 kB)
  Preparing metadata (pyproject.toml) ... done
  WARNING: Generating metadata for package l4casadi produced metadata for project name unknown. Fix your #egg=l4casadi fragments.
Discarding https://files.pythonhosted.org/packages/ff/38/e7599ed8681503252834337de5b343e40e5e85796d6fc99bbbf06b5a029b/l4casadi-1.1.1.tar.gz (from https://pypi.org/simple/l4casadi/) (requires-python:>=3.9): Requested unknown from https://files.pythonhosted.org/packages/ff/38/e7599ed8681503252834337de5b343e40e5e85796d6fc99bbbf06b5a029b/l4casadi-1.1.1.tar.gz has inconsistent name: expected 'l4casadi', but metadata has 'unknown'
  Using cached l4casadi-1.0.0.tar.gz (18 kB)
  Preparing metadata (pyproject.toml) ... done
  WARNING: Generating metadata for package l4casadi produced metadata for project name unknown. Fix your #egg=l4casadi fragments.
Discarding https://files.pythonhosted.org/packages/2b/ca/ec23f2a8d0804f9f47f092260ad4f6e8eb3fb9cccaed12cdaaf08f017296/l4casadi-1.0.0.tar.gz (from https://pypi.org/simple/l4casadi/) (requires-python:>=3.9): Requested unknown from https://files.pythonhosted.org/packages/2b/ca/ec23f2a8d0804f9f47f092260ad4f6e8eb3fb9cccaed12cdaaf08f017296/l4casadi-1.0.0.tar.gz has inconsistent name: expected 'l4casadi', but metadata has 'unknown'
ERROR: Could not find a version that satisfies the requirement l4casadi (from versions: 1.0.0, 1.1.1, 1.2.0, 1.3.0)
ERROR: No matching distribution found for l4casadi

I'm not sure why "unknown" was part of the metadata. What I ended trying was directly pip install l4casadi and the terminal kind of got stuck at installing build dependencies...

pip3 install l4casadi Defaulting to user installation because normal site-packages is not writeable Collecting l4casadi Using cached l4casadi-1.3.0.tar.gz (11.6 MB) Installing build dependencies ... -

Tim-Salzmann commented 5 months ago

Hi Jing,

If you execute pip install l4casadi --no-build-isolation pip will download the latest release version (this is not the same as the latest github state) from PyPi. One reason this fails could be that your pip or setuptools is not up to date or your python version is < 3.9:

pip3 install --upgrade pip setuptools

If you want to install the latest github state, you will have to clone/pull the repository and run the following in the cloned folder:

pip install . --no-build-isolation

Note the . for local

pip install l4casadi without --no-build-isolation will not work.

Best Tim

jy-cds commented 5 months ago

Hi Tim,

Got it! I think I can take it from here.. Thank you so much for taking the time to help debug my setup!!

Best, Jing