{"id":51070673,"url":"https://github.com/code-shoily/zog","last_synced_at":"2026-06-23T10:01:44.163Z","repository":{"id":364720379,"uuid":"1265691080","full_name":"code-shoily/zog","owner":"code-shoily","description":"NIF Powered Graph Library for Elixir","archived":false,"fork":false,"pushed_at":"2026-06-14T06:56:40.000Z","size":299,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-14T08:20:52.180Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Zig","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/code-shoily.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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-06-11T02:11:16.000Z","updated_at":"2026-06-14T06:56:44.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/code-shoily/zog","commit_stats":null,"previous_names":["code-shoily/zog"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/code-shoily/zog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-shoily%2Fzog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-shoily%2Fzog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-shoily%2Fzog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-shoily%2Fzog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/code-shoily","download_url":"https://codeload.github.com/code-shoily/zog/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/code-shoily%2Fzog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34550965,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-19T02:00:06.005Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2026-06-23T10:01:41.755Z","updated_at":"2026-06-23T10:01:44.154Z","avatar_url":"https://github.com/code-shoily.png","language":"Zig","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Zog ⚡\n\n[![Hex Version](https://img.shields.io/hexpm/v/zog.svg)](https://hex.pm/packages/zog)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-ffaff3)](https://hexdocs.pm/zog/)\n[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n\n`Zog` is a high-performance, native (Zig/NIF) graph and network analysis library for Elixir. Backed by [Zigler](https://github.com/orbitz/zigler), `Zog` compiles C-level fast graph algorithms directly into the Erlang VM.\n\nIt is designed to be fully standalone for lightweight native graph workloads, yet seamlessly integrates as a NIF-powered acceleration layer for [YogEx](https://hex.pm/packages/yog_ex) or [Yog (Gleam)](https://hex.pm/packages/yog).\n\n\u003e [!IMPORTANT]\n\u003e **Zig Compiler Prerequisite**: `Zog` uses Zigler `0.16.0` and requires the **Zig `0.16.x`** compiler to be installed on your host system to compile the native NIF components.\n\n---\n\n## Why Zog? (The ResourceGraph Pattern)\n\nTraditional NIFs suffer from serialization overhead when translating complex Elixir data structures (like maps or structs) into memory representations readable by C/Zig/Rust, and vice-versa (known as the *Copy-In/Copy-Out* pattern). For small graphs, this overhead can make NIFs slower than pure Elixir.\n\n`Zog` solves this using the **`ResourceGraph`** pattern:\n1. **Load/Build Once**: Create a native memory representation of your graph via `Zog.ResourceGraph.new/1` (from a `Zog.SoA`), or load it directly from disk into native memory using NIF-level file parsers (`read_edgelist/2`, `read_adjlist/2`, `read_tgf/2`).\n2. **Amortize Serialization**: The graph remains allocated inside native Zig memory as Erlang NIF resource references (`Zog.ResourceGraph.t()`).\n3. **Execute Repeatedly**: Run multiple heavy algorithms (Centrality, Leiden, Pathfinding, Min-Cut) directly on the reference.\n4. **Collect Outputs**: Only the final scalar metrics or integer arrays are returned back to Elixir.\n\n### Native Memory Backends\n\n`ResourceGraph` supports two alternative backend engines:\n\n* **`:soa` (ArrayGraph)**: Stores nodes and edges in flat, contiguous structure-of-arrays (SoA) memory slices. This layout maximizes CPU cache locality and provides the highest execution speed. **This is the default and recommended backend** for build-once, run-many workloads.\n* **`:hash_graph` (GraphMap)**: Uses standard pointer-heavy hash tables with collision/resize overhead. This backend should **only** be chosen if your application requires dynamic native mutation of nodes and edges between NIF calls, as it carries a substantial performance penalty relative to `:soa`.\n\nTo choose a backend, pass the `:backend` option:\n```elixir\n# Create via SoA builder\nnative_graph = Zog.ResourceGraph.new(graph, backend: :soa)\n\n# Or load directly from disk\nnative_graph = Zog.ResourceGraph.read_edgelist(\"edges.txt\", backend: :hash_graph)\n```\n\n### Bypassing Label Mapping with `:raw`\n\nBy default, when returning results for node-level queries (such as PageRank, Betweenness Centrality, Louvain/Leiden community detection, etc.), `Zog` automatically maps the native indices back to your original Elixir labels. For large graphs (e.g., millions of nodes), constructing large Elixir maps on the BEAM heap incurs serialization and memory overhead.\n\nTo bypass this overhead, pass `raw: true` as an option. When enabled, `Zog` returns flat lists of floats or integers directly from native memory where the list index corresponds to the internal `u32` node ID:\n\n```elixir\n# Returns %{\"node_A\" =\u003e 0.15, \"node_B\" =\u003e 0.35, ...}\nscores = Zog.ResourceGraph.pagerank(native_graph)\n\n# Returns [0.15, 0.35, ...] directly (O(1) serialization overhead on the BEAM heap)\nraw_scores = Zog.ResourceGraph.pagerank(native_graph, raw: true)\n```\n\n### Direct Integer Parsing with `:integer_labels`\n\nFor large networks where node labels are already contiguous (or near-contiguous) integers (e.g. standard SNAP datasets like Slashdot, LiveJournal, or Stanford web graphs), you can completely bypass string parsing, string hash-map lookups, and heap-allocated label arrays by passing the `integer_labels: true` option to the parser:\n\n```elixir\n# Reads graph by parsing and storing labels as integers directly in Zig\nlarge_graph = Zog.ResourceGraph.read_edgelist(\"slashdot_edges.txt\", integer_labels: true)\n\n# Node labels are now integers instead of binaries\n# pagerank/1 returns %{0 =\u003e 0.05, 1 =\u003e 0.12, ...} instead of %{\"0\" =\u003e 0.05, ...}\nscores = Zog.ResourceGraph.pagerank(large_graph)\n```\n\nCombined with the `:raw` option, this allows Zog to load and process large-scale networks with zero memory allocation or serialization overhead for node labels.\n\n---\n\n## Installation\n\nAdd `zog` to your list of dependencies in `mix.exs`. Since compiling Zig NIFs requires `zigler`, you can add it as a compiler-time dependency:\n\n```elixir\ndef deps do\n  [\n    {:zog, \"~\u003e 0.1.0\"},\n    {:zigler, \"~\u003e 0.16.0\", runtime: false}\n  ]\nend\n```\n\nIf you plan to use `Zog` alongside `YogEx` for seamless bridging, include both:\n\n```elixir\ndef deps do\n  [\n    {:yog_ex, \"~\u003e 0.99.0\"},\n    {:zog, \"~\u003e 0.1.0\"},\n    {:zigler, \"~\u003e 0.16.0\", runtime: false}\n  ]\nend\n```\n\n---\n\n## Getting Started\n\n### 1. Standalone Graph Building\n\nYou can build graphs in Elixir using `Zog.SoA`, then perform fast computations on them:\n\n```elixir\n# Create a directed or undirected graph builder\ngraph =\n  Zog.directed()\n  |\u003e Zog.add_node(\"A\")\n  |\u003e Zog.add_node(\"B\")\n  |\u003e Zog.add_node(\"C\")\n  |\u003e Zog.add_edge(\"A\", \"B\", 1.5)\n  |\u003e Zog.add_edge(\"B\", \"C\", 2.0)\n  |\u003e Zog.add_edge(\"C\", \"A\", 0.5)\n\n# Convert to a native ResourceGraph\nnative_graph = Zog.ResourceGraph.new(graph)\n\n# Compute centralities natively (returns Elixir map of labels to scores)\nZog.ResourceGraph.pagerank(native_graph)\n# =\u003e %{\"A\" =\u003e 0.22, \"B\" =\u003e 0.34, \"C\" =\u003e 0.44}\n\n# Always free native resources when done\nZog.ResourceGraph.destroy(native_graph)\n```\n\n### 2. Loading Large Graphs Directly Natively\n\nIf you have large datasets, bypass Elixir creation entirely and parse files directly into native memory:\n\n```elixir\n# Reads an edge list file, returning a resource map containing the native reference\n# and a lightweight label mapping builder.\nlarge_graph = Zog.ResourceGraph.read_edgelist(\"path/to/large_edges.txt\", directed: true)\n\n# Run Leiden Community Detection at native speed\ncommunities = Zog.ResourceGraph.leiden(large_graph)\n# =\u003e %{\"node_1\" =\u003e 0, \"node_2\" =\u003e 0, \"node_3\" =\u003e 1, ...}\n\n# Free native memory\nZog.ResourceGraph.destroy(large_graph)\n```\n\n---\n\n## Bridging with Yog (`YogEx`)\n\n`Zog` is designed to play nice with `Yog`. If `Yog` is loaded in the VM, `Zog` automatically compiles conversion functions to map Elixir-based `Yog.Graph` instances to `Zog.SoA` layouts and back.\n\n```elixir\n# 1. Start with an existing Yog.Graph\nyog_graph = \n  Yog.Graph.new(type: :directed)\n  |\u003e Yog.Graph.add_edge(\"A\", \"B\", weight: 5.0)\n\n# 2. Bridge it to Zog\nzog_soa = Zog.from_graph(yog_graph)\n\n# 3. Transition to a native NIF Resource for fast execution\nres_graph = Zog.ResourceGraph.new(zog_soa)\npaths = Zog.ResourceGraph.floyd_warshall(res_graph)\nZog.ResourceGraph.destroy(res_graph)\n\n# 4. Bridge back to Yog if necessary\nrestored_yog_graph = Zog.to_graph(zog_soa)\n```\n\n---\n\n## Native Performance\n\nFor large networks, native computation avoids overhead and runs at bare-metal speed (measured with `MIX_ENV=prod` to enable release optimizations):\n* **Floyd-Warshall / Johnson's Pathfinding**: **7x - 54x+ faster** than pure Elixir (e.g. Floyd-Warshall is **54x+ faster** on dense graphs).\n* **Leiden / Louvain Community Detection**: **10x - 21x+ faster**.\n* **Stoer-Wagner Min Cut / Max Flow**: **4x - 7x+ faster**.\n* **Exact Graph Coloring (Bron-Kerbosch / DSatur)**: **7x - 27x+ faster**.\n\nTo run the full benchmark suite on your local machine:\n\n```bash\n# Verify parity tests pass\nmix test\n\n# Run comparison suites\nmix run benchmarks/native_vs_elixir_comparison.exs\nmix run benchmarks/native_clique_comparison.exs\nmix run benchmarks/native_max_flow_comparison.exs\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcode-shoily%2Fzog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcode-shoily%2Fzog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcode-shoily%2Fzog/lists"}