using System.Linq; using System.Collections.Generic; using Collections.Pooled; namespace MoonTools.Graph { public class UndirectedGraph : DirectedGraph, IUnweightedGraph where TNode : System.IEquatable { enum Color { White, Gray, Black } new public int Size => edges.Count / 2; public bool Complete => Size == (Order * (Order - 1) / 2); public bool Chordal { get { var lexicographicOrder = LexicographicBFS(); return lexicographicOrder .Select((node, index) => (node, index)) .All(pair => { var (node, index) = pair; var successors = lexicographicOrder.Skip(index).Take(nodes.Count - index); return Clique(Neighbors(node).Intersect(successors).Union(Enumerable.Repeat(node, 1))); }); } } public bool Bipartite { get { var colors = new PooledDictionary(ClearMode.Always); var d = new PooledDictionary(ClearMode.Always); var partition = new PooledDictionary(ClearMode.Always); foreach (var node in Nodes) { colors[node] = Color.White; d[node] = int.MaxValue; partition[node] = 0; } var start = Nodes.First(); colors[start] = Color.Gray; partition[start] = 1; d[start] = 0; var stack = new PooledStack(ClearMode.Always); stack.Push(start); while (stack.Count > 0) { var node = stack.Pop(); foreach (var neighbor in Neighbors(node)) { if (partition[neighbor] == partition[node]) { return false; } if (colors[neighbor] == Color.White) { colors[neighbor] = Color.Gray; d[neighbor] = d[node] + 1; partition[neighbor] = 3 - partition[node]; stack.Push(neighbor); } } stack.Pop(); colors[node] = Color.Black; } stack.Dispose(); colors.Dispose(); d.Dispose(); partition.Dispose(); return true; } } public override void AddEdge(TNode v, TNode u, TEdgeData edgeData) { base.AddEdge(v, u, edgeData); base.AddEdge(u, v, edgeData); } public override void AddEdges(params (TNode, TNode, TEdgeData)[] edges) { foreach (var edge in edges) { AddEdge(edge.Item1, edge.Item2, edge.Item3); } } public override void RemoveEdge(TNode v, TNode u) { base.RemoveEdge(v, u); base.RemoveEdge(u, v); } public bool Clique(IEnumerable nodeList) { return nodeList.All(node => nodeList.All(other => Neighbors(node).Contains(other) || node.Equals(other))); } } }