diff --git a/src/main/java/m1graphs2025/Edge.java b/src/main/java/m1graphs2025/Edge.java index 9bb4742b3be25651b1b1eedac580d0214becf927..14ef5e012baf8941461d3849cd8f4a2920566b49 100644 --- a/src/main/java/m1graphs2025/Edge.java +++ b/src/main/java/m1graphs2025/Edge.java @@ -36,6 +36,12 @@ public class Edge implements Comparable { this.weight = null; } + public Edge() { + this.from = null; + this.to = null; + this.weight = null; + } + /** Arête pondérée */ public Edge(Node from, Node to, Integer weight) { this.from = from; @@ -90,24 +96,47 @@ public class Edge implements Comparable { // Getters / Setters // ====================== - public Node getNodeFrom() { return from; } - public Node getNodeTo() { return to; } - public Integer getWeight() { return weight; } + public Node getNodeFrom() { + return from; + } + + public Node getNodeTo() { + return to; + } + + public Integer getWeight() { + return weight; + } - public void setNodeFrom(Node from) { this.from = from; } - public void setNodeTo(Node to) { this.to = to; } - public void setWeight(Integer weight) { this.weight = weight; } + public void setNodeFrom(Node from) { + this.from = from; + } + + public void setNodeTo(Node to) { + this.to = to; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } // ====================== // Méthodes fonctionnelles // ====================== - public Node from() { return from; } - public Node to() { return to; } + public Node from() { + return from; + } + + public Node to() { + return to; + } /** * Retourne une arête symétrique (inversée) avec la même pondération. - * @return une nouvelle arête inversée ou null si les nœuds n’appartiennent pas au même graphe. + * + * @return une nouvelle arête inversée ou null si les nœuds n’appartiennent pas + * au même graphe. */ public Edge getSymmetric() { Graph g1 = (from != null) ? from.getGraph() : null; @@ -133,12 +162,14 @@ public class Edge implements Comparable { * mais avec un poids différent (arête multiple). */ public boolean isMultiEdge() { - if (from == null || from.getGraph() == null) return false; + if (from == null || from.getGraph() == null) + return false; Graph graph = from.getGraph(); List edges = graph.adjEdList.get(from); - if (edges == null) return false; + if (edges == null) + return false; for (Edge edge : edges) { boolean sameNodes = edge.from.getId() == this.from.getId() @@ -171,10 +202,12 @@ public class Edge implements Comparable { int w2 = (other.weight == null) ? 0 : other.weight; int cmp = Integer.compare(w1, w2); - if (cmp != 0) return cmp; + if (cmp != 0) + return cmp; cmp = Integer.compare(this.from.getId(), other.from.getId()); - if (cmp != 0) return cmp; + if (cmp != 0) + return cmp; return Integer.compare(this.to.getId(), other.to.getId()); } @@ -185,8 +218,10 @@ public class Edge implements Comparable { */ @Override public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Edge edge)) return false; + if (this == o) + return true; + if (!(o instanceof Edge edge)) + return false; return Objects.equals(from, edge.from) && Objects.equals(to, edge.to) && Objects.equals(weight, edge.weight); diff --git a/src/main/java/m1graphs2025/Graph.java b/src/main/java/m1graphs2025/Graph.java index 771164021afa18dd40a22636a71ac66acffaa59c..f565262a07584ec06b0d3675f8976c0cf14baa74 100644 --- a/src/main/java/m1graphs2025/Graph.java +++ b/src/main/java/m1graphs2025/Graph.java @@ -1,5 +1,7 @@ package m1graphs2025; +import java.io.BufferedReader; +import java.io.FileReader; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -96,7 +98,8 @@ public class Graph { return null; } for (Node entry : adjEdList.keySet()) { - if (entry != null && entry.getId() == id) return entry; + if (entry != null && entry.getId() == id) + return entry; } System.err.println("Aucun nœud trouvé avec l’id " + id + "."); return null; @@ -170,7 +173,6 @@ public class Graph { } } - public boolean removeNode() { return removeNode(0); } @@ -237,7 +239,8 @@ public class Graph { try { return n.getSuccessors(); } catch (Exception e) { - System.err.println("Erreur lors de la récupération des successeurs du nœud " + n.getId() + ": " + e.getMessage()); + System.err.println( + "Erreur lors de la récupération des successeurs du nœud " + n.getId() + ": " + e.getMessage()); return List.of(); } } @@ -259,7 +262,8 @@ public class Graph { try { return n.getSuccessorsMulti(); } catch (Exception e) { - System.err.println("Erreur lors de la récupération des successeurs multiples du nœud " + n.getId() + ": " + e.getMessage()); + System.err.println("Erreur lors de la récupération des successeurs multiples du nœud " + n.getId() + ": " + + e.getMessage()); return List.of(); } } @@ -281,7 +285,8 @@ public class Graph { try { return u.adjacent(v); } catch (Exception e) { - System.err.println("Erreur lors de la vérification de l’adjacence entre " + u.getId() + " et " + v.getId() + ": " + e.getMessage()); + System.err.println("Erreur lors de la vérification de l’adjacence entre " + u.getId() + " et " + v.getId() + + ": " + e.getMessage()); return false; } } @@ -368,7 +373,8 @@ public class Graph { public int nbEdges() { int count = 0; - for (List edges : adjEdList.values()) count += edges.size(); + for (List edges : adjEdList.values()) + count += edges.size(); return count; } @@ -378,7 +384,8 @@ public class Graph { throw new IllegalArgumentException("Les nœuds ne peuvent pas être null."); } for (Edge e : adjEdList.getOrDefault(u, Collections.emptyList())) { - if (e.getNodeTo().equals(v)) return true; + if (e.getNodeTo().equals(v)) + return true; } return false; } catch (Exception ex) { @@ -451,8 +458,10 @@ public class Graph { if (from == null || to == null) { throw new IllegalArgumentException("Les nœuds source et destination ne peuvent pas être null."); } - if (!usesNode(from)) addNode(from); - if (!usesNode(to)) addNode(to); + if (!usesNode(from)) + addNode(from); + if (!usesNode(to)) + addNode(to); adjEdList.get(from).add(new Edge(from, to)); } catch (Exception ex) { System.err.println("Erreur dans addEdge(Node, Node) : " + ex.getMessage()); @@ -466,8 +475,10 @@ public class Graph { } Node from = getNode(fromId); Node to = getNode(toId); - if (from == null) from = new Node(fromId, this); - if (to == null) to = new Node(toId, this); + if (from == null) + from = new Node(fromId, this); + if (to == null) + to = new Node(toId, this); addEdge(from, to); } catch (Exception ex) { System.err.println("Erreur dans addEdge(int, int) : " + ex.getMessage()); @@ -497,8 +508,10 @@ public class Graph { if (weight < 0) { throw new IllegalArgumentException("Le poids doit être positif ou nul."); } - if (!usesNode(from)) addNode(from); - if (!usesNode(to)) addNode(to); + if (!usesNode(from)) + addNode(from); + if (!usesNode(to)) + addNode(to); adjEdList.get(from).add(new Edge(from, to, weight)); } catch (Exception ex) { System.err.println("Erreur dans addEdge(Node, Node, int) : " + ex.getMessage()); @@ -515,8 +528,10 @@ public class Graph { } Node from = getNode(fromId); Node to = getNode(toId); - if (from == null) from = new Node(fromId, this); - if (to == null) to = new Node(toId, this); + if (from == null) + from = new Node(fromId, this); + if (to == null) + to = new Node(toId, this); addEdge(from, to, weight); } catch (Exception ex) { System.err.println("Erreur dans addEdge(int, int, int) : " + ex.getMessage()); @@ -533,8 +548,10 @@ public class Graph { } Node from = getNode(fromId); Node to = getNode(toId); - if (from == null) from = new Node(fromId, g); - if (to == null) to = new Node(toId, g); + if (from == null) + from = new Node(fromId, g); + if (to == null) + to = new Node(toId, g); addEdge(from, to); } catch (Exception ex) { System.err.println("Erreur dans addEdge(int, int, Graph) : " + ex.getMessage()); @@ -619,7 +636,8 @@ public class Graph { List result = new ArrayList<>(); for (List edges : adjEdList.values()) { for (Edge e : edges) { - if (e.getNodeTo().equals(n)) result.add(e); + if (e.getNodeTo().equals(n)) + result.add(e); } } return result; @@ -682,7 +700,8 @@ public class Graph { } List result = new ArrayList<>(); for (Edge e : adjEdList.getOrDefault(u, Collections.emptyList())) { - if (e.getNodeTo().equals(v)) result.add(e); + if (e.getNodeTo().equals(v)) + result.add(e); } return result; } catch (Exception ex) { @@ -694,7 +713,8 @@ public class Graph { public List getAllEdges() { try { List result = new ArrayList<>(); - for (List edges : adjEdList.values()) result.addAll(edges); + for (List edges : adjEdList.values()) + result.addAll(edges); return result; } catch (Exception ex) { System.err.println("Erreur dans getAllEdges() : " + ex.getMessage()); @@ -732,7 +752,8 @@ public class Graph { public Graph getReverse() { Map> reversed = new HashMap<>(); - for (Node n : adjEdList.keySet()) reversed.put(n, new ArrayList<>()); + for (Node n : adjEdList.keySet()) + reversed.put(n, new ArrayList<>()); for (Node u : adjEdList.keySet()) { for (Edge e : adjEdList.get(u)) { Node from = e.getNodeTo(); @@ -751,7 +772,8 @@ public class Graph { for (Node i : nodes) { for (Node j : nodes) { if (closure.existsEdge(i, k) && closure.existsEdge(k, j)) { - if (!closure.existsEdge(i, j)) closure.addEdge(i, j); + if (!closure.existsEdge(i, j)) + closure.addEdge(i, j); } } } @@ -765,7 +787,8 @@ public class Graph { Set seen = new HashSet<>(); for (Edge e : edges) { Node to = e.getNodeTo(); - if (seen.contains(to)) return true; + if (seen.contains(to)) + return true; seen.add(to); } } @@ -775,7 +798,8 @@ public class Graph { public boolean hasSelfLoops() { for (Node u : adjEdList.keySet()) { for (Edge e : adjEdList.get(u)) { - if (e.getNodeTo().equals(u)) return true; + if (e.getNodeTo().equals(u)) + return true; } } return false; @@ -787,7 +811,8 @@ public class Graph { public Graph toSimpleGraph() { Graph g = new Graph(new HashMap<>()); - for (Node u : adjEdList.keySet()) g.addNode(new Node(u.getId(), g)); + for (Node u : adjEdList.keySet()) + g.addNode(new Node(u.getId(), g)); for (Node u : adjEdList.keySet()) { Set seen = new HashSet<>(); for (Edge e : adjEdList.get(u)) { @@ -805,7 +830,8 @@ public class Graph { Map> copy = new HashMap<>(); for (Node u : adjEdList.keySet()) { List list = new ArrayList<>(); - for (Edge e : adjEdList.get(u)) list.add(new Edge(e.getNodeFrom(), e.getNodeTo(), e.getWeight())); + for (Edge e : adjEdList.get(u)) + list.add(new Edge(e.getNodeFrom(), e.getNodeTo(), e.getWeight())); copy.put(u, list); } return new Graph(copy); @@ -859,7 +885,9 @@ public class Graph { public List getBFS() { List visited = new ArrayList<>(); Map infos = initVisitInfo(); - for (Node s : sortNodes()) if (infos.get(s).getColour() == NodeColour.WHITE) BFSVisit(s, infos, visited); + for (Node s : sortNodes()) + if (infos.get(s).getColour() == NodeColour.WHITE) + BFSVisit(s, infos, visited); return visited; } @@ -900,7 +928,7 @@ public class Graph { // ====================== public List getDFSWithVisitInfo(Map nodeVisit, - Map edgeVisit) { + Map edgeVisit) { List visited = new ArrayList<>(); AtomicInteger time = new AtomicInteger(0); initVisitInfo(nodeVisit); @@ -912,8 +940,8 @@ public class Graph { } public List getDFSWithVisitInfo(Node start, - Map nodeVisit, - Map edgeVisit) { + Map nodeVisit, + Map edgeVisit) { List visited = new ArrayList<>(); AtomicInteger time = new AtomicInteger(0); initVisitInfo(nodeVisit); @@ -922,9 +950,9 @@ public class Graph { } private void DFSVisitEnriched(Node u, AtomicInteger time, - Map nodeVisit, - Map edgeVisit, - List visited) { + Map nodeVisit, + Map edgeVisit, + List visited) { time.incrementAndGet(); nodeVisit.get(u).setDiscoveryTime(time.get()); nodeVisit.get(u).setColour(NodeColour.GRAY); @@ -955,57 +983,35 @@ public class Graph { // DOT I/O // ====================== - public static Graph fromDotFile(String filename) { return fromDotFile(filename, ".gv"); } - - public static Graph fromDotFile(String filename, String ext) { - if (ext == null) ext = ".gv"; - if (!ext.startsWith(".")) ext = "." + ext; - Path path = Path.of(filename + ext); - Map> adj = new HashMap<>(); - - Pattern linePattern = Pattern.compile("^\\s*(\\d+)\\s*(--|->)\\s*(\\d+)\\s*(?:\\[(.*?)\\])?\\s*;?\\s*$"); - - List lines; - try { lines = Files.readAllLines(path, StandardCharsets.UTF_8); } - catch (IOException e) { return new Graph(adj); } - - for (String rawLine : lines) { - String line = rawLine.trim(); - if (line.isEmpty() || line.startsWith("digraph") || line.startsWith("graph") || line.startsWith("{") || line.startsWith("}")) - continue; - Matcher m = linePattern.matcher(line); - if (m.matches()) { - int fromId = Integer.parseInt(m.group(1)); - String op = m.group(2); - int toId = Integer.parseInt(m.group(3)); - String attr = m.group(4); - - Node from = adj.keySet().stream().filter(n -> n.getId() == fromId).findFirst().orElseGet(() -> { - Node nn = new Node(fromId, null); - adj.put(nn, new ArrayList<>()); - return nn; - }); - Node to = adj.keySet().stream().filter(n -> n.getId() == toId).findFirst().orElseGet(() -> { - Node nn = new Node(toId, null); - adj.put(nn, new ArrayList<>()); - return nn; - }); - - Integer weight = null; - if (attr != null) { - Matcher mW = Pattern.compile("len\\s*=\\s*(\\d+)").matcher(attr); - if (mW.find()) weight = Integer.parseInt(mW.group(1)); + public static Graph fromDotFile(String filename) { + BufferedReader dot = new BufferedReader(new FileReader(filename)); + Map> adjEdList = new HashMap<>(); + Graph g = new Graph(adjEdList); + BufferedReader dot = new BufferedReader(new FileReader(filename)); + List nodes = new ArrayList<>(); + + String line = dot.readLine(); + while (line != null) { + int iteration = 0; + Edge edge = new Edge(); + Node nFrom = new Node(); + Node nTo = new Node(); + String[] tokens = line.split("[^0-9]"); + if (!tokens[0].equals("")) { + if (!nodes.contains(Integer.parseInt(tokens[0]))) { + List listEdges = new ArrayList<>(); } - - if (weight == null) adj.get(from).add(new Edge(from, to)); - else adj.get(from).add(new Edge(from, to, weight)); - if (op.equals("--")) { - if (weight == null) adj.get(to).add(new Edge(to, from)); - else adj.get(to).add(new Edge(to, from, weight)); + nFrom.setId(Integer.parseInt(tokens[0])); + edge.setNodeFrom(nFrom); + nTo.setId(Integer.parseInt(tokens[1])); + edge.setNodeTo(nTo); + if (tokens[2] != "") { + edge.setWeight(Integer.parseInt(tokens[2])); } + } + } - return new Graph(adj); } public String toDotString() { @@ -1025,13 +1031,20 @@ public class Graph { return sb.toString(); } - public void toDotFile(String filename) { toDotFile(filename, ".gv"); } + public void toDotFile(String filename) { + toDotFile(filename, ".gv"); + } public void toDotFile(String filename, String ext) { - if (ext == null) ext = ".gv"; - if (!ext.startsWith(".")) ext = "." + ext; - try { Files.writeString(Path.of(filename + ext), toDotString(), StandardCharsets.UTF_8); } - catch (IOException e) { e.printStackTrace(); } + if (ext == null) + ext = ".gv"; + if (!ext.startsWith(".")) + ext = "." + ext; + try { + Files.writeString(Path.of(filename + ext), toDotString(), StandardCharsets.UTF_8); + } catch (IOException e) { + e.printStackTrace(); + } } // ====================== @@ -1040,12 +1053,14 @@ public class Graph { private Map initVisitInfo() { Map map = new HashMap<>(); - for (Node n : adjEdList.keySet()) map.put(n, new NodeVisitInfo()); + for (Node n : adjEdList.keySet()) + map.put(n, new NodeVisitInfo()); return map; } private void initVisitInfo(Map map) { - for (Node n : adjEdList.keySet()) map.put(n, new NodeVisitInfo()); + for (Node n : adjEdList.keySet()) + map.put(n, new NodeVisitInfo()); } private List sortNodes() { diff --git a/src/main/java/m1graphs2025/Node.java b/src/main/java/m1graphs2025/Node.java index ebd69ea5262c1ba5b8215960d52355e6a92c9bf7..40fa05e248bc4068e50919dd5fe17f9ec462ab90 100644 --- a/src/main/java/m1graphs2025/Node.java +++ b/src/main/java/m1graphs2025/Node.java @@ -39,6 +39,10 @@ public class Node implements Comparable { this.id = id; this.graph = graph; } + public Node(){ + this.id = 0; + this.graph = null; + } /** * Construit un nœud avec un identifiant, un graphe et un nom. diff --git a/src/main/java/m1graphs2025/TestGraphsPW2.java b/src/main/java/m1graphs2025/TestGraphsPW2.java index 463c541a80c0959083ed3759a93dbb95777a551c..6f9fb9b84331dd56967c7253361da598d2dcfd0c 100644 --- a/src/main/java/m1graphs2025/TestGraphsPW2.java +++ b/src/main/java/m1graphs2025/TestGraphsPW2.java @@ -14,29 +14,30 @@ public class TestGraphsPW2 { System.out.println(">>>>>>>> Creating the subject example graph in G"); Graph g = new Graph(2, 4, 0, 0, 6, 0, 2, 3, 5, 8, 0, 0, 4, 7, 0, 3, 0, 7, 0); System.out.println(">>>> Graph information"); - System.out.println(">> DOT representation\n"+g.toDotString()); - System.out.println(""+g.nbNodes()+" nodes, "+g.nbEdges()+" edges"); + System.out.println(">> DOT representation\n" + g.toDotString()); + System.out.println("" + g.nbNodes() + " nodes, " + g.nbEdges() + " edges"); System.out.println(">> Nodes: "); List nodes = g.getAllNodes(); Collections.sort(nodes); - for (Node n: nodes) - System.out.println("Node "+n+": degree "+g.degree(n)+" (in: "+g.inDegree(n)+"/ out: "+g.outDegree(n)+")"); + for (Node n : nodes) + System.out.println("Node " + n + ": degree " + g.degree(n) + " (in: " + g.inDegree(n) + "/ out: " + + g.outDegree(n) + ")"); List edges; System.out.println(">> Edges: "); System.out.println("---------------------------"); System.out.println("Out-edges per node"); - for (Node n: nodes) { + for (Node n : nodes) { edges = g.getOutEdges(n); Collections.sort(edges); - System.out.println(""+n+": "+edges); + System.out.println("" + n + ": " + edges); } System.out.println("In-edges per node"); - for (Node n: nodes) { + for (Node n : nodes) { edges = g.getInEdges(n); Collections.sort(edges); - System.out.println(""+n+": "+edges); + System.out.println("" + n + ": " + edges); } ///////////////////////////////////////////////////// @@ -46,37 +47,38 @@ public class TestGraphsPW2 { System.out.println("Error: failed to create node 12"); System.out.println("Graph now:"); System.out.println(g.toDotString()); - System.out.println(""+g.nbNodes()+" nodes, "+g.nbEdges()+" edges"); + System.out.println("" + g.nbNodes() + " nodes, " + g.nbEdges() + " edges"); nodes = g.getAllNodes(); Collections.sort(nodes); - System.out.println("Nodes list: "+nodes); + System.out.println("Nodes list: " + nodes); System.out.println("\n>>>>>>>> Removing node 3"); g.removeNode(3); System.out.println("Graph now:"); System.out.println(g.toDotString()); - System.out.println(""+g.nbNodes()+" nodes, "+g.nbEdges()+" edges"); + System.out.println("" + g.nbNodes() + " nodes, " + g.nbEdges() + " edges"); nodes = g.getAllNodes(); Collections.sort(nodes); - System.out.println("Nodes list: "+nodes); + System.out.println("Nodes list: " + nodes); System.out.println(">> Edges: "); System.out.println("---------------------------"); System.out.println("Out-edges per node"); - for (Node n: nodes) { + for (Node n : nodes) { edges = g.getOutEdges(n); Collections.sort(edges); - System.out.println(""+n+": "+edges); + System.out.println("" + n + ": " + edges); } System.out.println("In-edges per node"); - for (Node n: nodes) { + for (Node n : nodes) { edges = g.getInEdges(n); Collections.sort(edges); - System.out.println(""+n+": "+edges); + System.out.println("" + n + ": " + edges); } - System.out.println("\n>>>>>>>> Recreating edges (4, 3), (3, 6), (7, 3), adding edge (12, 3), creating edge (3, 25)"); + System.out.println( + "\n>>>>>>>> Recreating edges (4, 3), (3, 6), (7, 3), adding edge (12, 3), creating edge (3, 25)"); g.addEdge(new Edge(4, 3, g)); g.addEdge(new Edge(3, 6, g)); g.addEdge(new Edge(7, 3, g)); @@ -84,10 +86,10 @@ public class TestGraphsPW2 { g.addEdge(3, 25); System.out.println("Graph now:"); System.out.println(g.toDotString()); - System.out.println(""+g.nbNodes()+" nodes, "+g.nbEdges()+" edges"); + System.out.println("" + g.nbNodes() + " nodes, " + g.nbEdges() + " edges"); nodes = g.getAllNodes(); Collections.sort(nodes); - System.out.println("Nodes list: "+nodes); + System.out.println("Nodes list: " + nodes); System.out.println(""); System.out.println("\n>>>>>>>> Edges removal"); @@ -96,7 +98,8 @@ public class TestGraphsPW2 { g.removeEdge(4, 8); System.out.println(">>>> Removing absent edge (3, 4)"); g.removeEdge(3, 4); - System.out.println(">>>> Removing edges whith 1 or 2 not existing end-points: (-3, 4), (6, 0), (4, 11), (-1, -2), (13, 3), (9, 10)"); + System.out.println( + ">>>> Removing edges whith 1 or 2 not existing end-points: (-3, 4), (6, 0), (4, 11), (-1, -2), (13, 3), (9, 10)"); g.removeEdge(-3, 4); g.removeEdge(6, 0); g.removeEdge(4, 11); @@ -106,49 +109,49 @@ public class TestGraphsPW2 { System.out.println("Graph now:"); System.out.println(g.toDotString()); - System.out.println(""+g.nbNodes()+" nodes, "+g.nbEdges()+" edges"); + System.out.println("" + g.nbNodes() + " nodes, " + g.nbEdges() + " edges"); nodes = g.getAllNodes(); Collections.sort(nodes); - System.out.println("Nodes list: "+nodes); + System.out.println("Nodes list: " + nodes); - System.out.println("\nTesting that getSuccessors and getSuccessorsMulti give the same result for the simple graph:"); + System.out.println( + "\nTesting that getSuccessors and getSuccessorsMulti give the same result for the simple graph:"); boolean same = true; - for (Node u: nodes) { + for (Node u : nodes) { List succs = g.getSuccessors(u), succsMulti = g.getSuccessorsMulti(u); // sort the lists so that nodes always appear in the same order Collections.sort(succs); Collections.sort(succsMulti); same = same && succs.equals(succsMulti); } - System.out.println("\tgetSuccessors and getSuccessorsMulti "+(same?"are identical":"differ")); - - + System.out.println("\tgetSuccessors and getSuccessorsMulti " + (same ? "are identical" : "differ")); System.out.println("\n>>>>>>>> MULTIGRAPH: adding a self-loop on node 6, and a second edge (1, 4)"); g.addEdge(6, 6); g.addEdge(1, 4); System.out.println("Graph now:"); System.out.println(g.toDotString()); - System.out.println(""+g.nbNodes()+" nodes, "+g.nbEdges()+" edges"); + System.out.println("" + g.nbNodes() + " nodes, " + g.nbEdges() + " edges"); nodes = g.getAllNodes(); Collections.sort(nodes); - System.out.println("Nodes list: "+nodes); - System.out.println("Degree of node 6: "+g.degree(6)+" (in: "+g.inDegree(6)+"/ out: "+g.outDegree(6)+")"); + System.out.println("Nodes list: " + nodes); + System.out.println( + "Degree of node 6: " + g.degree(6) + " (in: " + g.inDegree(6) + "/ out: " + g.outDegree(6) + ")"); System.out.println(">> Edges: "); System.out.println("---------------------------"); System.out.println("Out-edges per node"); - for (Node n: nodes) { + for (Node n : nodes) { edges = g.getOutEdges(n); Collections.sort(edges); - System.out.println(""+n+": "+edges); + System.out.println("" + n + ": " + edges); } System.out.println("In-edges per node"); - for (Node n: nodes) { + for (Node n : nodes) { edges = g.getInEdges(n); Collections.sort(edges); - System.out.println(""+n+": "+edges); + System.out.println("" + n + ": " + edges); } System.out.println("\n>>>>>>>>>> Get the reverse graph"); @@ -159,7 +162,7 @@ public class TestGraphsPW2 { System.out.println(">>>>>>>>>> Emptying the graph by removing all its nodes"); nodes = g.getAllNodes(); - for (Node u: nodes) + for (Node u : nodes) g.removeNode(u); System.out.println("Graph now:"); System.out.println(g.toDotString()); @@ -182,7 +185,7 @@ public class TestGraphsPW2 { System.out.println("*------------------------------------------------------------------*"); System.out.println("\n>>> Graph with isolated nodes: reading file 'isolatedNodes.gv'"); Graph gin = Graph.fromDotFile("isolatedNodes"); - if (gin==null) + if (gin == null) System.out.println("Null graph was created from 'isolatedNodes.gv'"); else { System.out.println("Read: OK. The graph with isolated nodes has been read as:"); @@ -193,7 +196,7 @@ public class TestGraphsPW2 { System.out.println(">>> Simple graph: reading file 'simpleGraph.gv'"); Graph sg = Graph.fromDotFile("simpleGraph"); - if (sg==null) + if (sg == null) System.out.println("Null graph was created from 'simpleGraph.gv'"); else { System.out.println("Read: OK. The simple graph has been read as:"); @@ -204,7 +207,7 @@ public class TestGraphsPW2 { System.out.println("\n>>> Multi-graph: reading file 'multiGraph.gv'"); Graph mg = Graph.fromDotFile("multiGraph"); - if (mg==null) + if (mg == null) System.out.println("Null graph was created from 'multiGraph.gv'"); else { System.out.println("Read: OK. The multi-graph has been read as:"); @@ -214,17 +217,15 @@ public class TestGraphsPW2 { } System.out.println("Comparing single and multi successors per node for 'multiGraph.gv'"); - for (Node u: mg.getAllNodes()) { + for (Node u : mg.getAllNodes()) { List succs = mg.getSuccessors(u), succsMulti = mg.getSuccessorsMulti(u); // sort the lists so that nodes always appear in the same order Collections.sort(succs); Collections.sort(succsMulti); - System.out.println(""+u+" single successors: "+succs); - System.out.println(""+u+" multi successors: "+succsMulti); + System.out.println("" + u + " single successors: " + succs); + System.out.println("" + u + " multi successors: " + succsMulti); } - - System.out.println("\n\n"); System.out.println("*----------------------------------------------------------------------*"); System.out.println("************* PART 3. WEIGHTED DIRECTED GRAPHS ***********************"); @@ -234,7 +235,7 @@ public class TestGraphsPW2 { System.out.println("\n>>>>>>>>>>"); System.out.println("Reading a weighted directed simple graph from DOT file 'weightedSimpleGraph.gv'"); Graph wsg = Graph.fromDotFile("weightedSimpleGraph"); - if (wsg==null) + if (wsg == null) System.out.println("Null graph was created from 'weightedSimpleGraph.gv'"); else { System.out.println("Read: OK. The weighted directed simple graph has been read as:"); @@ -242,15 +243,15 @@ public class TestGraphsPW2 { System.out.println(wsg.toDotString()); System.out.println("---------------------"); - for (Edge e: wsg.getAllEdges()) + for (Edge e : wsg.getAllEdges()) totalEdgesWeight += e.getWeight(); - System.out.println("The sum of all edges weights equals "+totalEdgesWeight); + System.out.println("The sum of all edges weights equals " + totalEdgesWeight); } System.out.println("\n>>>>>>>>>>"); System.out.println("Reading a weighted directed multi graph from DOT file 'weightedMultiGraph.gv'"); Graph wmg = Graph.fromDotFile("weightedMultiGraph"); - if (wmg==null) + if (wmg == null) System.out.println("Null graph was created from 'weightedMultiGraph.gv'"); else { System.out.println("Read: OK. The weighted directed multi graph has been read as:"); @@ -259,113 +260,110 @@ public class TestGraphsPW2 { System.out.println("---------------------"); totalEdgesWeight = 0; - for (Edge e: wmg.getAllEdges()) + for (Edge e : wmg.getAllEdges()) totalEdgesWeight += e.getWeight(); - System.out.println("The sum of all edges weights equals "+totalEdgesWeight); + System.out.println("The sum of all edges weights equals " + totalEdgesWeight); } - - - System.out.println("\n\n"); System.out.println("*-------------------------------------------------------------------------*"); System.out.println("************ PART 4. UNDIRECTED UNWEIGHTED GRAPHS ***********************"); System.out.println("*-------------------------------------------------------------------------*"); System.out.println("\nCreating an undirected simple graph 'usg' from scracth"); - UndirectedGraph usg = new UndirectedGraph(2,3,0, 3,4,0, 4,0, 0); + UndirectedGraph usg = new UndirectedGraph(2, 3, 0, 3, 4, 0, 4, 0, 0); System.out.println(usg.toDotString()); - System.out.println("usg has "+usg.nbNodes()+" nodes and "+usg.nbEdges()+" edges."); + System.out.println("usg has " + usg.nbNodes() + " nodes and " + usg.nbEdges() + " edges."); System.out.println("\n>>>>>> usg: Counting degrees and showing successors"); - for (Node u: usg.getAllNodes()) { - System.out.println("Node "+u+". Degree: "+usg.degree(u.getId())+" (In: "+usg.inDegree(u.getId())+" / Out: "+usg.outDegree(u.getId())+")"); - System.out.println("\tSuccessors: "+usg.getSuccessors(u)); + for (Node u : usg.getAllNodes()) { + System.out.println("Node " + u + ". Degree: " + usg.degree(u.getId()) + " (In: " + usg.inDegree(u.getId()) + + " / Out: " + usg.outDegree(u.getId()) + ")"); + System.out.println("\tSuccessors: " + usg.getSuccessors(u)); } System.out.println(">>>>>> usg: Edges of the graph"); System.out.println("// N.B. The edges are printed as though they were directed. This is due to the toString()\n" + "// method that was not overridden. It is possible to do better but not important.\n" + "// What is important is that each edge appears only once per direction."); - System.out.println("All edges of the graph: "+usg.getAllEdges()); + System.out.println("All edges of the graph: " + usg.getAllEdges()); System.out.println("Out-edges per node"); - for (Node u: usg.getAllNodes()) - System.out.println(""+u+": "+usg.getOutEdges(u)); + for (Node u : usg.getAllNodes()) + System.out.println("" + u + ": " + usg.getOutEdges(u)); System.out.println("In-edges per node"); - for (Node u: usg.getAllNodes()) - System.out.println(""+u+": "+usg.getInEdges(u)); + for (Node u : usg.getAllNodes()) + System.out.println("" + u + ": " + usg.getInEdges(u)); System.out.println("Incident edges per node"); - for (Node u: usg.getAllNodes()) - System.out.println(""+u+": "+usg.getIncidentEdges(u)); + for (Node u : usg.getAllNodes()) + System.out.println("" + u + ": " + usg.getIncidentEdges(u)); System.out.println("Creating an undirected multi-graph with self-loops 'umg' from scratch"); - UndirectedGraph umg = new UndirectedGraph(1,1,2,2,3,0, 2,3,0, 0); + UndirectedGraph umg = new UndirectedGraph(1, 1, 2, 2, 3, 0, 2, 3, 0, 0); String dotUMG = umg.toDotString(); System.out.println(dotUMG); - System.out.println("umg has "+umg.nbNodes()+" nodes and "+umg.nbEdges()+" edges."); - + System.out.println("umg has " + umg.nbNodes() + " nodes and " + umg.nbEdges() + " edges."); System.out.println("\n>>>>>> umg: Counting degrees and showing successors"); - for (Node u: umg.getAllNodes()) { - System.out.println("Node "+u+". Degree: "+umg.degree(u.getId())+" (In: "+umg.inDegree(u.getId())+" / Out: "+umg.outDegree(u.getId())+")"); - System.out.println("\tSuccessors: "+umg.getSuccessors(u)); + for (Node u : umg.getAllNodes()) { + System.out.println("Node " + u + ". Degree: " + umg.degree(u.getId()) + " (In: " + umg.inDegree(u.getId()) + + " / Out: " + umg.outDegree(u.getId()) + ")"); + System.out.println("\tSuccessors: " + umg.getSuccessors(u)); } System.out.println(">>>>>> umg: Edges of the graph"); - System.out.println("All edges of the graph: "+umg.getAllEdges()); + System.out.println("All edges of the graph: " + umg.getAllEdges()); System.out.println("Out-edges per node"); - for (Node u: umg.getAllNodes()) - System.out.println(""+u+": "+umg.getOutEdges(u)); + for (Node u : umg.getAllNodes()) + System.out.println("" + u + ": " + umg.getOutEdges(u)); System.out.println("In-edges per node"); - for (Node u: umg.getAllNodes()) - System.out.println(""+u+": "+umg.getInEdges(u)); + for (Node u : umg.getAllNodes()) + System.out.println("" + u + ": " + umg.getInEdges(u)); System.out.println("Incident edges per node"); - for (Node u: umg.getAllNodes()) - System.out.println(""+u+": "+umg.getIncidentEdges(u)); + for (Node u : umg.getAllNodes()) + System.out.println("" + u + ": " + umg.getIncidentEdges(u)); System.out.println("\n>>>>>> umg: Successor Array, Adjacency Matrix, and Graph Reverse"); - System.out.println("umg Successor array\n"+Arrays.toString(umg.toSuccessorArray())); + System.out.println("umg Successor array\n" + Arrays.toString(umg.toSuccessorArray())); System.out.println("umg Adjacency Matrix"); - for (int[] row: umg.toAdjMatrix()) - System.out.println("\t"+Arrays.toString(row)); + for (int[] row : umg.toAdjMatrix()) + System.out.println("\t" + Arrays.toString(row)); System.out.println("Testing via toDotString() the equality with the reverse graph"); String dotRUMG = umg.getReverse().toDotString(); - System.out.println("DOT of the reverse of umg\n"+dotRUMG); - System.out.println("Graph gu and its reverse "+(dotUMG.equals(dotRUMG)?"are identical":"differ")); + System.out.println("DOT of the reverse of umg\n" + dotRUMG); + System.out.println("Graph gu and its reverse " + (dotUMG.equals(dotRUMG) ? "are identical" : "differ")); System.out.println("-----------------\n NOW a disconnected GRAPH \n----------------"); System.out.println("Building 'guDisc', a disconnected undirected graph with multi-edges and self-loops"); - UndirectedGraph guDisc = new UndirectedGraph(1,1,2,2,6,0, 2,3,6,0, 0, 6,0, 6,0, 0, 0, 9,10,0, 0, 0); + UndirectedGraph guDisc = new UndirectedGraph(1, 1, 2, 2, 6, 0, 2, 3, 6, 0, 0, 6, 0, 6, 0, 0, 0, 9, 10, 0, 0, 0); System.out.println(guDisc.toDotString()); // delete -// Graph guDisc2 = new Graph(1,1,2,2,6,0, 2,3,6,0, 0, 6,0, 6,0, 0, 0, 9,10,0, 0, 0); -// System.out.println(guDisc2.toDotString()); -// System.exit(0); - //end delete + // Graph guDisc2 = new Graph(1,1,2,2,6,0, 2,3,6,0, 0, 6,0, 6,0, 0, 0, 9,10,0, 0, + // 0); + // System.out.println(guDisc2.toDotString()); + // System.exit(0); + // end delete System.out.println("Comparing single and multi successors per node for guDisc"); - for (Node u: guDisc.getAllNodes()) { + for (Node u : guDisc.getAllNodes()) { List succs = guDisc.getSuccessors(u), succsMulti = guDisc.getSuccessorsMulti(u); // sort the lists so that nodes always appear in the same order Collections.sort(succs); Collections.sort(succsMulti); - System.out.println(""+u+" single successors: "+succs); - System.out.println(""+u+" multi successors: "+succsMulti); + System.out.println("" + u + " single successors: " + succs); + System.out.println("" + u + " multi successors: " + succsMulti); } - - System.out.println(">>>> DFS of guDisc: "+guDisc.getDFS()); - System.out.println(">>>> BFS of guDisc: "+guDisc.getBFS()); + System.out.println(">>>> DFS of guDisc: " + guDisc.getDFS()); + System.out.println(">>>> BFS of guDisc: " + guDisc.getBFS()); System.out.println(">>>>>>> Computing guDisc's transitive closure"); UndirectedGraph guDiscTC = (UndirectedGraph) guDisc.getTransitiveClosure(); System.out.println(guDiscTC.toDotString()); - System.out.println("\n\n"); System.out.println("*-----------------------------------------------------------------------*"); System.out.println("************ PART 5. UNDIRECTED WEIGHTED GRAPHS ***********************"); @@ -374,8 +372,8 @@ public class TestGraphsPW2 { System.out.println("\n>>>>>> Reading 'uwmg' an undirected weighted multi-graph with self loops\n" + "from file 'undirWeightedMultiGraph.gv'"); - UndirectedGraph uwmg = (UndirectedGraph) UndirectedGraph.fromDotFile("undirWeightedMultiGraph"); - if (uwmg==null) + UndirectedGraph uwmg = (UndirectedGraph) UndirectedGraph.fromDotFile("undirWeightedMultiGraph.gv"); + if (uwmg == null) System.out.println("Null graph was created from 'undirWeightedMultiGraph.gv'"); else { System.out.println("Read: OK. The undirected weighted multi-graph has been read as:"); @@ -384,43 +382,47 @@ public class TestGraphsPW2 { System.out.println("---------------------"); totalEdgesWeight = 0; - for (Edge e: uwmg.getAllEdges()) + for (Edge e : uwmg.getAllEdges()) totalEdgesWeight += e.getWeight(); - System.out.println("The sum of all edges weights equals "+totalEdgesWeight); + System.out.println("The sum of all edges weights equals " + totalEdgesWeight); } System.out.println("\nComparing single and multi successors per node for uwmg"); - for (Node u: uwmg.getAllNodes()) { + for (Node u : uwmg.getAllNodes()) { List succs = uwmg.getSuccessors(u), succsMulti = uwmg.getSuccessorsMulti(u); // sort the lists so that nodes always appear in the same order Collections.sort(succs); Collections.sort(succsMulti); - System.out.println(""+u+" single successors: "+succs); - System.out.println(""+u+" multi successors: "+succsMulti); + System.out.println("" + u + " single successors: " + succs); + System.out.println("" + u + " multi successors: " + succsMulti); } - - /* TO BE CONTINUED ... - System.out.println("\n\n"); - System.out.println("*-----------------------------------------------------------------------*"); - System.out.println("************ PART 6. DFS and Node Visit Info ***********************"); - System.out.println("*-----------------------------------------------------------------------*"); - - - // lecture example but undirected - UndirectedGraph gToVisit = new UndirectedGraph( - 2, 3, 4, 6, 0, //1 - 5, 6, 0, //2 - 4, 0, //3 - 8, 0, //4 - 6, 7, 8, 0, //5 - 7, 0, //6 - 8,0, //7 - 0 //8 - ); - System.out.println("\nAn undirected graph to visit:"); - System.out.println(gToVisit.toDotString()); - */ + /* + * TO BE CONTINUED ... + * System.out.println("\n\n"); + * System.out.println( + * "*-----------------------------------------------------------------------*"); + * System.out. + * println("************ PART 6. DFS and Node Visit Info ***********************" + * ); + * System.out.println( + * "*-----------------------------------------------------------------------*"); + * + * + * // lecture example but undirected + * UndirectedGraph gToVisit = new UndirectedGraph( + * 2, 3, 4, 6, 0, //1 + * 5, 6, 0, //2 + * 4, 0, //3 + * 8, 0, //4 + * 6, 7, 8, 0, //5 + * 7, 0, //6 + * 8,0, //7 + * 0 //8 + * ); + * System.out.println("\nAn undirected graph to visit:"); + * System.out.println(gToVisit.toDotString()); + */ } diff --git a/src/main/java/m1graphs2025/UndirectedGraph.java b/src/main/java/m1graphs2025/UndirectedGraph.java index afd49770085b23d0bcd8e121201362f16e4386ab..595e22fa7ec17da23e0307defd65b686f7e1d7d5 100644 --- a/src/main/java/m1graphs2025/UndirectedGraph.java +++ b/src/main/java/m1graphs2025/UndirectedGraph.java @@ -11,9 +11,12 @@ public class UndirectedGraph extends Graph { // ====================== // CONSTRUCTEURS // ====================== + public UndirectedGraph(Map> adjEdList) { + super(adjEdList); + } public UndirectedGraph() { - super(new HashMap<>()); // graphe vide + super(new HashMap<>()); // graphe vide } public UndirectedGraph(int... successorArray) { @@ -38,8 +41,10 @@ public class UndirectedGraph extends Graph { Node u = e.getNodeFrom(); Node v = e.getNodeTo(); if (!existsEdge(v, u)) { - if (e.isWeighted()) addEdge(v, u, e.getWeight()); - else addEdge(v, u); + if (e.isWeighted()) + addEdge(v, u, e.getWeight()); + else + addEdge(v, u); } } } @@ -52,32 +57,37 @@ public class UndirectedGraph extends Graph { public void addEdge(Node from, Node to) { super.addEdge(from, to); // Ajout symétrique - if (!existsEdge(to, from)) super.addEdge(to, from); + if (!existsEdge(to, from)) + super.addEdge(to, from); } @Override public void addEdge(int fromId, int toId) { super.addEdge(fromId, toId); - if (!existsEdge(toId, fromId)) super.addEdge(toId, fromId); + if (!existsEdge(toId, fromId)) + super.addEdge(toId, fromId); } @Override public void addEdge(Node from, Node to, int weight) { super.addEdge(from, to, weight); - if (!existsEdge(to, from)) super.addEdge(to, from, weight); + if (!existsEdge(to, from)) + super.addEdge(to, from, weight); } @Override public void addEdge(int fromId, int toId, int weight) { super.addEdge(fromId, toId, weight); - if (!existsEdge(toId, fromId)) super.addEdge(toId, fromId, weight); + if (!existsEdge(toId, fromId)) + super.addEdge(toId, fromId, weight); } @Override public void addEdge(Edge e) { super.addEdge(e); Edge sym = e.getSymmetric(); - if (sym != null && existsEdge(sym)) super.addEdge(sym); + if (sym != null && existsEdge(sym)) + super.addEdge(sym); } @Override @@ -119,6 +129,40 @@ public class UndirectedGraph extends Graph { return super.isMultiEdge(u, v) || super.isMultiEdge(v, u); } + @Override + public UndirectedGraph copy() { + Map> copy = new HashMap<>(); + for (Node u : adjEdList.keySet()) { + List list = new ArrayList<>(); + for (Edge e : adjEdList.get(u)) + list.add(new Edge(e.getNodeFrom(), e.getNodeTo(), e.getWeight())); + copy.put(u, list); + } + return new UndirectedGraph(copy); + } + + @Override + public UndirectedGraph getTransitiveClosure() { + UndirectedGraph closure = this.copy(); + List nodes = closure.getAllNodes(); + int n = nodes.size(); + for (Node k : nodes) { + for (Node i : nodes) { + for (Node j : nodes) { + if (closure.existsEdge(i, k) && closure.existsEdge(k, j)) { + if (!closure.existsEdge(i, j)) + closure.addEdge(i, j); + } + } + } + } + return closure; + } + + public static UndirectedGraph fromDotFile(String filename) { + return fromDotFile(filename, ".gv"); + } + // ====================== // Utilitaires // ====================== diff --git a/src/main/java/m1graphs2025/undirWeightedMultiGraph.gv b/src/main/java/m1graphs2025/undirWeightedMultiGraph.gv new file mode 100644 index 0000000000000000000000000000000000000000..ffaa40833c0e50a1a33a8ca925fe5b17808cf8e3 --- /dev/null +++ b/src/main/java/m1graphs2025/undirWeightedMultiGraph.gv @@ -0,0 +1,18 @@ +graph { + rankdir=LR + 1 -- 2 [label=4, len=4] + 1 -- 3 [label=3, len=3] + 1 -- 3 [label=6, len=6] + 1 -- 4 [label=0, len=0] + 2 -- 3 [label=1, len=1] + 2 -- 4 [label=2, len=2] + 2 -- 4 [label=50, len=50] + 2 -- 5 [label=3, len=3] + 3 -- 5 [label=2, len=2] + 4 -- 4 [label=14, len=14] + 4 -- 5 [label=2, len=2] + 5 -- 6 [label=7, len=7] + 5 -- 6 [label=10, len=10] + 6 -- 6 [label=5, len=5] + 6 -- 6 [label=8, len=8] +} \ No newline at end of file