{"id":50222237,"url":"https://github.com/thanos/ex_graphblas","last_synced_at":"2026-05-26T12:51:20.778Z","repository":{"id":352679609,"uuid":"1215238465","full_name":"thanos/ex_graphblas","owner":"thanos","description":"ex_graphblas` is an Elixir library for sparse linear algebra and graph computation inspired by the GraphBLAS model","archived":false,"fork":false,"pushed_at":"2026-04-20T16:34:32.000Z","size":86,"stargazers_count":0,"open_issues_count":8,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-20T18:38:39.118Z","etag":null,"topics":["blas","elixir","graphdb","graphs","linear-algebra","matrix","nx"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thanos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-19T16:58:15.000Z","updated_at":"2026-04-19T17:18:22.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/thanos/ex_graphblas","commit_stats":null,"previous_names":["thanos/ex_graphblas"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/thanos/ex_graphblas","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanos%2Fex_graphblas","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanos%2Fex_graphblas/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanos%2Fex_graphblas/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanos%2Fex_graphblas/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thanos","download_url":"https://codeload.github.com/thanos/ex_graphblas/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thanos%2Fex_graphblas/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33521333,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T03:12:49.672Z","status":"ssl_error","status_checked_at":"2026-05-26T03:12:47.976Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blas","elixir","graphdb","graphs","linear-algebra","matrix","nx"],"created_at":"2026-05-26T12:51:20.034Z","updated_at":"2026-05-26T12:51:20.770Z","avatar_url":"https://github.com/thanos.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GraphBLAS\n\nAn Elixir library for sparse linear algebra and graph computation, inspired by the GraphBLAS standard.\n\n[![Hex.pm](https://img.shields.io/hexpm/v/ex_graphblas.svg)](https://hex.pm/packages/ex_graphblas)\n[![Hex.pm](https://img.shields.io/hexpm/dt/ex_graphblas.svg)](https://hex.pm/packages/ex_graphblas)\n[![Hex.pm](https://img.shields.io/hexpm/l/ex_graphblas.svg)](https://hex.pm/packages/ex_graphblas)\n[![HexDocs.pm](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/ex_graphblas)\n[![Precompiled NIFs](https://github.com/thanos/ex_graphblas/actions/workflows/precompiled-nifs.yml/badge.svg)](https://github.com/thanos/ex_graphblas/actions/workflows/precompiled-nifs.yml)\n\nGraphBLAS provides idiomatic Elixir data structures at the boundary while delegating computation to swappable backends. The same code runs on a pure Elixir reference backend for development and testing, and on SuiteSparse:GraphBLAS via Zigler NIFs for native performance in production.\n\n## Contents\n\n- [Features](#features)\n- [Architecture](#architecture)\n- [Quick start](#quick-start)\n- [Use cases](#use-cases)\n- [Built-in semirings](#built-in-semirings)\n- [Graph algorithms](#graph-algorithms)\n- [Installation](#installation)\n- [Guides](#guides)\n- [Status](#status)\n- [License](#license)\n\n## Features\n\n- **Sparse matrices and vectors** -- COO construction, inspection, element-wise operations\n- **12 built-in semirings** -- `plus_times`, `plus_min`, `lor_land`, `min_plus`, and type-specific variants\n- **Graph algorithms** -- BFS reachability, BFS levels, SSSP, triangle count, connected components, degree, PageRank\n- **Knowledge graph queries** -- `GraphBLAS.Relation` module with multi-predicate traversal and transitive closure\n- **Masked operations** -- structural and complement masks on all compute operations\n- **Backend selection** -- per-call or application config; structs carry their backend for correct dispatch\n- **3 scalar types** -- `:int64`, `:fp64`, `:bool`\n- **470 tests**, property-based testing via StreamData\n\n## Architecture\n\nGraphBLAS separates the public API from the computation engine via a backend behaviour:\n\n```\nGraphBLAS.Matrix / GraphBLAS.Vector    -- public API (backend-neutral)\nGraphBLAS.Backend                      -- behaviour defining the computation contract\nGraphBLAS.Backend.Elixir               -- pure Elixir reference implementation\nGraphBLAS.Backend.SuiteSparse          -- SuiteSparse:GraphBLAS via Zigler NIFs\n```\n\nEach `%Matrix{}` and `%Vector{}` struct carries a `backend` field, so inspection and mutation operations dispatch to the correct backend automatically.\n\nSelect a backend via application config:\n\n    config :ex_graphblas, default_backend: GraphBLAS.Backend.Elixir\n\nOr per-call:\n\n    GraphBLAS.Matrix.from_coo(3, 3, entries, :int64, backend: GraphBLAS.Backend.SuiteSparse)\n\n## Quick start\n\n### Sparse matrix operations\n\n    # Create a sparse 3x3 matrix from COO triples\n    {:ok, m} = GraphBLAS.Matrix.from_coo(3, 3, [\n      {0, 1, 1}, {1, 2, 2}, {2, 0, 3}\n    ], :int64)\n\n    # Matrix multiplication\n    {:ok, result} = GraphBLAS.Matrix.mxm(m, m, :plus_times)\n\n    # Extract entries\n    {:ok, entries} = GraphBLAS.Matrix.to_coo(result)\n\n### Graph algorithms\n\n    # Build an adjacency matrix\n    {:ok, adj} = GraphBLAS.Matrix.from_coo(5, 5, [\n      {0, 1, 1}, {1, 2, 1}, {2, 3, 1}, {3, 4, 1}\n    ], :int64)\n\n    # BFS from vertex 0\n    {:ok, visited} = GraphBLAS.Algorithm.bfs_reach(adj, 0)\n\n    # Single-source shortest paths\n    {:ok, distances} = GraphBLAS.Algorithm.sssp(adj, 0)\n\n    # Triangle count\n    {:ok, count} = GraphBLAS.Algorithm.triangle_count(adj)\n\n    # PageRank\n    {:ok, ranks} = GraphBLAS.Algorithm.pagerank(adj)\n\n### Knowledge graph queries\n\n    rel = GraphBLAS.Relation.new(100)\n    {:ok, rel} = GraphBLAS.Relation.add_triples(rel, :follows, [{0, 1}, {1, 2}, {2, 3}])\n    {:ok, rel} = GraphBLAS.Relation.add_triples(rel, :likes, [{1, 3}, {2, 0}])\n\n    # Two-hop traversal: who can X reach by following then liking?\n    {:ok, result} = GraphBLAS.Relation.traverse(rel, [:follows, :likes], :lor_land)\n\n    # Transitive closure over :follows\n    {:ok, closure} = GraphBLAS.Relation.closure(rel, :follows, :lor_land)\n\n## Use cases\n\nThis section sketches a few concrete scenarios and how to approach them with GraphBLAS. The guides go deeper; here we focus on the high-level shape of a solution.\n\n### 1. Social graph: two-hop follower recommendations\n\nGoal: “Suggest accounts I might want to follow based on people my friends follow.”\n\n1. Model your social graph as an adjacency matrix `A` where `A[i,j] == 1` when user `i` follows `j`.\n2. Compute `A * A` using a boolean semiring to capture two-hop reachability.\n\n```elixir\nalias GraphBLAS.{Matrix, Algorithm}\n\n# 0 follows 1, 1 follows 2\n{:ok, adj} = Matrix.from_coo(3, 3, [{0, 1, 1}, {1, 2, 1}], :int64)\n{:ok, reach2} = Matrix.mxm(adj, adj, :lor_land)\n\n# reach2[0,2] is true: \"0 can reach 2 in two hops\"\n```\n\nInterpretation: non-zero entries in row `i` of `reach2` are candidates for “people you may know” based on two-hop paths. You can mask out already-followed accounts with a mask matrix (see the masks and descriptors guide).\n\n### 2. Weighted shortest paths in logistics or routing\n\nGoal: “Compute the cheapest cost from a depot to every destination.”\n\n1. Model edges as weights (cost, time, distance) in a weighted adjacency matrix.\n2. Use `GraphBLAS.Algorithm.sssp/2` which builds on the min-plus semiring.\n\n```elixir\nalias GraphBLAS.{Matrix, Algorithm}\n\n{:ok, weighted} = Matrix.from_coo(4, 4, [\n  {0, 1, 2.0},\n  {1, 2, 3.0},\n  {0, 2, 10.0}\n], :fp64)\n\n{:ok, dist} = Algorithm.sssp(weighted, 0)\n# dist[1] = 2.0, dist[2] = 5.0 (0→1→2 is cheaper than 0→2)\n```\n\nThis pattern generalises to road networks, communication networks, and any place where “cheapest path” matters.\n\n### 3. Knowledge graph traversal and path queries\n\nGoal: “Answer multi-hop questions over typed relationships.”\n\n1. Store triples `(subject, predicate, object)` in `GraphBLAS.Relation`.\n2. Use `Relation.traverse/3` to describe a path of predicates.\n\n```elixir\nalias GraphBLAS.Relation\n\n# alice=0, bob=1, carol=2, dave=3\nrel = Relation.new(4)\n{:ok, rel} = Relation.add_triples(rel, :follows, [{0, 1}, {1, 2}])\n{:ok, rel} = Relation.add_triples(rel, :likes, [{1, 2}])\n\n{:ok, result} = Relation.traverse(rel, [:follows, :likes], :lor_land)\n# result[0,2] == true means:\n#   \"there exists x such that 0 --follows→ x --likes→ 2\"\n```\n\nThis pattern scales to more complex path expressions and aggregation semirings (e.g. counting paths with `:plus_times`).\n\nFor a deeper, tutorial-style treatment of these examples, see the guides listed below.\n\n## Built-in semirings\n\n| Name               | Multiply | Add   | Type   | Use                           |\n|--------------------|----------|-------|--------|-------------------------------|\n| `:plus_times`      | `a * b`  | `a + b` | `:int64` | Standard matrix multiply  |\n| `:plus_times_fp64` | `a * b`  | `a + b` | `:fp64`  | Standard matrix multiply  |\n| `:plus_min`        | `min(a,b)` | `a + b` | `:int64` | Shortest path           |\n| `:plus_min_fp64`   | `min(a,b)` | `a + b` | `:fp64`  | Shortest path           |\n| `:min_plus`        | `a + b`  | `min(a,b)` | `:int64` | Shortest path variant  |\n| `:min_plus_fp64`   | `a + b`  | `min(a,b)` | `:fp64`  | Shortest path variant  |\n| `:max_plus`        | `a + b`  | `max(a,b)` | `:int64` | Longest / critical path |\n| `:max_plus_fp64`   | `a + b`  | `max(a,b)` | `:fp64`  | Longest / critical path |\n| `:max_min`         | `min(a,b)` | `max(a,b)` | `:int64` | Capacity / bottleneck  |\n| `:max_min_fp64`    | `min(a,b)` | `max(a,b)` | `:fp64`  | Capacity / bottleneck  |\n| `:lor_land`        | `a and b` | `a or b` | `:bool`  | Boolean adjacency (BFS) |\n| `:land_lor`        | `a or b`  | `a and b` | `:bool`  | Dual boolean semiring   |\n\n## Graph algorithms\n\n| Algorithm | Description |\n|-----------|-------------|\n| `bfs_reach/2` | BFS reachability -- bool vector of visited vertices |\n| `bfs_levels/2` | BFS levels -- integer vector of hop distances from source |\n| `sssp/2` | Single-source shortest paths (Dijkstra via min-plus semiring) |\n| `triangle_count/1` | Undirected triangle count via masked element-wise multiply |\n| `connected_components/1` | Connected components via iterative label propagation |\n| `degree/2` | In-degree or out-degree vector |\n| `pagerank/2` | PageRank with damping factor and convergence check |\n\nAll algorithms accept a `backend:` option and work identically on both backends.\n\n## Installation\n\nAdd `ex_graphblas` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:ex_graphblas, \"~\u003e 0.2.0\"}\n  ]\nend\n```\n\n### SuiteSparse backend\n\nTo use the native SuiteSparse backend, install SuiteSparse:GraphBLAS and set the include path:\n\n    export SUITESPARSE_INCLUDE_PATH=/opt/homebrew/include/suitesparse\n\nOr in your `config/config.exs`:\n\n    config :ex_graphblas, suitesparse_include_path: \"/opt/homebrew/include/suitesparse\"\n\nSee `guides/installation_guide.md` for platform-specific instructions.\n\n## Guides\n\nThe guides in the `guides/` directory provide end-to-end walkthroughs:\n\n- `guides/installation_guide.md` – installing ex_graphblas and SuiteSparse.\n- `guides/architecture_walkthrough.md` – how the library is structured and why.\n- `guides/reference_backend_walkthrough.md` – the pure Elixir backend and data model.\n- `guides/native_backend_walkthrough.md` – the SuiteSparse backend and NIF boundary.\n- `guides/graph_algorithms_guide.md` – graph algorithms and knowledge graph operations.\n- `guides/masks_and_descriptors_guide.md` – controlling computation with masks and descriptors.\n- `guides/parity_testing_guide.md` – keeping backends in sync with property tests.\n\n## Status\n\n| Phase | Description | Status |\n|-------|-------------|--------|\n| 1 | Architecture, API, scaffolding | Complete |\n| 2 | Pure Elixir reference backend | Complete |\n| 3 | SuiteSparse native backend | Complete |\n| 4 | Parity and semantic validation | Complete |\n| 5 | Masks, descriptors, API honing | Complete |\n| 6 | Graph algorithms and knowledge graphs | Complete |\n| 7 | Nx integration | Deferred |\n| 8 | Hardening, benchmarks, release prep | In progress |\n\n### Roadmap \u0026 milestones\n\nThese are not hard promises, but they capture the intended evolution of the library:\n\n- **Milestone: 0.2.x – Native backend + CI hardening (current)**  \n  - Ship a robust SuiteSparse backend behind `GraphBLAS.Backend.SuiteSparse`.\n  - Provide precompiled NIFs for common platforms, with CI-tested source builds as a fallback.\n  - Stabilise dialyzer, lint, and precompiled-NIF workflows.\n\n- **Milestone: 0.3.x – Developer experience and observability**  \n  - Improve error messages from the native backend, with clearer reasons and actionable hints.  \n  - Add instrumentation hooks so long-running operations can be measured (timers, counters) without exposing backend internals.\n\n- **Milestone: 0.4.x – Higher-level graph APIs**  \n  - Add richer graph helpers (graph builders, canned patterns) on top of the existing primitive operations.  \n  - Extend the `GraphBLAS.Relation` API with more path-query combinators and convenience functions.\n\n- **Milestone: 0.5.x – Nx and ecosystem integration (Phase 7)**  \n  - Revisit Nx integration once the core library is stable, focusing on zero-copy interop where possible.  \n  - Explore bridges to popular Elixir data tooling (e.g. Explorer, Livebook examples) using GraphBLAS under the hood.\n\n## License\n\nApache License 2.0. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthanos%2Fex_graphblas","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthanos%2Fex_graphblas","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthanos%2Fex_graphblas/lists"}