LOBPCG (Locally Optimal Block Preconditioned Conjugate Gradient) iterative eigensolver for Zig.
- Large sparse Hermitian eigenvalue problems - computes a few smallest eigenvalues efficiently
- Standard and generalized problems: Hx = lambdax and Hx = lambdaS*x
- Generic operator interface - supply your own matrix-vector product via function pointers
- Serial and parallel implementations (thread pool)
- SIMD-optimized complex vector operations
- BLAS/LAPACK bindings (macOS Accelerate / OpenBLAS)
Add to your build.zig.zon:
.dependencies = .{
.lobpcg = .{
.url = "https://github.com/soyukke/zig-lobpcg/archive/main.tar.gz",
.hash = "...", // run `zig fetch` to get this
},
},Then in build.zig:
const lobpcg_dep = b.dependency("lobpcg", .{
.target = target,
.optimize = optimize,
});
your_module.addImport("lobpcg", lobpcg_dep.module("lobpcg"));const lobpcg = @import("lobpcg");
// Define your matrix-vector product
fn matvec(ctx: *anyopaque, x: []const lobpcg.Complex, y: []lobpcg.Complex) !void {
// y = A * x
const matrix = @as(*MyMatrix, @ptrCast(@alignCast(ctx)));
matrix.apply(x, y);
}
// Set up the operator
const op = lobpcg.Operator{
.n = matrix_size,
.ctx = @ptrCast(&my_matrix),
.apply = matvec,
};
// Solve for the 4 smallest eigenvalues
var result = try lobpcg.solve(allocator, op, .{
.nbands = 4,
.tol = 1e-8,
.max_iter = 200,
});
defer result.deinit(allocator);
// result.values contains eigenvalues
// result.vectors contains eigenvectorsconst op = lobpcg.Operator{
.n = matrix_size,
.ctx = @ptrCast(&my_context),
.apply = matvec_H,
.apply_s = matvec_S, // overlap operator
};var pool = try lobpcg.ThreadPool.init(allocator, 4);
defer pool.deinit();
var result = try lobpcg.solveParallel(allocator, op, .{
.nbands = 4,
.tol = 1e-8,
}, &pool);- macOS: Accelerate framework (linked automatically)
- Linux: OpenBLAS + LAPACK
# Linux: pass OpenBLAS paths if not in default locations
zig build -Dopenblas-include=/path/to/include -Dopenblas-lib=/path/to/libzig build # build library
zig build test # run testsMIT