-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmetro.thor
More file actions
167 lines (132 loc) · 4.73 KB
/
metro.thor
File metadata and controls
167 lines (132 loc) · 4.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
require 'hashie'
require 'terminal-table'
require 'benchmark'
require 'parallel'
require 'thor'
require_relative './station_loader.rb'
require_relative './planner.rb'
# station_hash.each do |k, station|
# puts "#{k} #{station.name} -> #{station.connecting_station_id}"
# end
stations = StationLoader.new(file: "stations.csv").load.station_hash
planner = Planner.set(stations: stations)
# loop do
# puts 'Elige actividad a realizar (ruta/matriz)'
# option = ARGF.readline.strip
# next calculate_route(station_names:) if option == 'ruta'
# next calculate_matrices if option == 'matriz'
# puts 'Continuar (si/no)'
# break if ARGF.readline.strip == 'no'
# end
# ARGF.readline
# ARGF.readline
# res.each do |matrix|
# matrix.each do |route, result|
# puts "#{route}: #{result.stations.reverse.map(&:id).join(',')}"
# end
# ARGF.readline
# end
class Metro < Thor
package_name 'metro'
desc 'benchmark', 'benchmarks all matrix calculations'
def benchmark
res = []
Benchmark.bm do |benchmark|
benchmark.report('processes') { res << calculate_matrix_parallel_processes }
benchmark.report('threads') { res << calculate_matrix_parallel_threads }
benchmark.report('inline') { res << calculate_matrix }
end
res
end
desc 'matrix METHOD', 'calculates a distance matrix the specified method'
option :chance, type: :string, desc: 'chance from 0 to 1 to select a random station to consider'
option :output, type: :string, desc: 'file name of the file to export'
option :format, type: :string, default: :tabs, desc: 'format in which the file will be saved'
def matrix(method='processes')
puts options.inspect
chance = options[:chance].to_f
mtx = case method
when 'processes'
calculate_matrix_parallel_processes(chance)
when 'threads'
calculate_matrix_parallel_threads(chance)
when 'inline'
calculate_matrix(chance)
end
mtx.each do |route, result|
puts "#{route}: #{result.cost}\t #{result.stations.map(&:id).join(',')}"
end
if options[:output]
File.open(options[:output], 'w') do |file|
mtx.each do |route, result|
case options[:format]
when :tabs
file.print route.split('->').join('|')
file.print "|#{result.cost}|"
file.puts "#{result.stations.map(&:id).join(',')}"
when :json
# file.puts { route:, cost: result.cost, stations: result.stations.map(&:id).join(',') }.to_json
end
end
end
end
end
desc 'stations', 'list all known stations'
def stations
station_names = StationLoader.new(file: "./stations.csv").load.station_names
station_names.each do |code, name|
puts "#{code}\t#{name}"
end
end
desc 'calculate ORIGIN DESTINATION', 'calculates best route between stations'
def calculate_route(origin, destination)
station_names = StationLoader.new(file: "./stations.csv").load.station_names
puts 'Estación de Origen: '
origin = origin.strip
puts station_names[origin]
raise if station_names[origin].nil?
puts 'Estación de Destino: '
destination = destination.strip
puts station_names[destination]
raise if station_names[destination].nil?
res = Planner.get.travel(from: origin.to_s, to: destination.to_s)
puts res.stations.reverse.map { |s| "#{s.id} #{s.name} (#{s.line})"}.join("\n")
rescue StandardError => e
puts e.inspect
end
private
def prepare(filter: 0.04)
puts "Preparing. filter: #{filter}"
random = Random.new(100)
cropped_stations = StationLoader.new(file: "./stations.csv")
.load.station_names
.keys
.select { |k| random.rand > (1 - filter) }
crop_station_zip = []
cropped_stations.each { |o| cropped_stations.each { |d| crop_station_zip << [o, d] } }
puts "#{crop_station_zip.length} stations tuples loaded for test"
crop_station_zip
end
def calculate_matrix_parallel_threads(chance = 1)
tuples = prepare(filter: chance)
Parallel.map(tuples, in_threads: 12) do |from, to|
["#{from}->#{to}", Planner.get.travel(from:, to:)]
end.to_h
end
def calculate_matrix_parallel_processes(chance = 1)
tuples = prepare(filter: chance)
Parallel.map(tuples, in_processes: 12) do |from, to|
# puts "#{from} -> #{to}"
["#{from}->#{to}", Planner.get.travel(from:, to:)]
end.to_h
end
def calculate_matrix(chance = 1)
distance_matrix = {}
prepare(filter: chance).each do |from, to|
result = Planner.get.travel(from:, to:)
# puts "#{from} -> #{to} = #{result.cost}"
distance_matrix["#{from}->#{to}"] = result
end
distance_matrix
end
end