cvut_mi_rub_nodes_distance_solver 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|