cvut_mi_rub_nodes_distance_solver 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/bin/cvut_mi_rub_nodes_distance_solver +5 -0
- data/cvut_mi_rub_nodes_distance_solver.gemspec +23 -0
- data/lib/cvut_mi_rub_nodes_distance_solver.rb +5 -0
- data/lib/cvut_mi_rub_nodes_distance_solver/cli.rb +59 -0
- data/lib/cvut_mi_rub_nodes_distance_solver/dijkstra.rb +68 -0
- data/lib/cvut_mi_rub_nodes_distance_solver/distance_matrix.rb +170 -0
- data/lib/cvut_mi_rub_nodes_distance_solver/floyd.rb +29 -0
- data/lib/cvut_mi_rub_nodes_distance_solver/input_parser.rb +116 -0
- data/lib/cvut_mi_rub_nodes_distance_solver/multiplication.rb +22 -0
- data/lib/cvut_mi_rub_nodes_distance_solver/version.rb +3 -0
- data/sample inputs/input1 +6 -0
- data/sample inputs/input2 +7 -0
- data/sample inputs/input3 +8 -0
- data/spec/.DS_Store +0 -0
- data/spec/dijkstra_spec.rb +63 -0
- data/spec/distance_matrix_spec.rb +85 -0
- data/spec/floyd_spec.rb +63 -0
- data/spec/input_parser_spec.rb +80 -0
- data/spec/multiplication_spec.rb +63 -0
- data/spec/spec_data.rb +59 -0
- data/spec/spec_helper.rb +6 -0
- metadata +107 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 37a4eebd2a9637c18e096d34657976b795b083a8
|
4
|
+
data.tar.gz: 573bbe11f8bc1ff62939945bae8f74892587031a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b00731d0e5174e71831f3b138131fc6c690f706eb208cc79af23cda84822009b6e0f1036cdbdb20cc5fc3edb857c9bdaa1c344af52268fe67002ca5f8477b66e
|
7
|
+
data.tar.gz: 24df050e9474d88435d2acfab335aab3547a370d005bcf2f140345bc1447450cf0de0bef024bb488bf715db946ef8610886b1dc181c38e530bb36916d86c9d1e
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Bc. Petr Janouch
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# CvutMiRubNodesDistanceSolver
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'cvut_mi_rub_nodes_distance_solver'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install cvut_mi_rub_nodes_distance_solver
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cvut_mi_rub_nodes_distance_solver/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cvut_mi_rub_nodes_distance_solver"
|
8
|
+
spec.version = CvutMiRubNodesDistanceSolver::VERSION
|
9
|
+
spec.authors = ["Bc. Petr Janouch"]
|
10
|
+
spec.email = ["janoupe8@fit.cvut.cz"]
|
11
|
+
spec.description = "A gem that is used to compute distances between all nodes in graph"
|
12
|
+
spec.summary = "A gem that is used to compute distances between all nodes in graph"
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'cvut_mi_rub_nodes_distance_solver/dijkstra'
|
3
|
+
require 'cvut_mi_rub_nodes_distance_solver/multiplication'
|
4
|
+
require 'cvut_mi_rub_nodes_distance_solver/floyd'
|
5
|
+
require 'cvut_mi_rub_nodes_distance_solver/distance_matrix'
|
6
|
+
require 'cvut_mi_rub_nodes_distance_solver/input_parser'
|
7
|
+
require 'thor'
|
8
|
+
|
9
|
+
module NodesDistance
|
10
|
+
|
11
|
+
class CLI < Thor
|
12
|
+
desc "floyd FILE", "finds shortest distance between all nodes in a graph using Floid's algorithm"
|
13
|
+
def floyd(file)
|
14
|
+
matrix = get_matrix(file)
|
15
|
+
solver = Floyd.new(matrix)
|
16
|
+
result = solver.solve
|
17
|
+
puts result.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "dijkstra FILE", "finds shortest distance between all nodes in a graph using Dijkstra's algorithm"
|
21
|
+
def dijkstra(file)
|
22
|
+
matrix = get_matrix(file)
|
23
|
+
solver = Dijkstra.new(matrix)
|
24
|
+
result = solver.solve
|
25
|
+
puts result.to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "multiplication FILE", "finds shortest distance between all nodes in a graph using min-plus product"
|
29
|
+
def multiplication(file)
|
30
|
+
matrix = get_solver(file)
|
31
|
+
solver = Multiplication.new(matrix)
|
32
|
+
result = solver.solve
|
33
|
+
puts result.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def get_matrix(file)
|
39
|
+
input = get_input_from_file(file)
|
40
|
+
input_parser = InputParser.new(input)
|
41
|
+
unless input_parser.is_valid?
|
42
|
+
puts 'incorrect input format'
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
matrix = input_parser.create_matrix
|
46
|
+
matrix
|
47
|
+
end
|
48
|
+
|
49
|
+
def get_input_from_file(file_path)
|
50
|
+
str = ''
|
51
|
+
File.open(file_path, "r") do |f|
|
52
|
+
f.readlines.each do |line|
|
53
|
+
str += line
|
54
|
+
end
|
55
|
+
end
|
56
|
+
str
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
#!/bin/ruby
|
2
|
+
require 'cvut_mi_rub_nodes_distance_solver/distance_matrix'
|
3
|
+
require 'cvut_mi_rub_nodes_distance_solver/input_parser'
|
4
|
+
|
5
|
+
module NodesDistance
|
6
|
+
|
7
|
+
# class containing algorithms for shortest distances computation
|
8
|
+
class NodesDistance::Dijkstra
|
9
|
+
|
10
|
+
def initialize(input_matrix)
|
11
|
+
@input_matrix = input_matrix
|
12
|
+
end
|
13
|
+
|
14
|
+
# returns a matrix of shortest distances between all nodes
|
15
|
+
# computed using dijkstra algorithm from each node
|
16
|
+
def solve
|
17
|
+
matrix = DistanceMatrix.new(@input_matrix.dimension)
|
18
|
+
@input_matrix.dimension.times do |i|
|
19
|
+
distance_vector = dijkstra_for_one_node(i)
|
20
|
+
matrix[i] = distance_vector
|
21
|
+
end
|
22
|
+
matrix
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# calculates shortest distances between the starting_node and all other nodes
|
28
|
+
# Arguments: starting_node: (int) index of the node shortes path is calculated from
|
29
|
+
def dijkstra_for_one_node(starting_node)
|
30
|
+
distance_vector = Array.new(@input_matrix.dimension) do
|
31
|
+
INFINITY
|
32
|
+
end
|
33
|
+
distance_vector[starting_node] = 0
|
34
|
+
|
35
|
+
node_queue = []
|
36
|
+
@input_matrix.dimension.times do |i|
|
37
|
+
node_queue << i
|
38
|
+
end
|
39
|
+
|
40
|
+
until node_queue.empty?
|
41
|
+
node = remove_node_with_smallest_distance_from_queue(distance_vector, node_queue)
|
42
|
+
break if distance_vector[node] == INFINITY
|
43
|
+
neighbours = @input_matrix[node]
|
44
|
+
neighbours.each_with_index do |neighbour_distance, neighbour|
|
45
|
+
if distance_vector[neighbour] > distance_vector[node] + neighbour_distance
|
46
|
+
distance_vector[neighbour] = distance_vector[node] + neighbour_distance
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
distance_vector
|
51
|
+
end
|
52
|
+
|
53
|
+
# remove node with smallest distence from queue
|
54
|
+
# Arguments: distance_vector (Array) vector of distances
|
55
|
+
def remove_node_with_smallest_distance_from_queue(distance_vector, node_queue)
|
56
|
+
min_value = INFINITY
|
57
|
+
min_index = 0
|
58
|
+
node_queue.each_with_index do |node, index|
|
59
|
+
value = distance_vector[node]
|
60
|
+
if value < min_value
|
61
|
+
min_value = value
|
62
|
+
min_index = index
|
63
|
+
end
|
64
|
+
end
|
65
|
+
node_queue.delete_at(min_index)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module NodesDistance
|
4
|
+
|
5
|
+
INFINITY = Float::INFINITY
|
6
|
+
INFINITY_SYMBOL = 'I'
|
7
|
+
|
8
|
+
# class that represents the matrix of distances between nodes
|
9
|
+
# it also defines multiplication of matrixes using min-sum product
|
10
|
+
class DistanceMatrix
|
11
|
+
|
12
|
+
attr_reader :dimension
|
13
|
+
|
14
|
+
# expect a dimesion of the matrix
|
15
|
+
# Arguments: dimension (String)
|
16
|
+
def initialize(dimension)
|
17
|
+
@dimension = dimension
|
18
|
+
@matrix = Array.new(dimension) do
|
19
|
+
Array.new(dimension) { INFINITY }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# prints matrix in human-readible form
|
24
|
+
def to_s
|
25
|
+
res = ''
|
26
|
+
@matrix.each_with_index do |row, row_index|
|
27
|
+
res += horizontal_gap unless row_index == 0
|
28
|
+
row.each_with_index do |item, item_index|
|
29
|
+
res += ' ' unless item_index == 0
|
30
|
+
res += print_item(item)
|
31
|
+
end
|
32
|
+
res += "\n"
|
33
|
+
end
|
34
|
+
res
|
35
|
+
end
|
36
|
+
|
37
|
+
# accesses matrix item or row based on # of arguments
|
38
|
+
def [](*args)
|
39
|
+
return @matrix[args[0]] if args.length == 1
|
40
|
+
@matrix[args[0]][args[1]]
|
41
|
+
end
|
42
|
+
|
43
|
+
# sets matrix item or row based on # of arguments
|
44
|
+
def []=(*args)
|
45
|
+
if args.length == 2
|
46
|
+
@matrix[args[0]] = args[1]
|
47
|
+
else
|
48
|
+
@matrix[args[0]][args[1]] = args[2]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# returns min-sum product of the two matrixes
|
53
|
+
# Arguments: other_matrix (DistanceMatrix)
|
54
|
+
def *(other_matrix)
|
55
|
+
result = DistanceMatrix.new(@dimension)
|
56
|
+
@dimension.times do |i|
|
57
|
+
@dimension.times do |j|
|
58
|
+
sum_vector = []
|
59
|
+
@dimension.times do |k|
|
60
|
+
sum = @matrix[i][k] + other_matrix[k, j]
|
61
|
+
sum_vector << sum
|
62
|
+
end
|
63
|
+
min = minimum(sum_vector)
|
64
|
+
result[i, j] = min
|
65
|
+
end
|
66
|
+
end
|
67
|
+
result
|
68
|
+
end
|
69
|
+
|
70
|
+
# returns power of the matrix
|
71
|
+
|
72
|
+
def ^(power)
|
73
|
+
result = copy
|
74
|
+
(power - 1).times do |i|
|
75
|
+
result *= result
|
76
|
+
end
|
77
|
+
result
|
78
|
+
end
|
79
|
+
|
80
|
+
# test if the two matrixes are equal
|
81
|
+
# Arguments: other (DistanceMatrix)
|
82
|
+
def ==(other)
|
83
|
+
return false unless @dimension == other.dimension
|
84
|
+
@dimension.times do |x|
|
85
|
+
@dimension.times do |y|
|
86
|
+
return false unless @matrix[x][y] == other[x, y]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
true
|
90
|
+
end
|
91
|
+
|
92
|
+
# returs a copy of the matrix
|
93
|
+
def copy
|
94
|
+
result = DistanceMatrix.new(@dimension)
|
95
|
+
iterate_all do |item, x, y|
|
96
|
+
result[x, y] = item
|
97
|
+
end
|
98
|
+
result
|
99
|
+
end
|
100
|
+
|
101
|
+
# iterates over all intems in matrix and also yields their coordinates
|
102
|
+
def iterate_all
|
103
|
+
@matrix.each_with_index do |row, x|
|
104
|
+
row.each_with_index do |item, y|
|
105
|
+
yield(item, x, y)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
# prints empty line
|
113
|
+
def horizontal_gap
|
114
|
+
line = ''
|
115
|
+
max_digits = max_digits()
|
116
|
+
line_width = @dimension * (max_digits + 1) - 1
|
117
|
+
line_width.times do
|
118
|
+
line += ' '
|
119
|
+
end
|
120
|
+
line += "\n"
|
121
|
+
line
|
122
|
+
end
|
123
|
+
|
124
|
+
# returns number of digits in provided number
|
125
|
+
# Arguments: number (int)
|
126
|
+
def digits(number)
|
127
|
+
number.to_s.size
|
128
|
+
end
|
129
|
+
|
130
|
+
def max_digits
|
131
|
+
max = 1
|
132
|
+
@matrix.each do |row|
|
133
|
+
row.each do |item|
|
134
|
+
next if item == INFINITY
|
135
|
+
item_digits = digits(item)
|
136
|
+
max = item_digits if item_digits > max
|
137
|
+
end
|
138
|
+
end
|
139
|
+
max
|
140
|
+
end
|
141
|
+
|
142
|
+
# prints an item of the matrix
|
143
|
+
# Arguments: item (int)
|
144
|
+
def print_item(item)
|
145
|
+
res = ''
|
146
|
+
max_digits = max_digits()
|
147
|
+
item_digits = digits(item)
|
148
|
+
digits_diferrence = max_digits - item_digits
|
149
|
+
digits_diferrence.times do
|
150
|
+
res += ' '
|
151
|
+
end
|
152
|
+
if item == INFINITY
|
153
|
+
res += INFINITY_SYMBOL
|
154
|
+
else
|
155
|
+
res += item.to_s
|
156
|
+
end
|
157
|
+
res
|
158
|
+
end
|
159
|
+
|
160
|
+
# returns the smallest item from provided vector
|
161
|
+
# Arguments: vector (Array<int>)
|
162
|
+
def minimum(vector)
|
163
|
+
min = INFINITY
|
164
|
+
vector.each do |item|
|
165
|
+
min = item if item < min
|
166
|
+
end
|
167
|
+
min
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/bin/ruby
|
2
|
+
require 'cvut_mi_rub_nodes_distance_solver/distance_matrix'
|
3
|
+
require 'cvut_mi_rub_nodes_distance_solver/input_parser'
|
4
|
+
|
5
|
+
module NodesDistance
|
6
|
+
|
7
|
+
# class containing algorithms for shortest distances computation
|
8
|
+
class NodesDistance::Floyd
|
9
|
+
|
10
|
+
def initialize(input_matrix)
|
11
|
+
@input_matrix = input_matrix
|
12
|
+
end
|
13
|
+
|
14
|
+
# returns a matrix of shortest distances between all nodes
|
15
|
+
# computed using Floyd algorithm
|
16
|
+
def solve
|
17
|
+
matrix = @input_matrix.copy
|
18
|
+
matrix.dimension.times do |k|
|
19
|
+
matrix.dimension.times do |i|
|
20
|
+
matrix.dimension.times do |j|
|
21
|
+
matrix[i, j] = [matrix[i, j], matrix[i, k] + matrix[k, j]].min
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
matrix
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
#!/bin/ruby
|
2
|
+
require 'cvut_mi_rub_nodes_distance_solver/distance_matrix'
|
3
|
+
|
4
|
+
module NodesDistance
|
5
|
+
|
6
|
+
class InputParser
|
7
|
+
|
8
|
+
def initialize(input)
|
9
|
+
@input = input
|
10
|
+
end
|
11
|
+
|
12
|
+
# returns true if input is valid - is square matrix,
|
13
|
+
# contains non-negative numbers or signs for infinit distance,
|
14
|
+
# the distance of each node to self is 0
|
15
|
+
def is_valid?
|
16
|
+
# is square matrix
|
17
|
+
return false unless dimensions_valid?
|
18
|
+
# non-negative numbers or signs for infinit distance
|
19
|
+
return false unless is_valid_symbol?
|
20
|
+
# the distance to self is
|
21
|
+
return false unless zeros_on_diagonal?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_matrix
|
26
|
+
dimension = number_of_rows
|
27
|
+
matrix = DistanceMatrix.new(dimension)
|
28
|
+
iterate_elements do |item, row_index, col_index|
|
29
|
+
if item == INFINITY_SYMBOL
|
30
|
+
item = INFINITY
|
31
|
+
else
|
32
|
+
item = item.to_i
|
33
|
+
end
|
34
|
+
matrix[row_index, col_index] = item
|
35
|
+
end
|
36
|
+
matrix
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# iterates over all ellements in the input
|
42
|
+
def iterate_elements
|
43
|
+
iterate_rows do |row, row_index|
|
44
|
+
iterate_row_items(row) do |item, item_index|
|
45
|
+
yield(item, row_index, item_index)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# iterates over all rows in the input
|
51
|
+
def iterate_rows
|
52
|
+
@input.split(/\n/).each_with_index do |row, row_index|
|
53
|
+
row = row.strip
|
54
|
+
yield(row, row_index)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# returns number of rows in the input
|
59
|
+
def number_of_rows
|
60
|
+
row_counter = 0
|
61
|
+
iterate_rows do
|
62
|
+
row_counter += 1
|
63
|
+
end
|
64
|
+
row_counter
|
65
|
+
end
|
66
|
+
|
67
|
+
# non-negative numbers or signs for infinit distance
|
68
|
+
def is_valid_symbol?
|
69
|
+
iterate_elements do |item|
|
70
|
+
next if item == INFINITY_SYMBOL
|
71
|
+
begin
|
72
|
+
item = Float(item)
|
73
|
+
rescue ArgumentError, TypeError
|
74
|
+
return false
|
75
|
+
end
|
76
|
+
return false if item < 0
|
77
|
+
end
|
78
|
+
true
|
79
|
+
end
|
80
|
+
|
81
|
+
# is square matrix
|
82
|
+
def dimensions_valid?
|
83
|
+
row_number = number_of_rows
|
84
|
+
iterate_rows do |row|
|
85
|
+
return false unless row_size(row) == row_number
|
86
|
+
end
|
87
|
+
true
|
88
|
+
end
|
89
|
+
|
90
|
+
# returns number of items in the given row
|
91
|
+
# Arguments: row (Array)
|
92
|
+
def row_size(row)
|
93
|
+
counter = 0
|
94
|
+
iterate_row_items(row) do |item, index|
|
95
|
+
counter += 1
|
96
|
+
end
|
97
|
+
counter
|
98
|
+
end
|
99
|
+
|
100
|
+
# itertes over all row items
|
101
|
+
# Arguments: row (Array)
|
102
|
+
def iterate_row_items(row)
|
103
|
+
row.split(/ /).each_with_index do |item, index|
|
104
|
+
yield(item, index)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# the distance to self is
|
109
|
+
def zeros_on_diagonal?
|
110
|
+
iterate_elements do |item, row_index, col_index|
|
111
|
+
return false if row_index == col_index && item != '0'
|
112
|
+
end
|
113
|
+
true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/bin/ruby
|
2
|
+
require 'cvut_mi_rub_nodes_distance_solver/distance_matrix'
|
3
|
+
require 'cvut_mi_rub_nodes_distance_solver/input_parser'
|
4
|
+
|
5
|
+
module NodesDistance
|
6
|
+
|
7
|
+
# class containing algorithms for shortest distances computation
|
8
|
+
class NodesDistance::Multiplication
|
9
|
+
|
10
|
+
def initialize(input_matrix)
|
11
|
+
@input_matrix = input_matrix
|
12
|
+
end
|
13
|
+
|
14
|
+
# returns a matrix of shortest distances between all nodes
|
15
|
+
# computed using min-plus matrix product
|
16
|
+
def solve
|
17
|
+
matrix = @input_matrix.copy
|
18
|
+
matrix = matrix ^ matrix.dimension
|
19
|
+
matrix
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/spec/.DS_Store
ADDED
Binary file
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH << './'
|
4
|
+
require 'rspec'
|
5
|
+
require 'spec_helper'
|
6
|
+
require 'spec_data'
|
7
|
+
require 'cvut_mi_rub_nodes_distance_solver/input_parser'
|
8
|
+
require 'cvut_mi_rub_nodes_distance_solver/dijkstra'
|
9
|
+
|
10
|
+
describe NodesDistance::Dijkstra do
|
11
|
+
|
12
|
+
subject do
|
13
|
+
input_parser = NodesDistance::InputParser.new(input)
|
14
|
+
matrix = input_parser.create_matrix
|
15
|
+
shortest = NodesDistance::Dijkstra.new(matrix)
|
16
|
+
shortest
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'shortest paths 1' do
|
20
|
+
input, result = SpecData.first
|
21
|
+
let(:input) do
|
22
|
+
input
|
23
|
+
end
|
24
|
+
|
25
|
+
rip = NodesDistance::InputParser.new(result)
|
26
|
+
result_matrix = rip.create_matrix
|
27
|
+
|
28
|
+
it 'should find the shortest paths using dijkstra algorithm' do
|
29
|
+
expect(subject.solve).to eq result_matrix
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'shortest paths 2' do
|
35
|
+
input, result = SpecData.second
|
36
|
+
let(:input) do
|
37
|
+
input
|
38
|
+
end
|
39
|
+
|
40
|
+
rip = NodesDistance::InputParser.new(result)
|
41
|
+
result_matrix = rip.create_matrix
|
42
|
+
|
43
|
+
it 'should find the shortest paths using dijkstra algorithm' do
|
44
|
+
expect(subject.solve).to eq result_matrix
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'shortest paths 3' do
|
50
|
+
input, result = SpecData.third
|
51
|
+
let(:input) do
|
52
|
+
input
|
53
|
+
end
|
54
|
+
|
55
|
+
rip = NodesDistance::InputParser.new(result)
|
56
|
+
result_matrix = rip.create_matrix
|
57
|
+
|
58
|
+
it 'should find the shortest paths using dijkstra algorithm' do
|
59
|
+
expect(subject.solve).to eq result_matrix
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH << './'
|
4
|
+
require 'rspec'
|
5
|
+
require 'spec_helper'
|
6
|
+
require 'cvut_mi_rub_nodes_distance_solver/input_parser'
|
7
|
+
|
8
|
+
describe NodesDistance::DistanceMatrix do
|
9
|
+
|
10
|
+
subject do
|
11
|
+
input_parser = NodesDistance::InputParser.new(input)
|
12
|
+
input_parser.create_matrix
|
13
|
+
end
|
14
|
+
|
15
|
+
describe 'output format' do
|
16
|
+
let(:input) do
|
17
|
+
'0 5 22
|
18
|
+
0 0 42
|
19
|
+
99 0 33'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should print formated matrix' do
|
23
|
+
expected_result = " 0 5 22\n"\
|
24
|
+
" \n"\
|
25
|
+
" 0 0 42\n"\
|
26
|
+
" \n"\
|
27
|
+
"99 0 33\n"
|
28
|
+
expect(subject.to_s).to eq expected_result
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'accessing values' do
|
33
|
+
let(:input) do
|
34
|
+
'0 5 22
|
35
|
+
0 0 42
|
36
|
+
99 0 33'
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should get values' do
|
40
|
+
expect(subject[0, 0]).to eq 0
|
41
|
+
expect(subject[0, 2]).to eq 22
|
42
|
+
expect(subject[2, 2]).to eq 33
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'multiplication' do
|
47
|
+
let(:input) do
|
48
|
+
'1 -3 7
|
49
|
+
I 5 I
|
50
|
+
8 2 -5'
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should do modified multiplication' do
|
54
|
+
b_input = '8 I -4
|
55
|
+
-3 0 -7
|
56
|
+
5 -2 1'
|
57
|
+
b_ip = NodesDistance::InputParser.new(b_input)
|
58
|
+
b = b_ip.create_matrix
|
59
|
+
c_input = '-6 -3 -10
|
60
|
+
2 5 -2
|
61
|
+
-1 -7 -5'
|
62
|
+
c_ip = NodesDistance::InputParser.new(c_input)
|
63
|
+
c = c_ip.create_matrix
|
64
|
+
expect(subject * b).to eq c
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'square' do
|
69
|
+
let(:input) do
|
70
|
+
'1 -3 7
|
71
|
+
I 5 I
|
72
|
+
8 2 -5'
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should square matrix' do
|
76
|
+
res_input = '2 -2 2
|
77
|
+
I 10 I
|
78
|
+
3 -3 -10'
|
79
|
+
res_ip = NodesDistance::InputParser.new(res_input)
|
80
|
+
res = res_ip.create_matrix
|
81
|
+
expect(subject ^ 2).to eq res
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
data/spec/floyd_spec.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH << './'
|
4
|
+
require 'rspec'
|
5
|
+
require 'spec_helper'
|
6
|
+
require 'spec_data'
|
7
|
+
require 'cvut_mi_rub_nodes_distance_solver/input_parser'
|
8
|
+
require 'cvut_mi_rub_nodes_distance_solver/floyd'
|
9
|
+
|
10
|
+
describe NodesDistance::Floyd do
|
11
|
+
|
12
|
+
subject do
|
13
|
+
input_parser = NodesDistance::InputParser.new(input)
|
14
|
+
matrix = input_parser.create_matrix
|
15
|
+
shortest = NodesDistance::Floyd.new(matrix)
|
16
|
+
shortest
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'shortest paths 1' do
|
20
|
+
input, result = SpecData.first
|
21
|
+
let(:input) do
|
22
|
+
input
|
23
|
+
end
|
24
|
+
|
25
|
+
rip = NodesDistance::InputParser.new(result)
|
26
|
+
result_matrix = rip.create_matrix
|
27
|
+
|
28
|
+
it 'should find the shortest paths using floyd algorithm' do
|
29
|
+
expect(subject.solve).to eq result_matrix
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'shortest paths 2' do
|
35
|
+
input, result = SpecData.second
|
36
|
+
let(:input) do
|
37
|
+
input
|
38
|
+
end
|
39
|
+
|
40
|
+
rip = NodesDistance::InputParser.new(result)
|
41
|
+
result_matrix = rip.create_matrix
|
42
|
+
|
43
|
+
it 'should find the shortest paths using floyd algorithm' do
|
44
|
+
expect(subject.solve).to eq result_matrix
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'shortest paths 3' do
|
50
|
+
input, result = SpecData.third
|
51
|
+
let(:input) do
|
52
|
+
input
|
53
|
+
end
|
54
|
+
|
55
|
+
rip = NodesDistance::InputParser.new(result)
|
56
|
+
result_matrix = rip.create_matrix
|
57
|
+
|
58
|
+
it 'should find the shortest paths using floyd algorithm' do
|
59
|
+
expect(subject.solve).to eq result_matrix
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH << './'
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'cvut_mi_rub_nodes_distance_solver/input_parser'
|
5
|
+
|
6
|
+
describe NodesDistance::InputParser do
|
7
|
+
subject do
|
8
|
+
NodesDistance::InputParser.new(input)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'incorrect dimensions' do
|
12
|
+
let(:input) do
|
13
|
+
'0 0 0
|
14
|
+
0 0'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should not pass rows of different sizes' do
|
18
|
+
expect(subject.is_valid?).to eq false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'incorrect dimensions' do
|
23
|
+
let(:input) do
|
24
|
+
'0 0 0
|
25
|
+
0 0 0'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should not pass matrix that has width larger than height' do
|
29
|
+
expect(subject.is_valid?).to eq false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'incorrect dimensions' do
|
34
|
+
let(:input) do
|
35
|
+
'0 0
|
36
|
+
0 0
|
37
|
+
0 0'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should not pass matrix that has haight larger than width' do
|
41
|
+
expect(subject.is_valid?).to eq false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'input values' do
|
46
|
+
let(:input) do
|
47
|
+
'0 0 0
|
48
|
+
0 2 0
|
49
|
+
0 0 3'
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should not pass if a node has the distance to itself other than 0' do
|
53
|
+
expect(subject.is_valid?).to eq false
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'input values' do
|
58
|
+
let(:input) do
|
59
|
+
'0 -5 f
|
60
|
+
? 0 8
|
61
|
+
0 . 0'
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should not pass if there are not possitive numbers, infinity symbols or zeros on the input' do
|
65
|
+
expect(subject.is_valid?).to eq false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'input values' do
|
70
|
+
let(:input) do
|
71
|
+
'0 5 2.2
|
72
|
+
4 0 1
|
73
|
+
3 7 0'
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should recognize correct input' do
|
77
|
+
expect(subject.is_valid?).to eq true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH << './'
|
4
|
+
require 'rspec'
|
5
|
+
require 'spec_helper'
|
6
|
+
require 'spec_data'
|
7
|
+
require 'cvut_mi_rub_nodes_distance_solver/input_parser'
|
8
|
+
require 'cvut_mi_rub_nodes_distance_solver/multiplication'
|
9
|
+
|
10
|
+
describe NodesDistance::Multiplication do
|
11
|
+
|
12
|
+
subject do
|
13
|
+
input_parser = NodesDistance::InputParser.new(input)
|
14
|
+
matrix = input_parser.create_matrix
|
15
|
+
shortest = NodesDistance::Multiplication.new(matrix)
|
16
|
+
shortest
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'shortest paths 1' do
|
20
|
+
input, result = SpecData.first
|
21
|
+
let(:input) do
|
22
|
+
input
|
23
|
+
end
|
24
|
+
|
25
|
+
rip = NodesDistance::InputParser.new(result)
|
26
|
+
result_matrix = rip.create_matrix
|
27
|
+
|
28
|
+
it 'should find the shortest paths using multiplication algorithm' do
|
29
|
+
expect(subject.solve).to eq result_matrix
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'shortest paths 2' do
|
35
|
+
input, result = SpecData.second
|
36
|
+
let(:input) do
|
37
|
+
input
|
38
|
+
end
|
39
|
+
|
40
|
+
rip = NodesDistance::InputParser.new(result)
|
41
|
+
result_matrix = rip.create_matrix
|
42
|
+
|
43
|
+
it 'should find the shortest paths using multipliation algorithm' do
|
44
|
+
expect(subject.solve).to eq result_matrix
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'shortest paths 3' do
|
50
|
+
input, result = SpecData.third
|
51
|
+
let(:input) do
|
52
|
+
input
|
53
|
+
end
|
54
|
+
|
55
|
+
rip = NodesDistance::InputParser.new(result)
|
56
|
+
result_matrix = rip.create_matrix
|
57
|
+
|
58
|
+
it 'should find the shortest paths using multiplication algorithm' do
|
59
|
+
expect(subject.solve).to eq result_matrix
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
data/spec/spec_data.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
|
2
|
+
# contains data for test cases
|
3
|
+
class SpecData
|
4
|
+
|
5
|
+
def self.first
|
6
|
+
input = '0 I I 2 I 7
|
7
|
+
I 0 2 I I I
|
8
|
+
I I 0 I 3 I
|
9
|
+
I 7 I 0 1 I
|
10
|
+
I I I I 0 3
|
11
|
+
I I 1 I I 0'
|
12
|
+
result = '0 9 7 2 3 6
|
13
|
+
I 0 2 I 5 8
|
14
|
+
I I 0 I 3 6
|
15
|
+
I 7 5 0 1 4
|
16
|
+
I I 4 I 0 3
|
17
|
+
I I 1 I 4 0'
|
18
|
+
return input, result
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.second
|
22
|
+
input = '0 10 I 35 I I I
|
23
|
+
I 0 15 I 40 I I
|
24
|
+
I I 0 5 20 I I
|
25
|
+
10 I I 0 I I I
|
26
|
+
I I I I 0 20 10
|
27
|
+
I I I I I 0 5
|
28
|
+
I I I 25 I I 0'
|
29
|
+
result = '0 10 25 30 45 65 55
|
30
|
+
30 0 15 20 35 55 45
|
31
|
+
15 25 0 5 20 40 30
|
32
|
+
10 20 35 0 55 75 65
|
33
|
+
45 55 70 35 0 20 10
|
34
|
+
40 50 65 30 85 0 5
|
35
|
+
35 45 60 25 80 100 0'
|
36
|
+
return input, result
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.third
|
40
|
+
input = '0 5 8 I I 6 I 3
|
41
|
+
11 0 5 I I I 9 4
|
42
|
+
7 I 0 I I 3 I I
|
43
|
+
I I 4 0 8 3 I I
|
44
|
+
I 5 3 I 0 8 I I
|
45
|
+
2 1 I I I 0 4 6
|
46
|
+
5 4 I I 3 2 0 I
|
47
|
+
I I 12 7 8 I 5 0'
|
48
|
+
result = '0 5 8 10 11 6 8 3
|
49
|
+
10 0 5 11 12 8 9 4
|
50
|
+
5 4 0 15 10 3 7 8
|
51
|
+
5 4 4 0 8 3 7 8
|
52
|
+
8 5 3 16 0 6 10 9
|
53
|
+
2 1 6 12 7 0 4 5
|
54
|
+
4 3 6 14 3 2 0 7
|
55
|
+
9 8 11 7 8 7 5 0'
|
56
|
+
return input, result
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cvut_mi_rub_nodes_distance_solver
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bc. Petr Janouch
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: A gem that is used to compute distances between all nodes in graph
|
42
|
+
email:
|
43
|
+
- janoupe8@fit.cvut.cz
|
44
|
+
executables:
|
45
|
+
- cvut_mi_rub_nodes_distance_solver
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- .gitignore
|
50
|
+
- Gemfile
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- bin/cvut_mi_rub_nodes_distance_solver
|
55
|
+
- cvut_mi_rub_nodes_distance_solver.gemspec
|
56
|
+
- lib/cvut_mi_rub_nodes_distance_solver.rb
|
57
|
+
- lib/cvut_mi_rub_nodes_distance_solver/cli.rb
|
58
|
+
- lib/cvut_mi_rub_nodes_distance_solver/dijkstra.rb
|
59
|
+
- lib/cvut_mi_rub_nodes_distance_solver/distance_matrix.rb
|
60
|
+
- lib/cvut_mi_rub_nodes_distance_solver/floyd.rb
|
61
|
+
- lib/cvut_mi_rub_nodes_distance_solver/input_parser.rb
|
62
|
+
- lib/cvut_mi_rub_nodes_distance_solver/multiplication.rb
|
63
|
+
- lib/cvut_mi_rub_nodes_distance_solver/version.rb
|
64
|
+
- sample inputs/input1
|
65
|
+
- sample inputs/input2
|
66
|
+
- sample inputs/input3
|
67
|
+
- spec/.DS_Store
|
68
|
+
- spec/dijkstra_spec.rb
|
69
|
+
- spec/distance_matrix_spec.rb
|
70
|
+
- spec/floyd_spec.rb
|
71
|
+
- spec/input_parser_spec.rb
|
72
|
+
- spec/multiplication_spec.rb
|
73
|
+
- spec/spec_data.rb
|
74
|
+
- spec/spec_helper.rb
|
75
|
+
homepage: ''
|
76
|
+
licenses:
|
77
|
+
- MIT
|
78
|
+
metadata: {}
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.1.5
|
96
|
+
signing_key:
|
97
|
+
specification_version: 4
|
98
|
+
summary: A gem that is used to compute distances between all nodes in graph
|
99
|
+
test_files:
|
100
|
+
- spec/.DS_Store
|
101
|
+
- spec/dijkstra_spec.rb
|
102
|
+
- spec/distance_matrix_spec.rb
|
103
|
+
- spec/floyd_spec.rb
|
104
|
+
- spec/input_parser_spec.rb
|
105
|
+
- spec/multiplication_spec.rb
|
106
|
+
- spec/spec_data.rb
|
107
|
+
- spec/spec_helper.rb
|