From f989f96ed52a536817da8d73ffba62ca8dca8d6e Mon Sep 17 00:00:00 2001 From: elijah-gichev Date: Wed, 17 Nov 2021 19:50:54 +0300 Subject: [PATCH 1/3] added DFS realization and tests for it --- lib/visual_graphs/algorithms.rb | 46 +++++++++++++++++ test/algorithms_test.rb | 86 ++++++++++++++++++++++++++++++++ test/resources/test_min_heap.txt | 7 +++ 3 files changed, 139 insertions(+) create mode 100644 lib/visual_graphs/algorithms.rb create mode 100644 test/algorithms_test.rb create mode 100644 test/resources/test_min_heap.txt diff --git a/lib/visual_graphs/algorithms.rb b/lib/visual_graphs/algorithms.rb new file mode 100644 index 0000000..99b834d --- /dev/null +++ b/lib/visual_graphs/algorithms.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module VisualGraphs + class Algorithms + + # Depth-First Search, (for adjacency matrix based graph) + def DFS(graph_matrix, vertexAction) + + if !graph_matrix.is_a?(AdjMatrixGraph) + msg = 'argument must be of AdjMatrixGraph type' + raise AdjacencyMatrixError, msg + end + + matrix = graph_matrix.adjacency_matrix + initial_index = 0 + + visited = [] + node_stack = [initial_index] + loop do + curr_node = node_stack.shift + + visited.append(curr_node) + return false if curr_node == nil + return true if curr_node == matrix.length + + vertexAction.call(curr_node) + + children = (0..matrix.length-1).to_a.select do |i| + + # do not process loops + if curr_node == i + next + end + + if visited.find{|v| v == i} != nil + next + end + + matrix[curr_node][i] != 0 + end + node_stack = node_stack + children + end + end + end +end + diff --git a/test/algorithms_test.rb b/test/algorithms_test.rb new file mode 100644 index 0000000..fcdeeb4 --- /dev/null +++ b/test/algorithms_test.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require "./test/test_helper" +require './lib/visual_graphs/algorithms' +require './lib/visual_graphs/adjacency_matrix_graph' + +class AlgorithmTest < Minitest::Test + include VisualGraphs + + def test_exists_DFS_method + assert Algorithms.methods.size > 0 + end + + def test_DFS_does_not_accept_invalid_data + alg = Algorithms.new + + exception = assert_raises AdjacencyMatrixError do + my_print = lambda { |n| print(n ) } + alg.DFS(5, my_print) + end + assert_equal 'argument must be of AdjMatrixGraph type', exception.message + + exception = assert_raises AdjacencyMatrixError do + my_print = lambda { |n| print(n ) } + alg.DFS([1, 2, 3], my_print) + end + assert_equal 'argument must be of AdjMatrixGraph type', exception.message + + exception = assert_raises AdjacencyMatrixError do + my_print = lambda { |n| print(n ) } + alg.DFS("it's joke", my_print) + end + assert_equal 'argument must be of AdjMatrixGraph type', exception.message + end + + def test_DFS_correct_work_size2 + alg = Algorithms.new + + matrix = AdjMatrixGraph.new + matrixSrc = [[2, 3], [0, 1]] + matrix.load_from_array(matrixSrc) + + traversed_vertices = [] + traverse = lambda { |n| traversed_vertices.append(n) } + alg.DFS(matrix, traverse) + + assert_equal traversed_vertices, [0, 1] + end + + + def test_DFS_correct_work_size5 + alg = Algorithms.new + + matrix = AdjMatrixGraph.new + matrixSrc = [[0, 1, 1, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 1, 1], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]] + matrix.load_from_array(matrixSrc) + + traversed_vertices = [] + traverse = lambda { |n| traversed_vertices.append(n) } + alg.DFS(matrix, traverse) + + assert_equal traversed_vertices, [0, 1, 2, 3, 4] + end + + def test_DFS_correct_work_size3 + alg = Algorithms.new + + matrix = AdjMatrixGraph.new + matrixSrc = [[0, 0, 2], + [2, 0, 0], + [0, 2, 0]] + matrix.load_from_array(matrixSrc) + + traversed_vertices = [] + traverse = lambda { |n| traversed_vertices.append(n) } + alg.DFS(matrix, traverse) + + print(traversed_vertices) + + assert_equal traversed_vertices, [0, 2, 1] + end +end \ No newline at end of file diff --git a/test/resources/test_min_heap.txt b/test/resources/test_min_heap.txt new file mode 100644 index 0000000..715f3ce --- /dev/null +++ b/test/resources/test_min_heap.txt @@ -0,0 +1,7 @@ +printing min heap: +nil +Vertex +Vertex +Vertex +Vertex +Vertex From 49d0ca4fe229d03b0c61f818942a066af615a7ed Mon Sep 17 00:00:00 2001 From: elijah-gichev Date: Wed, 17 Nov 2021 20:11:22 +0300 Subject: [PATCH 2/3] added description --- README.md | 24 ++++++++++++++++++++++++ lib/visual_graphs/algorithms.rb | 3 ++- test/algorithms_test.rb | 23 +++++++++++------------ 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 4a90872..b8f1fa9 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,30 @@ graph.add_edge(3, 5, 4) # edge from vertex 3 to vertex 5 with weight 4 puts graph ``` +## Algorithms usage + +```ruby + +# initializes Algorithms object +alg = Algorithms.new + +# matrix example +matrix = AdjMatrixGraph.new +matrixSrc = [[0, 0, 2], + [2, 0, 0], + [0, 2, 0]] +matrix.load_from_array(matrixSrc) + +# lambda which will be used for each vertex +my_print = lambda { |n| print(n) } + +# matrix_DFS call +alg.matrix_DFS(matrix, my_print) +# 0 2 1 + +``` + + ## Data formats ``` diff --git a/lib/visual_graphs/algorithms.rb b/lib/visual_graphs/algorithms.rb index 99b834d..3250e2a 100644 --- a/lib/visual_graphs/algorithms.rb +++ b/lib/visual_graphs/algorithms.rb @@ -1,10 +1,11 @@ # frozen_string_literal: true module VisualGraphs + # class with different algorithms for graphs class Algorithms # Depth-First Search, (for adjacency matrix based graph) - def DFS(graph_matrix, vertexAction) + def matrix_DFS(graph_matrix, vertexAction) if !graph_matrix.is_a?(AdjMatrixGraph) msg = 'argument must be of AdjMatrixGraph type' diff --git a/test/algorithms_test.rb b/test/algorithms_test.rb index fcdeeb4..043b39e 100644 --- a/test/algorithms_test.rb +++ b/test/algorithms_test.rb @@ -7,33 +7,33 @@ class AlgorithmTest < Minitest::Test include VisualGraphs - def test_exists_DFS_method + def test_exists_matrix_DFS_method assert Algorithms.methods.size > 0 end - def test_DFS_does_not_accept_invalid_data + def test_matrix_DFS_does_not_accept_invalid_data alg = Algorithms.new exception = assert_raises AdjacencyMatrixError do my_print = lambda { |n| print(n ) } - alg.DFS(5, my_print) + alg.matrix_DFS(5, my_print) end assert_equal 'argument must be of AdjMatrixGraph type', exception.message exception = assert_raises AdjacencyMatrixError do my_print = lambda { |n| print(n ) } - alg.DFS([1, 2, 3], my_print) + alg.matrix_DFS([1, 2, 3], my_print) end assert_equal 'argument must be of AdjMatrixGraph type', exception.message exception = assert_raises AdjacencyMatrixError do my_print = lambda { |n| print(n ) } - alg.DFS("it's joke", my_print) + alg.matrix_DFS("it's joke", my_print) end assert_equal 'argument must be of AdjMatrixGraph type', exception.message end - def test_DFS_correct_work_size2 + def test_matrix_DFS_correct_work_size2 alg = Algorithms.new matrix = AdjMatrixGraph.new @@ -42,13 +42,13 @@ def test_DFS_correct_work_size2 traversed_vertices = [] traverse = lambda { |n| traversed_vertices.append(n) } - alg.DFS(matrix, traverse) + alg.matrix_DFS(matrix, traverse) assert_equal traversed_vertices, [0, 1] end - def test_DFS_correct_work_size5 + def test_matrix_DFS_correct_work_size5 alg = Algorithms.new matrix = AdjMatrixGraph.new @@ -61,12 +61,12 @@ def test_DFS_correct_work_size5 traversed_vertices = [] traverse = lambda { |n| traversed_vertices.append(n) } - alg.DFS(matrix, traverse) + alg.matrix_DFS(matrix, traverse) assert_equal traversed_vertices, [0, 1, 2, 3, 4] end - def test_DFS_correct_work_size3 + def test_matrix_DFS_correct_work_size3 alg = Algorithms.new matrix = AdjMatrixGraph.new @@ -77,9 +77,8 @@ def test_DFS_correct_work_size3 traversed_vertices = [] traverse = lambda { |n| traversed_vertices.append(n) } - alg.DFS(matrix, traverse) - print(traversed_vertices) + alg.matrix_DFS(matrix, traverse) assert_equal traversed_vertices, [0, 2, 1] end From ebb1d64a7e9458332f459b95377bdfb1263c2687 Mon Sep 17 00:00:00 2001 From: elijah-gichev Date: Wed, 17 Nov 2021 22:23:42 +0300 Subject: [PATCH 3/3] some refactoring --- lib/visual_graphs/algorithms.rb | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/lib/visual_graphs/algorithms.rb b/lib/visual_graphs/algorithms.rb index 3250e2a..de93fe8 100644 --- a/lib/visual_graphs/algorithms.rb +++ b/lib/visual_graphs/algorithms.rb @@ -7,10 +7,8 @@ class Algorithms # Depth-First Search, (for adjacency matrix based graph) def matrix_DFS(graph_matrix, vertexAction) - if !graph_matrix.is_a?(AdjMatrixGraph) - msg = 'argument must be of AdjMatrixGraph type' - raise AdjacencyMatrixError, msg - end + msg = 'argument must be of AdjMatrixGraph type' + raise AdjacencyMatrixError, msg unless graph_matrix.is_a?(AdjMatrixGraph) matrix = graph_matrix.adjacency_matrix initial_index = 0 @@ -27,18 +25,13 @@ def matrix_DFS(graph_matrix, vertexAction) vertexAction.call(curr_node) children = (0..matrix.length-1).to_a.select do |i| - # do not process loops - if curr_node == i - next - end - - if visited.find{|v| v == i} != nil - next - end + next if curr_node == i + next if visited.find{|v| v == i} != nil matrix[curr_node][i] != 0 end + node_stack = node_stack + children end end