@graphty/layout
Version:
graph layout algorithms based on networkx
126 lines (105 loc) • 3.06 kB
text/typescript
/**
* Special graph detection functions for planarity testing
*/
import { Node, Edge } from '../../types';
/**
* Check if graph is K5 (complete graph with 5 nodes)
*
* @param nodes - List of nodes
* @param edges - List of edges
* @returns True if graph is K5
*/
export function isK5(nodes: Node[], edges: Edge[]): boolean {
if (nodes.length !== 5) return false;
// K5 has exactly 10 edges
if (edges.length !== 10) return false;
// Check if every pair of distinct nodes is connected
for (let i = 0; i < nodes.length; i++) {
for (let j = i + 1; j < nodes.length; j++) {
const hasEdge = edges.some(
e => (e[0] === nodes[i] && e[1] === nodes[j]) ||
(e[0] === nodes[j] && e[1] === nodes[i])
);
if (!hasEdge) return false;
}
}
return true;
}
/**
* Check if graph is K3,3 (complete bipartite with 3,3 nodes)
*
* @param nodes - List of nodes
* @param edges - List of edges
* @returns True if graph is K3,3
*/
export function isK33(nodes: Node[], edges: Edge[]): boolean {
if (nodes.length !== 6) return false;
// K3,3 has exactly 9 edges
if (edges.length !== 9) return false;
// Try to find a bipartite partition
const nodePartitions = tryFindBipartitePartition(nodes, edges);
if (!nodePartitions) return false;
const [part1, part2] = nodePartitions;
// Check if both partitions have size 3
if (part1.length !== 3 || part2.length !== 3) return false;
// Check if every node in part1 is connected to every node in part2
for (const n1 of part1) {
for (const n2 of part2) {
const hasEdge = edges.some(
e => (e[0] === n1 && e[1] === n2) ||
(e[0] === n2 && e[1] === n1)
);
if (!hasEdge) return false;
}
}
return true;
}
/**
* Try to find a bipartite partition of the nodes
*
* @param nodes - List of nodes
* @param edges - List of edges
* @returns Array of two partitions, or null if not bipartite
*/
export function tryFindBipartitePartition(
nodes: Node[],
edges: Edge[]
): [Node[], Node[]] | null {
const colorMap: Record<Node, number> = {};
const adjList: Record<Node, Node[]> = {};
// Create adjacency list
for (const node of nodes) {
adjList[node] = [];
}
for (const [u, v] of edges) {
adjList[u].push(v);
adjList[v].push(u);
}
// BFS to color nodes
const queue: Node[] = [nodes[0]];
colorMap[nodes[0]] = 0;
while (queue.length > 0) {
const node = queue.shift()!;
const nodeColor = colorMap[node];
for (const neighbor of adjList[node]) {
if (colorMap[neighbor] === undefined) {
colorMap[neighbor] = 1 - nodeColor; // Toggle color (0/1)
queue.push(neighbor);
} else if (colorMap[neighbor] === nodeColor) {
// Conflict: not bipartite
return null;
}
}
}
// Create partitions
const part0: Node[] = [];
const part1: Node[] = [];
for (const node of nodes) {
if (colorMap[node] === 0) {
part0.push(node);
} else {
part1.push(node);
}
}
return [part0, part1];
}