archimedes.codegen¶
- archimedes.codegen(
- func: Callable | FunctionCache,
- args: Sequence[Any],
- static_argnums: int | Sequence[int] | None = None,
- static_argnames: str | Sequence[str] | None = None,
- return_names: Sequence[str] | None = None,
- kwargs: dict[str, Any] | None = None,
- float_type: type = float,
- int_type: type = int,
- input_descriptions: dict[str, str] | None = None,
- output_descriptions: dict[str, str] | None = None,
- output_dir: str | None = None,
- options: dict[str, Any] | None = None,
- debug: bool = False,
Generate C/C++ code from a compiled function.
Creates standalone C or C++ code that implements the computational graph defined by the function. This allows Archimedes models to be deployed on embedded systems, integrated into C/C++ codebases, or compiled to native executables for maximum performance.
For a detailed description of the codegen functionality, see the guide to code generation and hardware deployment.
- Parameters:
func (Callable | FunctionCache) – The compiled function to generate code for. If not already a FunctionCache, it will be compiled automatically.
args (tuple) –
Arguments to the function that specify shapes and dtypes. These can be:
SymbolicArray objects
NumPy arrays with the same shape and dtype as expected inputs
[tree-structured data types](../../trees.md) matching expected inputs
The actual values for static arguments
Note: For dynamic arguments, the numeric values are ignored.
static_argnums (tuple, optional) – The indices of the static arguments to the function. Will be ignored if func is already a FunctionCache.
static_argnames (tuple, optional) – The names of the static arguments to the function. Will be ignored if func is already a FunctionCache.
return_names (tuple, optional) – The names of the return values of the function. Ignored if func is already a FunctionCache. For the sake of readability, this argument is required to be provided, either directly or when separately compiling the function to a FunctionCache.
kwargs (dict, optional) – Keyword arguments to pass to the function during specialization.
float_type (type, default=float) – The C type to use for floating point numbers.
int_type (type, default=int) – The C type to use for integers.
input_descriptions (dict[str, str], optional) – Descriptions for the input arguments. Used for generating comments in the code.
output_descriptions (dict[str, str], optional) – Descriptions for the output values. Used for generating comments in the code.
output_dir (str, optional) – Path where the generated code will be written.
options (dict, optional) –
Additional options for code generation. This can include:
verbose: If True, include additional comments in the generated code.
with_mem: If True, generate a simplified C API with memory helpers.
indent: The number of spaces to use for indentation in the generated code.
debug (bool, default=False) – If True, print debugging information about the codegen process. Useful for development purposes only and subject to removal in future versions.
- Returns:
The function writes the generated code to the specified file(s).
- Return type:
None
Notes
Use this for:
Deploying models on embedded systems or hardware without Python
Integrating Archimedes algorithms into C/C++ applications
Maximum runtime performance by removing Python interpreter overhead
Creating standalone, portable implementations of your algorithm
This function specializes the computational graph of
func
to specific input shapes and types, then uses CasADi’s code generation capabilities to produce C code that implements the same computation. The generated code has no dependencies on Archimedes, CasADi, or Python.Currently, this function uses CasADi’s code generation directly, so the generated code will contain
CASADI_*
prefixes and follow CasADi’s conventions. The function will also generate an “interface” API layer with struct definitions for inputs and outputs, along with convenience functions for initialization and function calls.Generated API
The codegen guide has a detailed description of how to use the generated API. In short, a Python function named
func
will generate three top-level C structs:func_arg_t
: Arguments tofunc
func_res_t
: Return values offunc
func_work_t
: Pre-allocated temporary workspace variables
There will also be two generated functions:
func_init
: Initializes the argument and workspace structsfunc_step
: Calls the main computation function
The basic pattern for using this API is:
// Allocate all structs on the stack func_arg_t arg; func_res_t res; func_work_t work; func_init(&arg, &res, &work); // Initialize using the template values func_step(&arg, &res, &work); // Numerically evaluate the function
If the function is “stateful”, meaning some outputs are recursively looped back to the inputs, manual copying of the state will be required. See below for details.
Numerical constants
To store numerical constants in the generated code, either:
“Close over” the values in your function definition
Pass them as hashable static arguments (same effect as a closure)
Pass as “dynamic” arguments that could be edited in the generated code
Support for structured data types
The code generation system supports structured data types, either as homogeneous arrays (lists or tuples with all elements of the same type) or as heterogeneous containers (e.g. dictionaries, named tuples, or
struct()
classes. The former will be represented as C arrays, while the latter will be represented as C structs.For example, a struct argument defined with
@struct class Point: x: float y: float
will autogenerate a C struct:
typedef struct { float x; float y; } point_t;
Stateful functions
A common pattern for dynamics models or control algorithms is to have functions that implement a generic discrete-time state-space model of the form
\[ \begin{align}\begin{aligned}x_{k+1} = f(x_k, u_k)\\y_k = g(x_k, u_k)\end{aligned}\end{align} \]This can be combined into a single function with the signature
func(x[k], u[k]) -> (x[k+1], y[k])
. When working with functions of this form (or any similar stateful functions), the generated code will still be “functionally pure”, meaning that the result data will storex[k+1]
and the argument data will storex[k]
, but the updated state will not automatically be copied back to the input.If the state is implemented as a @struct, it will correspond to a C struct and the copy operation can be implemented simply using direct copy semantics. For example, a function with the signature
func(state, inputs) -> (state_new, outputs)
for which the state is a @struct (or dict, or named tuple) will generate a C struct namedstate_t
. Thearg
structure will include a fieldstate
, and theres
structure will include a fieldstate_new
, both of which have typestate_t
. With direct assignment copying, the updated state can be copied back to the input witharg.state = res.state_new;
Examples
>>> import numpy as np >>> import archimedes as arc >>> >>> # Define a simple function >>> @arc.compile ... def rotate(x, theta): ... R = np.array([ ... [np.cos(theta), -np.sin(theta)], ... [np.sin(theta), np.cos(theta)], ... ], like=x) ... return R @ x >>> >>> # Create templates with appropriate shapes and dtypes >>> x_type = np.zeros((2,), dtype=float) >>> theta_type = np.array(0.0, dtype=float) >>> >>> # Generate C code >>> arc.codegen(rotate, (x_type, theta_type))
The above code will generate files including ‘rotate.c’ and ‘rotate.h’ that implement the rotation function in C.
To use numerical constants, declaring arguments as static will fix the value in the generated code:
>>> @arc.compile(static_argnames=("scale",)) ... def scaled_rotation(x, theta, scale=2.0): ... R = np.array([ ... [np.cos(theta), -np.sin(theta)], ... [np.sin(theta), np.cos(theta)], ... ], like=x) ... return scale * (R @ x) >>> >>> arc.codegen(scaled_rotation, (x_type, theta_type, 5.0))
See also
compile
Create a compiled function for use with codegen