diff --git a/GraphX.java b/GraphX.java new file mode 100644 index 0000000..d322e2d --- /dev/null +++ b/GraphX.java @@ -0,0 +1,242 @@ +import java.util.*; + +// ****************BLACKBOX START***************** +// START COPYING FROM HERE + +class Hash { + private Map keyMap = new HashMap<>(); + + public Hash() {} + + private int hashInternal(int x, int y, int z) { + String key = x + "," + y + "," + z; + if (!keyMap.containsKey(key)) { + int newHash = keyMap.size(); + keyMap.put(key, newHash); + } + return keyMap.get(key); + } + + public int hash(int x) { + return hashInternal(x, 0, 0); + } + + public int hash(int x, int y) { + return hashInternal(x, y, 0); + } + + public int hash(int x, int y, int z) { + return hashInternal(x, y, z); + } +} + +class Graph { + boolean isDirected; + List> adj; + int n; + static final int N = 5000000; + Hash h; + + public Graph(int n, boolean isDirected) { + this.n = n; + this.isDirected = isDirected; + this.h = new Hash(); + this.adj = new ArrayList<>(N); + for (int i = 0; i < N; i++) { + adj.add(new ArrayList<>()); + } + } + + public Graph(int n) { + this(n, true); + } + + public int hash(int u, int v) { + return h.hash(u, v); + } + + public int hash(int u, int v, int k) { + return h.hash(u, v, k); + } + + // int node + public void addEdge(int uR, int vR, int c) { + int u = h.hash(uR); + int v = h.hash(vR); + addEdgeInternal(u, v, c); + } + public void addEdge(int uR, int vR) { addEdge(uR, vR, 0); } + + // 2-tuple node + public void addEdge(int uX, int uY, int vX, int vY, int c) { + int u = h.hash(uX, uY); + int v = h.hash(vX, vY); + addEdgeInternal(u, v, c); + } + public void addEdge(int uX, int uY, int vX, int vY) { addEdge(uX, uY, vX, vY, 0); } + + // 3-tuple node + public void addEdge(int uX, int uY, int uZ, int vX, int vY, int vZ, int c) { + int u = h.hash(uX, uY, uZ); + int v = h.hash(vX, vY, vZ); + addEdgeInternal(u, v, c); + } + public void addEdge(int uX, int uY, int uZ, int vX, int vY, int vZ) { + addEdge(uX, uY, uZ, vX, vY, vZ, 0); + } + + private void addEdgeInternal(int u, int v, int c) { + addEdgeWeighted(u, v, c); + if (!isDirected) { + addEdgeWeighted(v, u, c); + } + } + + private void addEdgeWeighted(int u, int v, int c) { + adj.get(u).add(new int[]{v, c}); + } +} + +class BFS { + private int[] minDistFromSource; + private boolean[] visited; + private Graph g; + + public BFS(Graph g) { + this.g = g; + clear(); + } + + public void clear() { + minDistFromSource = new int[Graph.N]; + visited = new boolean[Graph.N]; + Arrays.fill(minDistFromSource, -1); + Arrays.fill(visited, false); + } + + // run from int source + public void run(int sourceR) { + int source = g.h.hash(sourceR); + runInternal(source); + } + + // run from 2-tuple source + public void run(int sX, int sY) { + int source = g.h.hash(sX, sY); + runInternal(source); + } + + // run from 3-tuple source + public void run(int sX, int sY, int sZ) { + int source = g.h.hash(sX, sY, sZ); + runInternal(source); + } + + // minDist for int node + public int minDist(int targetR) { + int target = g.h.hash(targetR); + return minDistFromSource[target]; + } + + // minDist for 2-tuple node + public int minDist(int tX, int tY) { + int target = g.h.hash(tX, tY); + return minDistFromSource[target]; + } + + // minDist for 3-tuple node + public int minDist(int tX, int tY, int tZ) { + int target = g.h.hash(tX, tY, tZ); + return minDistFromSource[target]; + } + + // isVisited for int node + public boolean isVisited(int targetR) { + int target = g.h.hash(targetR); + return visited[target]; + } + + // isVisited for 2-tuple node + public boolean isVisited(int tX, int tY) { + int target = g.h.hash(tX, tY); + return visited[target]; + } + + // isVisited for 3-tuple node + public boolean isVisited(int tX, int tY, int tZ) { + int target = g.h.hash(tX, tY, tZ); + return visited[target]; + } + + private void runInternal(int source) { + Queue q = new LinkedList<>(); + q.add(source); + visited[source] = true; + minDistFromSource[source] = 0; + + while (!q.isEmpty()) { + int curNode = q.poll(); + for (int[] neighbor : g.adj.get(curNode)) { + int adjNode = neighbor[0]; + if (!visited[adjNode]) { + visited[adjNode] = true; + minDistFromSource[adjNode] = minDistFromSource[curNode] + 1; + q.add(adjNode); + } + } + } + } +} + +// END COPYING HERE +// ********************BLACKBOX END****************** + + +// ---- USAGE (main) ---- +public class GraphX { + public static void main(String[] args) { + + // Example 1: Integer nodes + Graph g1 = new Graph(5, false); + g1.addEdge(0, 1); + g1.addEdge(1, 2); + g1.addEdge(2, 3); + g1.addEdge(3, 4); + + BFS bfs1 = new BFS(g1); + bfs1.run(0); + System.out.println("Integer nodes BFS from 0:"); + for (int node = 0; node < 5; node++) { + System.out.println(" dist to " + node + " = " + bfs1.minDist(node)); + } + + // Example 2: 2D tuple nodes (grid coordinates) + Graph g2 = new Graph(9, false); + g2.addEdge(0, 0, 0, 1); + g2.addEdge(0, 1, 0, 2); + g2.addEdge(0, 2, 1, 2); + + BFS bfs2 = new BFS(g2); + bfs2.run(0, 0); + System.out.println("\n2D tuple nodes BFS from (0,0):"); + int[][] nodes2D = {{0,0},{0,1},{0,2},{1,2}}; + for (int[] node : nodes2D) { + System.out.println(" dist to (" + node[0] + "," + node[1] + ") = " + + bfs2.minDist(node[0], node[1])); + } + + // Example 3: 3D tuple nodes + Graph g3 = new Graph(4, false); + g3.addEdge(0, 0, 0, 0, 0, 1); + g3.addEdge(0, 0, 1, 0, 1, 1); + + BFS bfs3 = new BFS(g3); + bfs3.run(0, 0, 0); + System.out.println("\n3D tuple nodes BFS from (0,0,0):"); + int[][] nodes3D = {{0,0,0},{0,0,1},{0,1,1}}; + for (int[] node : nodes3D) { + System.out.println(" dist to (" + node[0] + "," + node[1] + "," + node[2] + ") = " + + bfs3.minDist(node[0], node[1], node[2])); + } + } +} \ No newline at end of file diff --git a/GraphX.py b/GraphX.py new file mode 100644 index 0000000..1e4d0ae --- /dev/null +++ b/GraphX.py @@ -0,0 +1,132 @@ +from collections import defaultdict, deque + +# ****************BLACKBOX START***************** +# START COPYING FROM HERE + +class Hash: + def __init__(self): + self.hash_table = {} + + def hash(self, x): + # Normalize input to a tuple of 3 ints + if isinstance(x, int): + key = (x, 0, 0) + elif isinstance(x, tuple): + if len(x) == 2: + key = (x[0], x[1], 0) + elif len(x) == 3: + key = x + else: + raise ValueError("Tuple must have 2 or 3 elements") + else: + raise TypeError(f"Unsupported type: {type(x)}") + + if key not in self.hash_table: + self.hash_table[key] = len(self.hash_table) + return self.hash_table[key] + + +class Graph: + N = 5000000 + + def __init__(self, n, is_directed=True): + self.n = n + self.is_directed = is_directed + self.adj = defaultdict(list) # sparse, no need to pre-allocate N slots + self.h = Hash() + + def hash(self, u, v, k=None): + if k is None: + return self.h.hash((u, v)) + return self.h.hash((u, v, k)) + + def add_edge(self, u_raw, v_raw, c=0): + u = self.h.hash(u_raw) + v = self.h.hash(v_raw) + self._add_edge_internal(u, v, c) + + def _add_edge_internal(self, u, v, c=0): + self._add_edge_weighted_undirected(u, v, c) + if not self.is_directed: + self._add_edge_weighted_undirected(v, u, c) + + def _add_edge_weighted_undirected(self, u, v, c): + self.adj[u].append((v, c)) + + +class BFS: + def __init__(self, graph): + self.g = graph + self.clear() + + def clear(self): + self.min_dist_from_source = defaultdict(lambda: -1) + self.visited = defaultdict(bool) + + def run(self, source_raw): + source = self.g.h.hash(source_raw) + self._run_internal(source) + + def min_dist(self, target_raw): + target = self.g.h.hash(target_raw) + return self.min_dist_from_source[target] + + def is_visited(self, target_raw): + target = self.g.h.hash(target_raw) + return self.visited[target] + + def _run_internal(self, source): + q = deque() + q.append(source) + self.visited[source] = True + self.min_dist_from_source[source] = 0 + + while q: + cur_node = q.popleft() + for adj_node, _ in self.g.adj[cur_node]: + if not self.visited[adj_node]: + self.visited[adj_node] = True + self.min_dist_from_source[adj_node] = self.min_dist_from_source[cur_node] + 1 + q.append(adj_node) + +# END COPYING HERE +# ********************BLACKBOX END****************** + + +# ---- USAGE (main) ---- +if __name__ == "__main__": + # Example 1: Integer nodes + g1 = Graph(n=5, is_directed=False) + g1.add_edge(0, 1) + g1.add_edge(1, 2) + g1.add_edge(2, 3) + g1.add_edge(3, 4) + + bfs1 = BFS(g1) + bfs1.run(0) + print("Integer nodes BFS from 0:") + for node in range(5): + print(f" dist to {node} = {bfs1.min_dist(node)}") + + # Example 2: 2D tuple nodes (e.g., grid coordinates) + g2 = Graph(n=9, is_directed=False) + g2.add_edge((0, 0), (0, 1)) + g2.add_edge((0, 1), (0, 2)) + g2.add_edge((0, 2), (1, 2)) + + bfs2 = BFS(g2) + bfs2.run((0, 0)) + print("\n2D tuple nodes BFS from (0,0):") + for node in [(0,0), (0,1), (0,2), (1,2)]: + print(f" dist to {node} = {bfs2.min_dist(node)}") + + # Example 3: 3D tuple nodes + g3 = Graph(n=4, is_directed=False) + g3.add_edge((0, 0, 0), (0, 0, 1)) + g3.add_edge((0, 0, 1), (0, 1, 1)) + + bfs3 = BFS(g3) + bfs3.run((0, 0, 0)) + print("\n3D tuple nodes BFS from (0,0,0):") + for node in [(0,0,0), (0,0,1), (0,1,1)]: + print(f" dist to {node} = {bfs3.min_dist(node)}") \ No newline at end of file