From 6ac726725c4e4fb2441092e0843ded2d205e44a1 Mon Sep 17 00:00:00 2001 From: Ioana Cotutiu Date: Tue, 2 Mar 2021 16:39:55 +0200 Subject: [PATCH 1/5] add clique searching algorithm Added clique searching algorithm. Co-Authored-By: Theodor Andrei Moise <38431187+iriediese@users.noreply.github.com> Co-Authored-By: Nihm <24206687+Nihm@users.noreply.github.com> Co-Authored-By: johennin <52281498+johennin@users.noreply.github.com> Co-Authored-By: JoaBon <34160048+JoaBon@users.noreply.github.com> --- .../graphtheory/FindAllCliques.java | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/main/java/com/williamfiset/algorithms/graphtheory/FindAllCliques.java diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/FindAllCliques.java b/src/main/java/com/williamfiset/algorithms/graphtheory/FindAllCliques.java new file mode 100644 index 000000000..28fec20d6 --- /dev/null +++ b/src/main/java/com/williamfiset/algorithms/graphtheory/FindAllCliques.java @@ -0,0 +1,108 @@ +package com.williamfiset.algorithms.graphtheory; + +public class FindAllCliques { + static int size = 10000; + static int[] vertices = new int[size]; + static int n; + static int[][] graph = new int[size][size]; + static int[] degree = new int[size]; + + /** + * Function that checks if the given set of vertices + * in store array is a clique or not + * @param count number of vertices in the vertices array + * @return true id the current subgraph is a clique + * false otherwise + */ + static boolean isClique(int count) { + for (int i = 1; i < count; i++) { + for (int j = i + 1; j < count; j++) { + // If any edge is missing + if (graph[vertices[i]][vertices[j]] == 0) { + return false; + } + } + } + return true; + } + + /** + * Function that prints the clique + * @param n number of nodes in the clique + */ + static void print(int n) { + for (int i = 1; i < n; i++) { + if (i < n-1) { + System.out.print(vertices[i] + ", "); + } else { + System.out.print(vertices[i] + ";"); + System.out.println(); + } + } + } + + /** + * Function that finds all the cliques of size s + * @param i + * @param position + * @param s the vertex count of the searched clique + */ + static void findCliques(int i, int position, int s) { + // Check if any vertices from i+1 can be inserted + for (int j = i + 1; j <= n - (s - position); j++) { + + // If the degree of the graph is sufficient + if (degree[j] >= s - 1) { + + // Add the vertex to store + vertices[position] = j; + + // If the graph is not a clique of size k + // then it cannot be a clique + // by adding another edge + if (isClique(position + 1)) { + + // If the length of the clique is + // still less than the desired size + if (position < s) { + findCliques(j, position + 1, s); + } else { + print(position + 1); + } + } + } + } + } + + /** + * Function that finds all cliques + * @param edges + * @param n + */ + public static void findAllCliques(int[][] edges, int n){ + for (int[] edge : edges) { + graph[edge[0]][edge[1]] = 1; + graph[edge[1]][edge[0]] = 1; + degree[edge[0]]++; + degree[edge[1]]++; + } + + for (int i =1; i<= n; i++) { + findCliques(0, 1, i); + } + } + + public static void main(String[] args){ + int[][] edges = { + { 1, 2 }, + { 2, 3 }, + { 3, 1 }, + { 4, 3 }, + { 4, 5 }, + { 5, 3 }, + }; + n = 5; + + findAllCliques(edges, n); + } +} \ No newline at end of file From f0d31d53f635a4c323e0b4b925498772b782e22c Mon Sep 17 00:00:00 2001 From: Ioana Cotutiu Date: Wed, 3 Mar 2021 16:50:42 +0200 Subject: [PATCH 2/5] refactor class for finding all cliques Refactored the function for finding all cliques in a given graph. Changed code documentation. Refactored variable names. Refactored code. Co-Authored-By: Theodor Andrei Moise <38431187+iriediese@users.noreply.github.com> --- .../graphtheory/FindAllCliques.java | 56 +++++++++---------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/FindAllCliques.java b/src/main/java/com/williamfiset/algorithms/graphtheory/FindAllCliques.java index 28fec20d6..dfa5a51ce 100644 --- a/src/main/java/com/williamfiset/algorithms/graphtheory/FindAllCliques.java +++ b/src/main/java/com/williamfiset/algorithms/graphtheory/FindAllCliques.java @@ -1,5 +1,11 @@ package com.williamfiset.algorithms.graphtheory; +/** + * Finds all cliques (complete sub-graphs) in a given graph. + * The algorithm loops and finds all cliques for each given clique size up until the size of the graph itself. + * + * Complexity: O(n^2) + */ public class FindAllCliques { static int size = 10000; static int[] vertices = new int[size]; @@ -17,7 +23,7 @@ public class FindAllCliques { static boolean isClique(int count) { for (int i = 1; i < count; i++) { for (int j = i + 1; j < count; j++) { - // If any edge is missing + // for missing edges if (graph[vertices[i]][vertices[j]] == 0) { return false; } @@ -35,39 +41,31 @@ static void print(int n) { if (i < n-1) { System.out.print(vertices[i] + ", "); } else { - System.out.print(vertices[i] + ";"); - System.out.println(); + System.out.println(vertices[i]); } } } /** * Function that finds all the cliques of size s - * @param i - * @param position - * @param s the vertex count of the searched clique + * @param i initial index counter + * @param currentSize the size of the current sub-graph + * @param size the vertex count of the searched clique */ - static void findCliques(int i, int position, int s) { - // Check if any vertices from i+1 can be inserted - for (int j = i + 1; j <= n - (s - position); j++) { + static void findCliques(int i, int currentSize, int size) { + // Find insertable vertices + for (int j = i + 1; j <= n - (size - currentSize); j++) { + if (degree[j] >= size - 1) { + vertices[currentSize] = j; - // If the degree of the graph is sufficient - if (degree[j] >= s - 1) { + // Max subgraph size achieved + if (isClique(currentSize + 1)) { - // Add the vertex to store - vertices[position] = j; - - // If the graph is not a clique of size k - // then it cannot be a clique - // by adding another edge - if (isClique(position + 1)) { - - // If the length of the clique is - // still less than the desired size - if (position < s) { - findCliques(j, position + 1, s); + // Max subgraph size not yet achieved + if (currentSize < size) { + findCliques(j, currentSize + 1, size); } else { - print(position + 1); + print(currentSize + 1); } } } @@ -76,10 +74,11 @@ static void findCliques(int i, int position, int s) { /** * Function that finds all cliques - * @param edges - * @param n + * @param edges the list of edges formed with the nodes of the graph + * @param nodesNr the number of nodes of the graph */ - public static void findAllCliques(int[][] edges, int n){ + public static void findAllCliques(int[][] edges, int nodesNr){ + n = nodesNr; for (int[] edge : edges) { graph[edge[0]][edge[1]] = 1; graph[edge[1]][edge[0]] = 1; @@ -101,8 +100,7 @@ public static void main(String[] args){ { 4, 5 }, { 5, 3 }, }; - n = 5; - findAllCliques(edges, n); + findAllCliques(edges, 5); } } \ No newline at end of file From 8c31e7fd0495f3590fb20e66a5bf38c8b80fa7b3 Mon Sep 17 00:00:00 2001 From: Ioana Cotutiu Date: Wed, 3 Mar 2021 17:05:52 +0200 Subject: [PATCH 3/5] add tests for FindAllCliques Added test cases for FindAllCliques Co-Authored-By: Theodor Andrei Moise <38431187+iriediese@users.noreply.github.com> --- .../algorithms/dp/FindAllCliquesTest.java | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/test/java/com/williamfiset/algorithms/dp/FindAllCliquesTest.java diff --git a/src/test/java/com/williamfiset/algorithms/dp/FindAllCliquesTest.java b/src/test/java/com/williamfiset/algorithms/dp/FindAllCliquesTest.java new file mode 100644 index 000000000..4a8290cad --- /dev/null +++ b/src/test/java/com/williamfiset/algorithms/dp/FindAllCliquesTest.java @@ -0,0 +1,123 @@ +package com.williamfiset.algorithms.dp; + +import com.williamfiset.algorithms.graphtheory.FindAllCliques; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +public class FindAllCliquesTest { + private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + private final ByteArrayOutputStream errContent = new ByteArrayOutputStream(); + private final PrintStream originalOut = System.out; + private final PrintStream originalErr = System.err; + + private String outputBuilder(String[] output){ + String lineSeparator = System.getProperty("line.separator"); + StringBuilder result = new StringBuilder(); + for (String element:output) { + result.append(element).append(lineSeparator); + } + + return result.toString(); + } + + @Before + public void setUpStreams() { + System.setOut(new PrintStream(outContent)); + System.setErr(new PrintStream(errContent)); + } + + @After + public void restoreStreams() { + System.setOut(originalOut); + System.setErr(originalErr); + } + + @Test + public void testFindAllCliquesEmptyGraph(){ + int[][] edges = {}; + String[] cliquesList = {}; + + FindAllCliques.findAllCliques(edges, 0); + Assert.assertEquals(outputBuilder(cliquesList), outContent.toString()); + } + + @Test + public void testFindAllCliquesSingleNode(){ + int[][] edges = {}; + String[] cliquesList = {"1"}; + + FindAllCliques.findAllCliques(edges, 1); + Assert.assertEquals(outputBuilder(cliquesList), outContent.toString()); + } + + @Test + public void testFindAllCliquesMultipleNodes(){ + int[][] edges = { + { 1, 2 }, + { 2, 3 }, + { 3, 1 }, + { 4, 3 }, + { 4, 5 }, + { 5, 3 }, + }; + + String[] cliquesList = { + "1", + "2", + "3", + "4", + "5", + "1, 2", + "1, 3", + "2, 3", + "3, 4", + "3, 5", + "4, 5", + "1, 2, 3", + "3, 4, 5", + + }; + + FindAllCliques.findAllCliques(edges, 5); + + Assert.assertEquals(outputBuilder(cliquesList), outContent.toString()); + } + + @Test(expected = NullPointerException.class) + public void testFindAllCliquesNullInput(){ + FindAllCliques.findAllCliques(null, 0); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testFindAllCliquesTooManyNodes(){ + int[][] edges = { + { 1, 2 }, + { 2, 3 }, + { 3, 1 }, + { 4, 3 }, + { 4, 5 }, + { 5, 3 }, + }; + FindAllCliques.findAllCliques(edges, 10001); + } + + @Test + public void testFindAllCliquesNegativeNumberOfNodes(){ + int[][] edges = { + { 1, 2 }, + { 2, 3 }, + { 3, 1 }, + { 4, 3 }, + { 4, 5 }, + { 5, 3 }, + }; + FindAllCliques.findAllCliques(edges, -1); + + Assert.assertEquals("", outContent.toString()); + } +} From 04ffaf16fe4a0877da3ef626cb26cf8ec889615c Mon Sep 17 00:00:00 2001 From: Ioana Cotutiu Date: Wed, 3 Mar 2021 17:08:22 +0200 Subject: [PATCH 4/5] fix wrong test file location Moved test class to different folder. Co-Authored-By: Theodor Andrei Moise <38431187+iriediese@users.noreply.github.com> --- .../algorithms/{dp => graphtheory}/FindAllCliquesTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/test/java/com/williamfiset/algorithms/{dp => graphtheory}/FindAllCliquesTest.java (98%) diff --git a/src/test/java/com/williamfiset/algorithms/dp/FindAllCliquesTest.java b/src/test/java/com/williamfiset/algorithms/graphtheory/FindAllCliquesTest.java similarity index 98% rename from src/test/java/com/williamfiset/algorithms/dp/FindAllCliquesTest.java rename to src/test/java/com/williamfiset/algorithms/graphtheory/FindAllCliquesTest.java index 4a8290cad..c017ab546 100644 --- a/src/test/java/com/williamfiset/algorithms/dp/FindAllCliquesTest.java +++ b/src/test/java/com/williamfiset/algorithms/graphtheory/FindAllCliquesTest.java @@ -1,4 +1,4 @@ -package com.williamfiset.algorithms.dp; +package com.williamfiset.algorithms.graphtheory; import com.williamfiset.algorithms.graphtheory.FindAllCliques; import org.junit.After; From 4d1b940ffd63e31dad8079953d9bf734b26cb1fa Mon Sep 17 00:00:00 2001 From: Ioana Cotutiu Date: Wed, 3 Mar 2021 18:38:45 +0200 Subject: [PATCH 5/5] refactor FindAllCliques Removed white spaces and changed code formatting. Co-Authored-By: Theodor Andrei Moise <38431187+iriediese@users.noreply.github.com> --- .../graphtheory/FindAllCliques.java | 176 ++++++++------- .../graphtheory/FindAllCliquesTest.java | 209 ++++++++---------- 2 files changed, 184 insertions(+), 201 deletions(-) diff --git a/src/main/java/com/williamfiset/algorithms/graphtheory/FindAllCliques.java b/src/main/java/com/williamfiset/algorithms/graphtheory/FindAllCliques.java index dfa5a51ce..00c0a8e59 100644 --- a/src/main/java/com/williamfiset/algorithms/graphtheory/FindAllCliques.java +++ b/src/main/java/com/williamfiset/algorithms/graphtheory/FindAllCliques.java @@ -1,106 +1,104 @@ package com.williamfiset.algorithms.graphtheory; /** - * Finds all cliques (complete sub-graphs) in a given graph. - * The algorithm loops and finds all cliques for each given clique size up until the size of the graph itself. + * Finds all cliques (complete sub-graphs) in a given graph. The algorithm loops and finds all + * cliques for each given clique size up until the size of the graph itself. * - * Complexity: O(n^2) + *

Complexity: O(n^2) */ public class FindAllCliques { - static int size = 10000; - static int[] vertices = new int[size]; - static int n; - static int[][] graph = new int[size][size]; - static int[] degree = new int[size]; + static int size = 10000; + static int[] vertices = new int[size]; + static int n; + static int[][] graph = new int[size][size]; + static int[] degree = new int[size]; - /** - * Function that checks if the given set of vertices - * in store array is a clique or not - * @param count number of vertices in the vertices array - * @return true id the current subgraph is a clique - * false otherwise - */ - static boolean isClique(int count) { - for (int i = 1; i < count; i++) { - for (int j = i + 1; j < count; j++) { - // for missing edges - if (graph[vertices[i]][vertices[j]] == 0) { - return false; - } - } + /** + * Function that checks if the given set of vertices in store array is a clique or not + * + * @param count number of vertices in the vertices array + * @return true id the current subgraph is a clique false otherwise + */ + static boolean isClique(int count) { + for (int i = 1; i < count; i++) { + for (int j = i + 1; j < count; j++) { + // for missing edges + if (graph[vertices[i]][vertices[j]] == 0) { + return false; } - return true; + } } + return true; + } - /** - * Function that prints the clique - * @param n number of nodes in the clique - */ - static void print(int n) { - for (int i = 1; i < n; i++) { - if (i < n-1) { - System.out.print(vertices[i] + ", "); - } else { - System.out.println(vertices[i]); - } - } + /** + * Function that prints the clique + * + * @param n number of nodes in the clique + */ + static void print(int n) { + for (int i = 1; i < n; i++) { + if (i < n - 1) { + System.out.print(vertices[i] + ", "); + } else { + System.out.println(vertices[i]); + } } + } - /** - * Function that finds all the cliques of size s - * @param i initial index counter - * @param currentSize the size of the current sub-graph - * @param size the vertex count of the searched clique - */ - static void findCliques(int i, int currentSize, int size) { - // Find insertable vertices - for (int j = i + 1; j <= n - (size - currentSize); j++) { - if (degree[j] >= size - 1) { - vertices[currentSize] = j; - - // Max subgraph size achieved - if (isClique(currentSize + 1)) { - - // Max subgraph size not yet achieved - if (currentSize < size) { - findCliques(j, currentSize + 1, size); - } else { - print(currentSize + 1); - } - } - } + /** + * Function that finds all the cliques of size s + * + * @param i initial index counter + * @param currentSize the size of the current sub-graph + * @param size the vertex count of the searched clique + */ + static void findCliques(int i, int currentSize, int size) { + // Find insertable vertices + for (int j = i + 1; j <= n - (size - currentSize); j++) { + if (degree[j] >= size - 1) { + vertices[currentSize] = j; + // Max subgraph size achieved + if (isClique(currentSize + 1)) { + // Max subgraph size not yet achieved + if (currentSize < size) { + findCliques(j, currentSize + 1, size); + } else { + print(currentSize + 1); + } } + } } + } - /** - * Function that finds all cliques - * @param edges the list of edges formed with the nodes of the graph - * @param nodesNr the number of nodes of the graph - */ - public static void findAllCliques(int[][] edges, int nodesNr){ - n = nodesNr; - for (int[] edge : edges) { - graph[edge[0]][edge[1]] = 1; - graph[edge[1]][edge[0]] = 1; - degree[edge[0]]++; - degree[edge[1]]++; - } - - for (int i =1; i<= n; i++) { - findCliques(0, 1, i); - } + /** + * Function that finds all cliques + * + * @param edges the list of edges formed with the nodes of the graph + * @param nodesNr the number of nodes of the graph + */ + public static void findAllCliques(int[][] edges, int nodesNr) { + n = nodesNr; + for (int[] edge : edges) { + graph[edge[0]][edge[1]] = 1; + graph[edge[1]][edge[0]] = 1; + degree[edge[0]]++; + degree[edge[1]]++; } - - public static void main(String[] args){ - int[][] edges = { - { 1, 2 }, - { 2, 3 }, - { 3, 1 }, - { 4, 3 }, - { 4, 5 }, - { 5, 3 }, - }; - - findAllCliques(edges, 5); + for (int i = 1; i <= n; i++) { + findCliques(0, 1, i); } -} \ No newline at end of file + } + + public static void main(String[] args) { + int[][] edges = { + {1, 2}, + {2, 3}, + {3, 1}, + {4, 3}, + {4, 5}, + {5, 3}, + }; + findAllCliques(edges, 5); + } +} diff --git a/src/test/java/com/williamfiset/algorithms/graphtheory/FindAllCliquesTest.java b/src/test/java/com/williamfiset/algorithms/graphtheory/FindAllCliquesTest.java index c017ab546..70d6c679c 100644 --- a/src/test/java/com/williamfiset/algorithms/graphtheory/FindAllCliquesTest.java +++ b/src/test/java/com/williamfiset/algorithms/graphtheory/FindAllCliquesTest.java @@ -1,123 +1,108 @@ package com.williamfiset.algorithms.graphtheory; -import com.williamfiset.algorithms.graphtheory.FindAllCliques; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; - public class FindAllCliquesTest { - private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); - private final ByteArrayOutputStream errContent = new ByteArrayOutputStream(); - private final PrintStream originalOut = System.out; - private final PrintStream originalErr = System.err; - - private String outputBuilder(String[] output){ - String lineSeparator = System.getProperty("line.separator"); - StringBuilder result = new StringBuilder(); - for (String element:output) { - result.append(element).append(lineSeparator); - } - - return result.toString(); - } - - @Before - public void setUpStreams() { - System.setOut(new PrintStream(outContent)); - System.setErr(new PrintStream(errContent)); - } - - @After - public void restoreStreams() { - System.setOut(originalOut); - System.setErr(originalErr); - } - - @Test - public void testFindAllCliquesEmptyGraph(){ - int[][] edges = {}; - String[] cliquesList = {}; - - FindAllCliques.findAllCliques(edges, 0); - Assert.assertEquals(outputBuilder(cliquesList), outContent.toString()); - } - - @Test - public void testFindAllCliquesSingleNode(){ - int[][] edges = {}; - String[] cliquesList = {"1"}; - - FindAllCliques.findAllCliques(edges, 1); - Assert.assertEquals(outputBuilder(cliquesList), outContent.toString()); - } - - @Test - public void testFindAllCliquesMultipleNodes(){ - int[][] edges = { - { 1, 2 }, - { 2, 3 }, - { 3, 1 }, - { 4, 3 }, - { 4, 5 }, - { 5, 3 }, - }; - - String[] cliquesList = { - "1", - "2", - "3", - "4", - "5", - "1, 2", - "1, 3", - "2, 3", - "3, 4", - "3, 5", - "4, 5", - "1, 2, 3", - "3, 4, 5", - - }; - - FindAllCliques.findAllCliques(edges, 5); - - Assert.assertEquals(outputBuilder(cliquesList), outContent.toString()); + private final ByteArrayOutputStream outContent = new ByteArrayOutputStream(); + private final ByteArrayOutputStream errContent = new ByteArrayOutputStream(); + private final PrintStream originalOut = System.out; + private final PrintStream originalErr = System.err; + + private String outputBuilder(String[] output) { + String lineSeparator = System.getProperty("line.separator"); + StringBuilder result = new StringBuilder(); + for (String element : output) { + result.append(element).append(lineSeparator); } - @Test(expected = NullPointerException.class) - public void testFindAllCliquesNullInput(){ - FindAllCliques.findAllCliques(null, 0); - } - - @Test(expected = IndexOutOfBoundsException.class) - public void testFindAllCliquesTooManyNodes(){ - int[][] edges = { - { 1, 2 }, - { 2, 3 }, - { 3, 1 }, - { 4, 3 }, - { 4, 5 }, - { 5, 3 }, - }; - FindAllCliques.findAllCliques(edges, 10001); - } - - @Test - public void testFindAllCliquesNegativeNumberOfNodes(){ - int[][] edges = { - { 1, 2 }, - { 2, 3 }, - { 3, 1 }, - { 4, 3 }, - { 4, 5 }, - { 5, 3 }, - }; - FindAllCliques.findAllCliques(edges, -1); - - Assert.assertEquals("", outContent.toString()); - } + return result.toString(); + } + + @Before + public void setUpStreams() { + System.setOut(new PrintStream(outContent)); + System.setErr(new PrintStream(errContent)); + } + + @After + public void restoreStreams() { + System.setOut(originalOut); + System.setErr(originalErr); + } + + @Test + public void testFindAllCliquesEmptyGraph() { + int[][] edges = {}; + String[] cliquesList = {}; + + FindAllCliques.findAllCliques(edges, 0); + Assert.assertEquals(outputBuilder(cliquesList), outContent.toString()); + } + + @Test + public void testFindAllCliquesSingleNode() { + int[][] edges = {}; + String[] cliquesList = {"1"}; + + FindAllCliques.findAllCliques(edges, 1); + Assert.assertEquals(outputBuilder(cliquesList), outContent.toString()); + } + + @Test + public void testFindAllCliquesMultipleNodes() { + int[][] edges = { + {1, 2}, + {2, 3}, + {3, 1}, + {4, 3}, + {4, 5}, + {5, 3}, + }; + + String[] cliquesList = { + "1", "2", "3", "4", "5", "1, 2", "1, 3", "2, 3", "3, 4", "3, 5", "4, 5", "1, 2, 3", "3, 4, 5", + }; + + FindAllCliques.findAllCliques(edges, 5); + + Assert.assertEquals(outputBuilder(cliquesList), outContent.toString()); + } + + @Test(expected = NullPointerException.class) + public void testFindAllCliquesNullInput() { + FindAllCliques.findAllCliques(null, 0); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testFindAllCliquesTooManyNodes() { + int[][] edges = { + {1, 2}, + {2, 3}, + {3, 1}, + {4, 3}, + {4, 5}, + {5, 3}, + }; + FindAllCliques.findAllCliques(edges, 10001); + } + + @Test + public void testFindAllCliquesNegativeNumberOfNodes() { + int[][] edges = { + {1, 2}, + {2, 3}, + {3, 1}, + {4, 3}, + {4, 5}, + {5, 3}, + }; + FindAllCliques.findAllCliques(edges, -1); + + Assert.assertEquals("", outContent.toString()); + } }