Leidenfold

Elixir bindings for the Leiden community detection algorithm via libleidenalg.

The Leiden algorithm is a state-of-the-art method for detecting communities in networks. It guarantees well-connected communities and runs significantly faster than the Louvain algorithm.

Installation

Add leidenfold to your list of dependencies in mix.exs:

def deps do
[
{:leidenfold, "~> 0.4"}
]
end

Precompiled binaries are available for:

No additional setup is required for these platforms.

Building from Source

If precompiled binaries are not available for your platform, or you want to build from source, set LEIDENFOLD_BUILD=true and install the prerequisites:

macOS
# Install igraph via Homebrew
brew install igraph
# Build and install libleidenalg
git clone https://github.com/vtraag/libleidenalg.git
cd libleidenalg
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/.local
make -j4
make install
# Build leidenfold from source
LEIDENFOLD_BUILD=true mix deps.compile leidenfold
Linux (Ubuntu/Debian)
# Install igraph
sudo apt-get install libigraph-dev
# Build and install libleidenalg
git clone https://github.com/vtraag/libleidenalg.git
cd libleidenalg
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/.local
make -j4
make install
# Build leidenfold from source
LEIDENFOLD_BUILD=true mix deps.compile leidenfold
Linux (Fedora/RHEL)
# Install igraph
sudo dnf install igraph-devel
# Build and install libleidenalg
git clone https://github.com/vtraag/libleidenalg.git
cd libleidenalg
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/.local
make -j4
make install
# Build leidenfold from source
LEIDENFOLD_BUILD=true mix deps.compile leidenfold

Usage

# Basic usage with edge tuples
# Two triangles connected by edge 2-3:
# 0 3
# / \ / \
# 1---2 --------- 4---5
edges = [{0, 1}, {1, 2}, {2, 0}, {3, 4}, {4, 5}, {5, 3}, {2, 3}]
{:ok, result} = Leidenfold.detect_from_edges(edges)
# => {:ok, %{membership: [0, 0, 0, 1, 1, 1], n_communities: 2, quality: 0.0}}
# Nodes 0,1,2 form community 0; nodes 3,4,5 form community 1
# Same graph using source/target lists (pairs source[i] -> target[i])
sources = [0, 1, 2, 3, 4, 5, 2]
targets = [1, 2, 0, 4, 5, 3, 3]
{:ok, result} = Leidenfold.detect(sources, targets)
# With options
{:ok, result} = Leidenfold.detect(sources, targets,
objective: :modularity, # or :cpm, :rber, :rbc, :significance, :surprise
resolution: 1.0,
iterations: 2,
seed: 42
)
# Weighted edges
weighted_edges = [{0, 1, 1.0}, {1, 2, 2.0}, {2, 0, 1.5}]
{:ok, result} = Leidenfold.detect_from_weighted_edges(weighted_edges)
# Bang version that raises on error
result = Leidenfold.detect!(sources, targets)

Quality Functions

Options

Option Type Default Description
:weights [float] nil Edge weights
:n_nodes integer auto Number of nodes (inferred if not specified)
:directed boolean false Whether graph is directed
:objective atom :cpm Quality function to optimize
:resolution float 1.0 Resolution parameter for CPM/RBER/RBC
:iterations integer 2 Number of optimization iterations
:seed integer 0 Random seed (0 = random)

Result

The detect functions return a map with:

Contributing

Dependencies

Leidenfold builds against these native libraries (statically linked in precompiled binaries):

Development Setup

To build and test locally:

# Install build dependencies (macOS)
brew install cmake automake autoconf libtool bison flex
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Clone the repo
git clone https://github.com/georgeguimaraes/leidenfold.git
cd leidenfold
# Build igraph from source (static)
git clone --depth 1 --branch 0.10.15 https://github.com/igraph/igraph.git
cd igraph && mkdir build && cd build
cmake .. \
-DCMAKE_INSTALL_PREFIX="$HOME/.local" \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-DBUILD_SHARED_LIBS=OFF \
-DIGRAPH_USE_INTERNAL_BLAS=ON \
-DIGRAPH_USE_INTERNAL_LAPACK=ON \
-DIGRAPH_USE_INTERNAL_ARPACK=ON \
-DIGRAPH_USE_INTERNAL_GLPK=ON \
-DIGRAPH_USE_INTERNAL_GMP=ON
make -j$(sysctl -n hw.ncpu)
make install
cd ../..
# Build libleidenalg from source (static)
git clone --depth 1 --branch 0.11.1 https://github.com/vtraag/libleidenalg.git
cd libleidenalg && mkdir build && cd build
cmake .. \
-DCMAKE_INSTALL_PREFIX="$HOME/.local" \
-DCMAKE_PREFIX_PATH="$HOME/.local" \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON \
-DBUILD_SHARED_LIBS=OFF
make -j$(sysctl -n hw.ncpu)
make install
cd ../..
# Build and test
mix deps.get
LEIDENFOLD_BUILD=true \
LEIDENFOLD_STATIC_LIB_PATH="$HOME/.local/lib" \
LEIDENFOLD_STATIC_INCLUDE_PATH="$HOME/.local/include" \
mix test

CI Pipeline

The CI pipeline runs on GitHub Actions:

  1. Test job - Runs on Linux with Elixir 1.20 / OTP 29, Elixir 1.19 / OTP 28 and Elixir 1.18 / OTP 27
  2. Build and Publish - Triggered on version tags (v*), builds precompiled NIFs:
    • macOS ARM64 (Apple Silicon)
    • Linux x86_64
    • Linux ARM64
  3. Release - Uploads artifacts to GitHub Releases
  4. Checksums - Auto-generates and commits checksum file
  5. Hex Publish - Publishes to hex.pm

NIFs are built for NIF versions 2.15, 2.16, and 2.17 to support OTP 22+.

License

MIT