replacing 'eval' with a better solution - ruby

This method works, but it works very slowly. I think one of the problems might be the 'eval' statements in the add_by method.
Some explanation: every Node object has three relevant attributes, :x, :y and :neighbors. :x and :y are integers representing planar coordinates, :neighbors is an array, and nodes are stored in the #nodes array. The goal is to find, for each node k in #nodes, the nodes that are within some distance d of k and add them to the #neighbors array of k.
def set_neighbors d
def add_by dim, d
dict = {}
#nodes.each{|k| dict[k] = []}
#nodes.each_index do |k|
up = k+1
down = k-1
while up < #nodes.length and ((eval '#nodes[k].'+ dim) - (eval '#nodes[up].'+dim)).abs <= d
dict[#nodes[k]].push(#nodes[up])
up += 1
end
while down >= 0 and ((eval '#nodes[k].'+ dim) - (eval '#nodes[down].'+dim)).abs <= d
dict[#nodes[k]].push(#nodes[down])
down -= 1
end
end
return dict
end
#nodes.sort_by{|k| k.x}
exis = add_by('x', d)
whys = add_by('y', d)
#nodes.each do |k|
neighbors = exis[k]&whys[k]
k.neighbors = neighbors.select{|j| planar_distance(j,k) <= d}
end
end
My question is, how would you do this without either repeating the add_by routine for x and y or using eval?

You can avoid eval by using #nodes[k].send dim.to_sym.
I'm not sure what your code is doing exactly, but maybe a few pointers:
def set_neighbors d
#nodes.each do |node|
node.neighbors = #nodes.select do |n|
(node.x - n.x).abs <= d &&
(node.x - n.x).abs <= d &&
planar_distance(n,node) <= d
end - node
end
end

How would I do it? I'd use the Neo4J graph database via the neo4j gem (source). If you're concerned about performance, this is optimized for graph distance calculations. Also the API is very nice.
That being said, you really don't need eval at all. You can call a calculated method name on an object by using send. So you can replace the above with #nodes[k].send(dim), #nodes[up].send(dim), etc.

Related

What's a proper algorithm to count all possible paths from any given vertex to another in a graph?

I'm working with graphs and I'd like to count all possible paths from given vertex X to given vertex Y.
This is the algorithm I've come up with:
class Graph
def paths_from(vertex_a, vertex_b, count = 0, visited = Array.new(#vertices.length, false))
return count if #vertices.none?(vertex_b) || #vertices.none?(vertex_a)
count += 1 if vertex_a == vertex_b
visited[#vertices.index(vertex_a)] = true
#net[#vertices.index(vertex_a)].each do |vertex|
paths_from(vertex, vertex_b, count, visited) unless visited[#vertices.index(vertex)]
end
count
end
end
Using recursion, I'm expecting to traverse df through the graph. However, I keep getting 0 instead of the expected value given below graph:
describe Graph do
context 'can output all possible from vertex a to vertex b.' do
let(:subject) { Graph.new(%w[a b c d e]) }
before(:each) do
subject.add_edge(0, 1)
subject.add_edge(0, 2)
subject.add_edge(0, 4)
subject.add_edge(1, 2)
subject.add_edge(1, 4)
subject.add_edge(2, 3)
subject.add_edge(3, 1)
end
it 'example #1' do
expect(subject.paths_from('a', 'f')).to eql 0 # => should output 0 and it does.
end
it 'example #2' do
expect(subject.paths_from('f', 'a')).to eql 0 # => should ouput 0 and it does.
end
it 'example #3' do
expect(subject.paths_from('a', 'b')).to eql 2
end
end
end
Doubt #1: I've checked geeksforgeeks approach tips regarding the algorithm: it states I should backtrack. What is that and how may I do it? I guess they're referencing the visited variable... but I've got no clue as to how to do that.
I'll drop the class definition just in case.
class Graph
attr_accessor :net, :vertices
def initialize(vertices = [])
#net = Array.new(vertices.length) { [] }
#vertices = vertices
end
def add_edge(vertex_a, vertex_b)
return if #net[vertex_a].nil? || #vertices[vertex_b].nil?
#net[vertex_a] << #vertices[vertex_b]
end
end
Doubt #2: If I print the count variable right before the #net loop, it prints 0, then '1' four times, yet it returns 0. Why is that? I suppose it's because it's returing #paths_from's first call... if that's the case, how may I return #paths_from's last call's count variable?
I assume the graph is directed and contains no cycles.
Suppose the graph is described by the following hash.
graph = { :A=>[:C, :D], :B=> [:D], :C=>[:D, :E, :F], :D=>[:G], :E=>[:F, :H],
:F=>[:D, :G, :I, :H], :G=>[:H, :I], :H=>[], :I=>[] }
The nodes are keys and the arcs are given by the keys and each element of a keys value. There are, for example, arcs :A->:C, :A-->:D, :B->:D and so on.
We can display this graph as follows.
Given two of the nodes, designated as the origin and terminus, the problem is to determine the number of paths from origin to terminus.
Suppose
origin = :A
terminus = :H
It is seen that there are nine paths from A to H:
A-C-E-H
A-C-E-F-H
A-C-E-F-G-H
A-C-E-F-D-G-H
A-C-F-H
A-C-F-D-G-H
A-C-F-G-H
A-C-D-G-H
A-D-G-H
I will give two solutions. The first is a recursion that requires little code but enumerates all paths. The number of such paths, however, can grow exponentially with the number of nodes. The second is more complex but is much faster for larger graphs. It's computational complexity appears to be only O(n2), where n is the number of nodes.
Enumerate paths from origin to destination
def tot_paths(graph, terminus, node)
graph[node].reduce(0) do |tot, n|
tot + ((n == terminus) ? 1 : tot_paths(graph, terminus, n))
end
end
tot_paths(graph, :H, :A)
#=> 9
More complex, but a much more efficient solution
The second approach requires two steps. The first is to perform a topological sort of the nodes of the graph.
Any array sorted that is an array of topologically-sorted nodes has the property that, for any pair of nodes ni = sorted[i] and nj = sorted[j] there is no path from nj to ni if j > i. A directed graph with no cycles is guaranteed to have at least one topological sort of nodes.
I have used Kuhn's algorithm (described at the above link) to produce the topological sort given by the following array:
[:B, :A, :C, :E, :F, :D, :G, :I, :H]
As shown below, if these nodes are viewed as being on a line, all arcs are directed from left to right. (For now disregard the numbers shown above the nodes.)
My implementation of the Kuhn algorithm is as follows.
nodes = graph.keys
#=> [:A, :B, :C, :D, :E, :F, :G, :H, :I]
incoming = graph.each_with_object(nodes.map { |n| [n, []] }.to_h) do |(k,v),h|
v.each { |n| h[n] << k }
end
#=> {:A=>[], :B=>[], :C=>[:A], :D=>[:A, :B, :C, :F], :E=>[:C], :F=>[:C, :E],
# :G=>[:D, :F], :H=>[:E, :F, :G], :I=>[:F, :G]}
incoming[:H] #=> [:E, :F, :G], for example, shows that the arcs directed into node :H are :E->:H, :F->:H and :G->:H.
no_incoming_nodes = incoming.select { |k,v| v.empty? }.keys
#=> [:A, :B]
sorted_nodes = []
until no_incoming_nodes.empty?
n = no_incoming_nodes.pop
sorted_nodes << n
graph[n].each do |next_node|
incoming[next_node].delete(n)
no_incoming_nodes << next_node if incoming[next_node].empty?
end
end
sorted_nodes
#=> [:B, :A, :C, :E, :F, :D, :G, :I, :H]
The second step is to implement a dynamic-programming algorithm to count the number of paths from node :A to node :H. I will explain how it works by explaining the meaning of the numbers above each node in the diagram immediatally above.
The number of paths from node I (the element of sorted_nodes that is followed by the terminus) is 0 (the number above I) because I is not the terminus and has no outgoing nodes.
Going back one node in sorted_nodes, the number of paths from G to the terminus is 1 as it is followed by the terminus (1) and node I, which has 0 paths to the terminus.
The number of paths from node D to the terminus is 1 because D is followed by only one node, G, and G has 1 path to the terminus.
Node F has 3 paths to the terminus, 1 that goes directly to the terminus, 1 that passes through D, 0 that pass through I and 1 that passes through G.
Similarly, there are 4 paths from node E to the terminus, 8 paths from node C to the terminus and, our objective, 9 paths from A, the origin, to the terminus.
The computation can be implemented as follows (using sorted_nodes computed earlier).
origin = :A
terminus = :H
tot_to = graph.each_with_object({}) do |(k,v),h|
(h[k] = k == terminus ? 1 : 0) if v.empty?
end
#=> {:H=>1, :I=>0}
(sorted_nodes.index(terminus) - 1).downto(sorted_nodes.index(origin)).each do |i|
n = sorted_nodes[i]
tot_to[n] = graph[n].sum { |m| tot_to[m] }
end
tot_to[origin]
#=> 9
Lastly, I would like to mention that the dynamic programming algorithm could have been organised differently, with roughly equal computational efficiency. Rather than beginning at the terminus and working backward, we could have started at the origin and worked forward until the terminus is reached, at each node computing the number of paths from A to the given node.
You don't appear to be recording the output of the recursion.
can you try something like:
count += paths_from(vertex, vertex_b, count, visited) unless visited[#vertices.index(vertex)]
not passing in a count at all:
class Graph
attr_accessor :net, :vertices, :visited
def initialize(vertices = [])
#net = Array.new(vertices.length) { [] }
#visited = Array.new(vertices.length, false)
#vertices = vertices
end
def add_edge(vertex_a, vertex_b)
return if #net[vertex_a].nil? || #vertices[vertex_b].nil?
#net[vertex_a] << #vertices[vertex_b]
end
def paths_from(vertex_a, vertex_b)
return 0 if #vertices.none?(vertex_b) || #vertices.none?(vertex_a)
count = 0
count += 1 if vertex_a == vertex_b
#visited[#vertices.index(vertex_a)] = true
#net[#vertices.index(vertex_a)].each do |vertex|
count += paths_from(vertex, vertex_b) unless #visited[#vertices.index(vertex)]
end
count
end
end

Iterate over array and first again

In order to export the coordinates of a polygon with n points I need to have n+1 points. The additional one is supposed to "close" the polygon. Currently I simply iterate over the whole array and do it manually again for the first:
face.outer_loop.vertices.each do |g|
xml.Grafic(
:X=>g.position.x,
:Y=>g.position.y,
:Z=>g.position.z)
end
xml.Grafic(
:X=>face.outer_loop.vertices[0].x,
:Y=>face.outer_loop.vertices[0].y,
:Z=>face.outer_loop.vertices[0].z)
Is there a more elegant solution?
I can think about:
COORDS = %i(X Y Z)
(face.outer_loop.vertices + [face.outer_loop.vertices.first]).each do |g|
values = COORDS.map do |c|
g.position.public_send "#{c.to_s.downcase}"
end
xml.Graphic COORDS.zip(values).to_h
end
or use each_with_object to not pollute coords in the global namespace:
(face.outer_loop.vertices + [face.outer_loop.vertices.first]).each_with_object(%i(X Y Z)) do |g, coords|
values = coords.map do |c|
g.position.public_send "#{c.to_s.downcase}"
end
xml.Graphic coords.zip(values).to_h
end

implement shell sort by ruby

I try to implement shell sort by ruby.
def shell_sort(list)
d = list.length
return -1 if d == 0
(0...list.length).each do |i|
d = d / 2
puts "d:#{d}"
(0...(list.length-d)).each do |j|
if list[j] >= list[j+d]
list[j], list[j+d] = list[j+d], list[j]
end
end
puts list.inspect
break if d == 1
end
list
end
puts shell_sort([10,9,8,7,6,5,4,3,2,1]).inspect
but the result is incorrect.
=>[2, 1, 3, 4, 5, 7, 6, 8, 9, 10]
I don't know where going wrong, hope someone can help me. Thanks in advance!
I referenced Shell Sort in here : Shell Sort - Wikepedia, and from that I have understood your algorithm is wrong. Iteration of gap sequence is alright, I mean you iterate only upto d/2 == 1.
But for a gap, let's say 2, you simply iterate from 0 to list.length-2 and swap every j and j+2 elements if list[j] is greater than list[j+2]. That isn't even a proper insertion sort, and Shell Sort requires Insertion sorts on gaps. Also Shell Sort requires that after you do an x gap sort, every xth element, starting from anywhere will be sorted (see the example run on the link and you can verify yourself).
A case where it can wrong in a 2 gap sort pass :
list = 5,4,3,2,1
j = 0 passed :
list = 3,4,5,2,1
j = 1 passed :
list = 3,2,5,4,1
j = 2 passed
list = 3,2,1,4,5
After it completes, you can see that every 2nd element starting from 0 isn't in a sorted order. I suggest that you learn Insertion Sort first, then understand where and how it is used in Shell Sort, and try again, if you want to do it by yourself.
Anyway, I have written one (save it for later if you want) taking your method as a base, with a lot of comments. Hope you get the idea through this. Also tried to make the outputs clarify the how the algorithm works.
def shell_sort(list)
d = list.length
return -1 if d == 0
# You select and iterate over your gap sequence here.
until d/2 == 0 do
d = d / 2
# Now you pick up an index i, and make sure every dth element,
# starting from i is sorted.
# i = 0
# while i < list.length do
0.step(list.length) do |i|
# Okay we picked up index i. Now it's just plain insertion sort.
# Only difference is that we take elements with constant gap,
# rather than taking them up serially.
# igap = i + d
# while igap < list.length do
(i+d).step(list.length-1, d) do |igap|
# Just like insertion sort, we take up the last most value.
# So that we can shift values greater than list[igap] to its side,
# and assign it to a proper position we find for it later.
temp = list[igap]
j = igap
while j >= i do
break if list[j] >= list[j - d]
list[j] = list[j-d]
j -= d
end
# Okay this is where it belongs.
list[j] = temp
#igap += d
end
# i += 1
end
puts "#{d} sort done, the list now : "
puts list.inspect
end
list
end
list = [10,9,8,7,6,5,4,3,2,1]
puts "List before sort : "
puts list.inspect
shell_sort(list)
puts "Sorted list : "
puts list.inspect
I think your algorithm needs a little tweaking.
The reason it fails is simply because on the last run (when d == 1) the smallest element (1) isn't near enough the first element to swap it in in one go.
The easiest way to make it work is to "restart" your inner loop whenever elements switch places. So, a little bit rough solution would be something like
(0...(list.length-d)).each do |j|
if list[j] >= list[j+d]
list[j], list[j+d] = list[j+d], list[j]
d *= 2
break
end
end
This solution is of course far from optimal, but should achieve required results with as little code as possible.
You should just do a last run on array. To simplify your code I extracted exchange part into standalone fucntion so you could see now where you should do this:
def exchange e, list
(0...(list.length-e)).each do |j|
if list[j] >= list[j+e]
list[j], list[j+e] = list[j+e], list[j]
end
end
end
def shell_sort(list)
d = list.length
return -1 if d == 0
(0...list.length).each do |i|
d = d / 2
puts "d:#{d}"
exchange(d, list)
puts list.inspect
if d == 1
exchange(d, list)
break
end
end
list
end
arr = [10,9,8,7,6,5,4,3,2,1]
p shell_sort(arr)
Result:
#> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Pascal's Triangle in Ruby

I am writing Pascal's triangle in Ruby, but keep getting the error message:
pascalsTriangle.rb:3:in 'triangle': undefined method `each' for
4:Fixnum (NoMethodError) from pascalsTriangle.rb:18
def triangle(n)
for r in n:
lst=[1]
term=1
k=0
(0..r+1).step(1){ |index|
term=term*(r-k+1)/k
lst.append(term)
k+=1
}
print lst
end
end
triangle(4)
Why code C style in Ruby? :-)
Breaking the problem down would allow you to concentrate on one problem at a time and iterators would make the code more readable. I'm using the binomial theorem to calculate the values in the triangle. If you don't need a super large value from the triangle, this will be fast enough.
Calculating the 1000th line took 2.9 seconds on my virtual linux:
# factorial method
def fact(n)
(1..n).reduce(:*)
end
# binomial theorem, n choose k
def binomial(n,k)
return 1 if n-k <= 0
return 1 if k <= 0
fact(n) / ( fact(k) * fact( n - k ) )
end
def triangle(nth_line)
(0..nth_line).map { |e| binomial(nth_line, e) }
end
p triangle(5)
the final source code:
def triangle(n)
(0..n).each{|r|
lst=[1]
term=1
k=1
(0..r-1).step(1){|index|
term=term*(r-k+1)/k
lst.push term
k+=1
}
p lst
}
end
triangle(4)
changes:
you have syntax error on for r in n:.
a logical error on k=0 that causes Division by zero.
(0..r+1) is changed to (0..r-1)
there is no append method for array. changed to push
p is used instead of print
Factorial(num), takes a number and return the factorial of it.
find_num(n, k), is the mathmatical formula of pascales triangle. !n/
!k * !(n - k) ---- '!' = factorial of number
Lastly pascale(num), this iterates a new row of the triangle by
maping the index numbers or (k) for each row of (n).
If you want to truly understand how this works comment out the
pascale, and simply run numbers through find_num((row number),
(index number)). Then compare to a picture of the triangle to see
the magic for your self
-
def find_num(n, k)
result = factorial(n) / (factorial(k) * factorial(n - k))
end
def pascale(num)
i = 0
scale = 75
while i <= num
new_arr = []
(0..i).map {|x| new_arr << find_num(i, x)}
p new_arr.to_s.rjust(50 + scale)
i += 1
scale += 1
end
def factorial(num)
if num == 0
return 1
else
num *= factorial(num - 1)
end
end
end
pascale(12)

Is there any idiom to get the identity element (0,1) for an operation (:+,:*) on a Ruby object?

Given a certain object that respond_to? :+ I would like to know what it's the identity element for that operation on that object. For example, if a is Fixnum then it should give 0 for operation :+ because a + 0 == a for any Fixnum. Of course I already know the identity element for :+ and :* when talking about Fixnums, but is there any standard pattern/idiom to obtain those dynamically for all Numeric types and operations?.
More specifically I have write some code (see below) to calculate shortest path between v1 and v2 (vertexes in a graph) where the cost/distance/weigh of each edge in the graph is given in a user-specified type. In the current implementation the cost/weight of the edges could be a Fixnum, a Float or anything that implements Comparable and can add 0 to itself and return self.
But I was wondering what is the best pattern:
requiring that type used must support a + 0 == a
requiring that type provide some kind of addition identity element discovery 'a.class::ADDITION_IDENTITY_ELEMENT
??
My Dijkstra algorithm implementation
def s_path(v1,v2)
dist = Hash.new { nil}
pred = {}
dist[v1] = 0 # distance from v1 to v1 is zero
#pq = nodes
pq = [v1]
while u = pq.shift
for edge in from(u)
u,v,cost = *edge
new_dist = cost + dist[u]
if dist[v].nil? or new_dist < dist[v]
dist[v] = new_dist
pred[v] = u
pq << v
end
end
end
path = [v2]
path << pred[path.last] while pred[path.last]
path.reverse
end
I think the a.class::ADDITION_IDENTITY_ELEMENT is pretty good except I would call it a.class::Zero.
Another option would be to do (a-a).
Personally I wouldn't try to make things so abstract and I would just require that every distance be a Numeric (e.g. Float or Integer). Then you can just keep using 0.

Resources