sparse-ir-capi 0.8.0

C API for SparseIR Rust implementation
Documentation
# SparseIR C-API

[![Crates.io](https://img.shields.io/crates/v/sparse-ir-capi.svg)](https://crates.io/crates/sparse-ir-capi)
[![Documentation](https://docs.rs/sparse-ir-capi/badge.svg)](https://docs.rs/sparse-ir-capi)
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/License-MIT%20OR%20Apache--2.0-blue.svg)](https://opensource.org/licenses/MIT)

This crate provides a C API for the SparseIR library.

### Language Support
- Fortran (via ISO_C_BINDING)
- Julia (via ccall)
- Python (via ctypes)
- C/C++
- Other languages that can call C ABIs

## Features

### Currently Implemented

See the header file for the complete API: [include/sparseir/sparseir.h](include/sparseir/sparseir.h)

### Sampling: Supported Type Patterns

The C-API provides `eval` (coefficients → values) and `fit` (values → coefficients) functions with different type combinations. The suffix indicates input/output types:
- `d` = double (f64, real)
- `z` = double complex (Complex64)

#### Evaluate Functions (Coefficients → Values)

| Function | Tau | Matsubara (full) | Matsubara (positive_only) |
|----------|:---:|:----------------:|:-------------------------:|
| `spir_sampling_eval_dd` ||||
| `spir_sampling_eval_dz` ||||
| `spir_sampling_eval_zz` ||| ✅* |

#### Fit Functions (Values → Coefficients)

| Function | Tau | Matsubara (full) | Matsubara (positive_only) |
|----------|:---:|:----------------:|:-------------------------:|
| `spir_sampling_fit_dd` ||||
| `spir_sampling_fit_zd` || ✅* ||
| `spir_sampling_fit_zz` ||| ✅** |

\* For Matsubara (full), `fit_zd` internally fits complex coefficients and returns their real parts. This is physically correct for Green's functions where IR coefficients are guaranteed to be real by symmetry.

\*\* For Matsubara (positive_only), `fit_zz` internally fits to real coefficients and converts to complex with zero imaginary parts. This is valid because IR coefficients are guaranteed to be real for physical Green's functions.

\* For Matsubara (positive_only), `eval_zz` extracts real parts from input coefficients and evaluates. This is valid because IR coefficients are guaranteed to be real for physical Green's functions.

#### Notes

- **Tau sampling**: Uses real transformation matrix. Supports `dd` for real data, `zz` for complex data (real/imag parts transformed independently).
- **Matsubara (full)**: Uses complex transformation matrix with both positive and negative frequencies. Natural type is `zz`. The `dz` evaluate is supported for real coefficients (physically guaranteed for Green's functions).
- **Matsubara (positive_only)**: Uses only positive frequencies with complex matrix but real coefficients. Natural types are `dz` (evaluate) and `zd` (fit). Also supports `zz` variants by extracting/adding zero imaginary parts.

### 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

```bash
# 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
```

### Installation

Install the header and shared library to your system:

```bash
# Install cargo-c (first time only)
cargo install cargo-c

# Install header and shared library to system directories
cargo cinstall --release

# Or install to a custom prefix
cargo cinstall --release --prefix /custom/path
```

By default, `cargo cinstall` installs to:
- **Header**: `/usr/local/include/sparse_ir_capi/sparse_ir_capi.h` (Linux/macOS)
- **Library**: `/usr/local/lib/libsparse_ir_capi.so` (Linux) or `.dylib` (macOS)
- **Static library**: `/usr/local/lib/libsparse_ir_capi.a`
- **pkg-config**: `/usr/local/lib/pkgconfig/sparse_ir_capi.pc`

After installation, you can use pkg-config to find the library:
```bash
pkg-config --cflags --libs sparse-ir-capi
```

**Note on Header Files**: 

The header file `include/sparseir/sparseir.h` is automatically generated by `cbindgen` during `cargo build` with C++ compatibility enabled (`--cpp-compat` flag). The header is used directly without post-processing.

The `Cargo.toml` is configured with `generation = false` so that `cargo cinstall` uses the header from `assets/sparse_ir_capi.h`. This file is a copy of `include/sparseir/sparseir.h` and is maintained in the repository (not generated by `build.rs` to avoid `cargo publish` issues).

**Do not manually edit** `include/sparseir/sparseir.h` - it is automatically generated and will be overwritten on the next build. When the header changes, update `assets/sparse_ir_capi.h` manually or via CI/CD.

### Header Generation

The C header (`include/sparseir/sparseir.h`) is **automatically generated** from Rust source code using [cbindgen](https://github.com/mozilla/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

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

# Create kernel
kernel_ptr = Ref{Ptr{Cvoid}}()
status = ccall((:spir_logistic_kernel_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

```c
#include "sparseir/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:
```bash
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.)

All objects are immutable and thread-safe.

## License

This crate is dual-licensed under the terms of the MIT license and the Apache License (Version 2.0).

- You may use this crate under the terms of either license, at your option:
  - [MIT License]../LICENSE
  - [Apache License 2.0]../LICENSE-APACHE