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.2.0"}
  ]
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 ```bash # 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) ```bash # 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) ```bash # 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_nodesinteger auto Number of nodes (inferred if not specified)
:directedbooleanfalse Whether graph is directed
:objectiveatom:cpm Quality function to optimize
:resolutionfloat1.0 Resolution parameter for CPM/RBER/RBC
:iterationsinteger2 Number of optimization iterations
:seedinteger0 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 OTP 26/27/28 and Elixir 1.17/1.18/1.19 (8 combinations)
  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