sparse-ir-capi 0.7.0

C API for SparseIR Rust implementation
Documentation

SparseIR C-API

C-compatible interface to the SparseIR Rust library.

Overview

This crate provides a libsparseir-compatible C API for the SparseIR library, designed as a drop-in replacement for the C++ implementation.

Language Support

  • Julia βœ… (tested)
  • Python (via ctypes/cffi)
  • Fortran (via ISO_C_BINDING)
  • C/C++

Compatibility with libsparseir C++ πŸ”„

This API is 100% compatible with the libsparseir C++ library:

Feature libsparseir C++ sparse-ir-capi Rust Status
Type name spir_kernel spir_kernel βœ… Identical
Function names spir_logistic_kernel_new() spir_logistic_kernel_new() βœ… Identical
Error codes SPIR_COMPUTATION_SUCCESS, etc. Same codes βœ… Identical
Memory model Opaque pointers Opaque pointers βœ… Compatible
Function signature spir_kernel* f(..., int* status) spir_kernel* f(..., int* status) βœ… Identical

Why choose Rust over C++?

  • πŸ”’ Memory safety - No use-after-free, no double-free
  • πŸ›‘οΈ Panic safety - catch_unwind() prevents crashes
  • πŸš€ Zero-cost abstractions - Same performance as C++
  • πŸ“¦ Easy deployment - Single static library, no C++ runtime needed

Features

Currently Implemented βœ…

  • Kernel API (5 functions) - libsparseir compatible
    • spir_logistic_kernel_new() - Create LogisticKernel
    • spir_reg_bose_kernel_new() - Create RegularizedBoseKernel
    • spir_kernel_release() - Free kernel
    • spir_kernel_get_lambda() - Get Ξ» parameter
    • spir_kernel_compute() - Compute K(x, y)

Error Handling πŸ›‘οΈ

All C-API functions use catch_unwind() to prevent panics from crossing the FFI boundary:

  • Returns error codes instead of panicking
  • Process remains stable even on internal errors
  • Safe for production use

Building

# Build shared library (.dylib on macOS, .so on Linux, .dll on Windows)
# The C header is automatically generated by cbindgen during build
cargo build --release

# Run tests
cargo test

Header Generation

The C header (include/sparseir.h) is automatically generated from Rust source code using cbindgen:

  • Build time: Header is regenerated automatically when Rust sources change
  • Manual regeneration: cargo build (header is created by build.rs)
  • Configuration: See cbindgen.toml for generation settings

Do not edit the generated header manually - edit the Rust source code instead!

Usage Examples

Julia

# Load library
const lib = "../target/release/libsparse_ir_capi.dylib"

# Create kernel
kernel_ptr = Ref{Ptr{Cvoid}}()
status = ccall((:spir_kernel_logistic_new, lib),
               Int32, (Float64, Ref{Ptr{Cvoid}}),
               10.0, kernel_ptr)

# Compute kernel value
result = Ref{Float64}()
status = ccall((:spir_kernel_compute, lib),
               Int32, (Ptr{Cvoid}, Float64, Float64, Ref{Float64}),
               kernel_ptr[], 0.5, 0.5, result)

println("K(0.5, 0.5) = ", result[])

# Release
ccall((:spir_kernel_release, lib), Cvoid, (Ptr{Cvoid},), kernel_ptr[])

See examples/test_julia.jl for a complete example.

C

#include "sparseir.h"
#include <stdio.h>

int main() {
    // libsparseir compatible API
    int status;
    spir_kernel* kernel = spir_logistic_kernel_new(10.0, &status);

    if (kernel == NULL || status != SPIR_COMPUTATION_SUCCESS) {
        fprintf(stderr, "Failed to create kernel: status = %d\n", status);
        return 1;
    }

    double result;
    status = spir_kernel_compute(kernel, 0.5, 0.5, &result);
    printf("K(0.5, 0.5) = %f\n", result);

    spir_kernel_release(kernel);
    return 0;
}

Testing

Run the Julia example:

cd examples
julia test_julia.jl

Memory Management

All objects returned by *_new() functions must be released with their corresponding *_release() function:

  • spir_kernel_release()
  • (more to come: spir_basis_release(), etc.)

Error Codes

Code Name Description
0 SPIR_SUCCESS Operation succeeded
-1 SPIR_ERROR_NULL_POINTER NULL pointer argument
-2 SPIR_ERROR_INVALID_ARGUMENT Invalid argument value
-99 SPIR_ERROR_PANIC Internal panic (bug)

Implementation Status

  • Kernel API (5/5 functions) βœ…
  • SVE API (0/10 functions)
  • Basis API (0/15 functions)
  • Sampling API (0/15 functions)
  • DLR API (0/8 functions)

See C-API_IMPLEMENTATION_PLAN.md for details.

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Julia/Python β”‚  ← High-level languages
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚ ccall/ctypes
β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”
β”‚   C-API      β”‚  ← This crate (FFI boundary)
β”‚ catch_unwind β”‚  ← Panic protection
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚
β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”
β”‚ sparseir-rustβ”‚  ← Core Rust implementation
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Safety Features

  1. Input Validation - User errors return error codes (don't panic)
  2. Panic Catching - catch_unwind() at FFI boundary prevents UB
  3. Arc-based Sharing - Efficient memory management for large objects
  4. Type Safety - Opaque pointers hide implementation details

License

MIT