All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.98.3 - 2026-06-09
Fixed
Yog.Community.Walktrap.detect/1— Now selects the modularity-maximizing level from the dendrogram instead of the trivial all-merged level. The default partition is meaningful for typical graphs.Yog.Multi.Model.degree/2,out_degree/2,in_degree/2— Now correctly count undirected self-loops as contributing 2 to a node's degree (matching standard graph theory). This also fixes false-negative Eulerian path/circuit detection on undirected multigraphs containing self-loops.Yog.Multi.Eulerian.has_eulerian_circuit?/1,has_eulerian_path?/1,find_eulerian_circuit/1,find_eulerian_path/1— Now correctly tolerate isolated nodes (nodes with zero degree). Connectivity is checked over non-isolated nodes only, and start-node selection skips isolated nodes, matching standard Eulerian theory and NetworkX's behavior.Yog.Community.Louvain.detect/1— Now runs full hierarchical Louvain (phase 1 + aggregation + recursion) instead of phase 1 only. The returned partition may differ from previous versions on graphs without strong community structure (e.g., scale-free networks) — both partitions are valid modularity local optima but the new one is the standard Louvain output.Yog.Community.Louvain.detect_hierarchical/1— Now stores raw community IDs at each level so that the dendrogram can be correctly flattened back to original node IDs. SeeYog.Community.Dendrogram.flatten_to_original/1.Yog.Community.Leiden.detect_hierarchical/1— Updated docstrings to point atYog.Community.Dendrogram.flatten_to_original/1for obtaining final partitions over original node IDs. The dendrogram structure was already compatible after the Louvain fix.Yog.Community.Infomap.detect/1— Rewrote to implement the actual Map Equation optimization (Rosvall & Bergstrom 2008). Previously ran a single greedy pass with a flow heuristic that did not compute description length. Now computes L(M) = q↷ H(Q) + Σ p↻^i H(P^i), iterates to convergence, and minimizes description length as documented.Yog.Community.GirvanNewman.detect/1— Now defaults to the modularity-maximizing partition across the dendrogram instead of the trivial all-singletons partition. For users who specifically want the all-singletons partition, passtarget_communities: Yog.node_count(graph)explicitly.
Added
Yog.Community.Dendrogram.flatten_to_original/1— Folds per-level assignment maps into a singleResult.t()over original-graph node ids.
[0.98.2] - 2026-06-06
Added
Yog.Builder.Labeled.get_label/2&Yog.Builder.Live.get_label/2— Added reverse registry lookup to query the label of a given node ID.Yog.Builder.Live.add_node/2— Added support for registering standalone nodes during incremental live graph building.Yog.Approximate.closeness/2— Implemented closeness centrality approximation using Eppstein-Wang pivot sampling on the transposed graph.Yog.Approximate.harmonic/2— Implemented harmonic centrality approximation using Eppstein-Wang pivot sampling on the transposed graph.Yog.Operation.tensor_product/2,Yog.Operation.strong_product/4, &Yog.Operation.lexicographic_product/4— Added three standard graph product operations with optimized private helpers and performance complexity warning alerts.Yog.OperationProperty-Based Tests — Added recursive mathematical invariants and edge/node count verification checks for all newly implemented graph products to the PBT suite.Yog.Transform.add_self_loops/2&Yog.Transform.remove_self_loops/1— Added convenience functions for managing self-loops in graphs, along with delegations inYog.add_self_loops/2andYog.remove_self_loops/1.Yog.PairingHeap.merge/2— Exposed the $O(1)$ priority queue merge operation as a public API.Yog.PairingHeapInspect Protocol — Implemented theInspectprotocol for pairing heaps (%Yog.PairingHeap.Node{}and%Yog.PairingHeap.Empty{}), showing size and peek elements cleanly.Yog.OperationPerformance Warnings — Added warning docstrings to potentially slow and scale-sensitive operations (cartesian_product/4,line_graph/2,power/3, andisomorphic?/2) to detail growth, space/time complexities, and caution users on large graphs.
Changed
Yog.Approximate&Yog.HealthOption Documentation — Normalized:to_floatdocumentation to match the parsed:with_to_floatoption key.Yog.Health&Yog.ApproximateOption Parsing — DRYed up option parsing by sharing the internalparse_metric_opts/1helper.Yog.Builder.Grid&Yog.Builder.Toroidal— Extractedadd_grid_edge/5helper to comply with Credo nesting rules and avoid deep function nesting.Yog.UtilsOptimizations — Refactorednorm_diff/3to be completely allocation-free by using direct map folds, eliminating intermediate key list concatenations and temporary map allocations.Yog.TransformOptimizations — Overhauled multiple transformer functions to eliminate dynamic protocol dispatch and intermediate list/tuple allocations during graph folding:complement/2: Fetches the source node's out-edges once outside the inner loop (saving $O(V^2)$ lookups) and utilizesList.foldl/3/Utils.map_fold/3.to_undirected/2: Replaced list-comprehension based reduction with nestedUtils.map_fold/3loops.relabel_nodes/2: Folds over nodes and out-edges directly viaUtils.map_fold/3, avoiding full edge list allocations (Model.all_edges/1).transitive_closure/1&redirect_neighbors/5: Updated to fold over adjacency and reachability maps usingUtils.map_fold/3in-place.
Yog.OperationOptimizations — Upgraded several core graph join and product builders to completely bypass dynamic enumerable dispatch and intermediate lists:symmetric_difference/2: Rewritten as a single-pass edge collection on the symmetric difference of nodes, completely removing three intermediate subgraph copy and union allocations.isomorphic?/2(mapping_valid?/5): Replaced linear-time list search checks (s in Map.keys(...)) with $O(1)$ constant-timeMap.has_key?/2lookups.disjoint_union/2: Avoids flat-mapping/rebuilding intermediate edge lists by folding over out-edges directly viaUtils.map_fold/3.cartesian_product/4: Rewrote vertical, horizontal, and node product helpers to fold withUtils.map_fold/3andList.foldl/3instead of nestedEnum.reduce/3on maps.line_graph/2: Optimized unique undirected edge extraction to filter in $O(E)$ during fold, eliminating expensiveEnum.uniq_by/2andEnum.map/2stages. Bypassed enumerable reduction in edge-incident traversals.power/3: Refactored distance closure iterations to utilize fastList.foldl/3on lists.
Yog.PairingHeap— Optimized the internalcombinehelper to bypass creating%Empty{}structs when matching even number of children (size $\ge 2$), reducing allocation overhead during restructuring.Yog.Model.add_node/3— Defaulted thedataparameter tonil, allowing nodes to be added to graphs and multigraphs without a data payload (e.g.,Yog.add_node(graph, id)). Updated delegations inYog.add_node/3andYog.Multi.add_node/3.Yog.DisjointSet— Optimizedfind/2andfind_root_readonly/2to eliminate redundant struct allocations during recursion.find_root_readonly/2now operates directly on theparentsmap.
Fixed
Yog.Centrality.pagerank/2— FixedArithmeticError(division by zero) crash on empty and single-node graphs.Yog.Health.average_path_length/2— Added $O(V+E)$ connectivity fast-path check to avoid running parallel Dijkstra computations on disconnected graphs.Yog.Health.eccentricity/3— Replaced linear key list sizing checks with constant-time$O(1)$BIFmap_size/1.Yog.Builder.Grid&Yog.Builder.ToroidalNil-cell Handling — Replaced directto_data != nilchecks withModel.has_node?/2to support jagged grids while correctly handling nodes withnilpayloads.Yog.Builder.Grid&Yog.Builder.ToroidalConnection Topology — Addeddetect_topology/1to dynamically identify and populate connection topology instead of always hardcoding:rook.- Property Tests — Resolved flaky
StreamData.TooManyDuplicatesErrorfailures inYog.PBT.FlowTestandYog.PBT.PathfindingTestproperties by pattern-matching directly on the generated node list to obtain distinct source/target nodes, instead of usinguniq_list_of/2onStreamData.member_of/1.
[0.98.1] - 2026-05-23
Added
Multigraph Collapse Helpers
Yog.Multi.Model.to_simple_graph_max_edges/1— New helper that collapses parallel edges keeping the maximum weight. Useful for widest-path and bottleneck algorithms.Yog.Multi.Model.to_simple_graph_sum_edges/1— New zero-argument helper that sums parallel edge weights using&Kernel.+/2. Complements the existingto_simple_graph_sum_edges/2which accepts a custom combine function.Yog.Multi— Added facade delegations forto_simple_graph_max_edges/1andto_simple_graph_sum_edges/1.
Documentation
ALGORITHMS.md— Comprehensive audit and update:- Added missing algorithms: Brandes SSSP, Chinese Postman, Path Utilities, Distance Matrix, Hungarian matching, Blossom matching, Graph Coloring, Tree Decomposition, and maze generators (Kruskal's, Prim's simplified/true, Eller's, Growing Tree, Recursive Division).
- Added missing categories: Random Graph Generation, Graph Builders, Functional Graphs (FGL-style), and Rendering.
- Fixed incorrect module names:
Yog.PriorityQueue→Yog.PairingHeap,Yog.Connectivity.Bridge/Articulation→Yog.Connectivity.Analysis. - Removed ghost algorithms: Capacity Scaling, Network Simplex.
- Removed duplicate
Dinic'sentry in Flow & Cuts. - Moved maze generation algorithms out of Approximation Algorithms into Maze Generation.
Fixed
Yog.Multi.Model.to_simple_graph/1— Now deterministic. Edges are sorted byedge_idbefore collapsing, guaranteeing that the earliest-added edge is always kept. Previously, iteration order over theedgesmap was undefined, making the result non-deterministic.
[0.98.0] - 2026-05-16
Added
Builder Modules
Yog.Builder.Labeled— Added convenience query functions:has_label?/2— Check if a label is registered.has_edge?/3— Check if an edge exists between two labels.node_count/1— Number of registered nodes.edge_count/1— Number of edges in the underlying graph.
Yog.Builder.Live— Addedhas_label?/2for registry membership checks.
DAG Modules
Yog.DAG— Filled facade gaps and added DAG-native algorithms. The DAG modules are now feature-complete:- Query functions:
has_node?/2,has_edge?/3,node_count/1,edge_count/1,nodes/1,successors/2,predecessors/2,in_degree/2,out_degree/2,reachable?/3. - Convenience constructors:
from_edges/1andfrom_edges/2— create a DAG directly from edge tuples without manually building aYog.Graphfirst. Yog.DAG.Algorithm.sources/1— Returns all source nodes (in-degree 0).Yog.DAG.Algorithm.sinks/1— Returns all sink nodes (out-degree 0).Yog.DAG.Algorithm.ancestors/2— Returns all ancestors of a node (includes the node itself).Yog.DAG.Algorithm.descendants/2— Returns all descendants of a node (includes the node itself).Yog.DAG.Algorithm.single_source_distances/2— O(V+E) single-source shortest distances (faster than Dijkstra for DAGs).Yog.DAG.Algorithm.longest_path/3— Longest path between two specific nodes.Yog.DAG.Algorithm.path_count/3— Counts distinct paths between two nodes via DP.- Safety fix:
topological_sort/1now raisesRuntimeErrorif a cycle is somehow detected, instead of silently returning[].
- Query functions:
Multigraph Facade
Yog.Multi— Filled facade gaps and added multigraph-native algorithms:has_edge/2— Check if a specificedge_idexists.edge_count/3— Count parallel edges between a node pair.degree/2— Total degree (in + out for directed, out-degree for undirected).has_cycle?/1— Detect cycles without manual collapsing.topological_sort/1— Returns{:ok, [node_id]}or{:error, :contains_cycle}.to_simple_graph/1— Collapse keeping only the first edge between each pair.to_simple_graph_min_edges/1— Collapse parallel edges keeping the minimum weight.to_simple_graph_sum_edges/2— Collapse parallel edges summing weights via a custom function.
Generators
Yog.Generator.Classic— Added missing_with_typevariant:prism_with_type/2— Generate a prism (circular ladder) graph with a specified graph type.
Rendering
Yog.Multi.Mermaid— New Mermaid.js renderer for multigraphs (Yog.Multi.Graph).- Supports parallel edges between the same pair of nodes.
edge_id-based callbacks (edge_label/2,edge_attributes/4) for per-edge customization.- Highlighting by
edge_idor{from, to}tuple. - Subgraphs, per-node styling, and all node shapes/directions.
theme/1with:default,:dark,:minimal,:presentationpresets.- Algorithm helpers:
path_to_options/2,mst_to_options/2,community_to_options/2,cut_to_options/2,matching_to_options/2. default_options_with_edge_formatter/1,default_options_with/1,default_options_without_labels/0.
Yog.Multi.DOT— Feature parity withYog.Render.DOT:theme/1with all presets.- Algorithm helpers:
path_to_options/2,mst_to_options/2,community_to_options/2,cut_to_options/2,matching_to_options/2. default_options_with_edge_formatter/1,default_options_with/1,default_options_without_labels/0.
Yog.Render.Mermaidparity withYog.Render.DOT:node_attributes/2callback for per-node inline styling (style node_id fill:...,stroke:...).edge_attributes/3callback for per-edge styling vialinkStyle index ....subgraphsoption for Mermaidsubgraph ... endblocks.theme/1— Presets::default,:dark,:minimal,:presentation.mst_to_options/2,community_to_options/2,cut_to_options/2,matching_to_options/2.default_options_with_edge_formatter/1anddefault_options_with/1.- Internal
MapSetconversion for O(1) highlight membership checks.
Yog.Utils— Extracted shared rendering helpers to eliminate Credo duplication:generate_palette/1,hsl_to_hex/3,mst_highlights/1,matching_highlights/1,path_to_edges/1.
Fixed
- Mermaid themes now apply globally to all nodes/edges via
classDef defaultandlinkStyle(previously only affected highlighted elements). - Mermaid dark mode readability — Added
default_font_coloroption for white text on dark backgrounds. - Mermaid undirected edge labels — Fixed invalid
---|1|syntax to correct-- 1 ---. - Mermaid per-node shapes —
node_shapenow accepts(id, data) -> shapefunction in addition to atom values. - Credo alias warnings in
Yog.Multi.Mermaid. - Maze generator RNG state isolation — All maze algorithms (
binary_tree/3,sidewinder/3,recursive_backtracker/3,hunt_and_kill/3,aldous_broder/3,wilson/3,kruskal/3,prim_simplified/3,prim_true/3,ellers/3,growing_tree/3,recursive_division/3) now restore the global:randstate after seeding, matching the behavior ofYog.Generator.Random. Previously, passing:seedpermanently altered the global RNG state. - Removed accidental
IO.putsdebug output fromtest/yog/multi/dot_test.exs.
Builders
Yog.Builder.Live.sync_multi/2— New function to sync pending changes to a multigraph (Yog.Multi.Graph).add_edgecreates parallel edges rather than overwriting existing ones.remove_edgeremoves all parallel edges between the given node pair.- Supports incremental sync, unweighted/simple edges, node removal, and both directed/undirected multigraphs.
Documentation & Livebooks
- All 11 livebooks reviewed and improved with better content and code coverage:
gallery/graph_catalog— Added Mermaid rendering, property checks (regularity, connectivity, diameter, girth), hypercube and binary tree generators.guides/getting_started— AddedYog.Builder.Liveexample, community detection, Mermaid export, and more query examples.guides/dag_analysis— Added cycle detection, transitive reduction with visualization, Mermaid rendering, andYog.acyclic?/1.guides/graph_properties— Fixed coloring visualization (now actually applies colors to DOT), added DSatur comparison, exact coloring, K3,3 planarity, and planar embedding.guides/network_analysis— Fixed community detection API (.assignmentsinstead of.communities), added degree/closeness centrality, articulation point/bridge visualization with per-element styling.guides/network_flow— Added global min-cut (Stoer-Wagner), fixed bipartite matching example, removed broken min-cost max-flow placeholder.guides/traversals_and_pathfinding— Added Bellman-Ford with negative weights, real A* grid example usingYog.Builder.GridGraph, Johnson's mention.how_to/customizing_visualizations— Fixed old API usage (node_attributesas function, not keyword list), added Mermaid themes, per-node/edge styling, subgraphs, and algorithm helpers (path_to_options,mst_to_options,community_to_options,cut_to_options).how_to/import_export— Added Graph6 and GDF format coverage.how_to/maze_generation— Added Wilson's algorithm demonstration, algorithm property comparison table, path length analysis across algorithms.how_to/multigraphs_and_collapsing— Added multigraph visualization (Yog.Multi.DOTandYog.Multi.Mermaid),Yog.Builder.Live.sync_multi/2example, per-edge styled rendering, Eulerian circuits on multigraphs, BFS/DFS traversals.