diff options
| author | mo khan <mo@mokhan.ca> | 2025-01-22 18:01:48 -0700 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-01-22 18:01:48 -0700 |
| commit | 1b281e9b926d546dd781c2841b6fca94e61f3a97 (patch) | |
| tree | f9c9b689a232b9ae606e34692754d5ca4e5aa663 | |
| parent | 08fe640cc61a7c587297e079a2d174534fab5ff3 (diff) | |
Add ruby code to prove graph traversal
| -rw-r--r-- | 3431709-assignment-3.pdf | bin | 152826 -> 187523 bytes | |||
| -rw-r--r-- | assignments/3-solution.md | 14 | ||||
| -rw-r--r-- | assignments/3/graph.rb | 113 | ||||
| -rw-r--r-- | assignments/3/main.rb | 158 |
4 files changed, 125 insertions, 160 deletions
diff --git a/3431709-assignment-3.pdf b/3431709-assignment-3.pdf Binary files differindex 5b01942..e2e4f82 100644 --- a/3431709-assignment-3.pdf +++ b/3431709-assignment-3.pdf diff --git a/assignments/3-solution.md b/assignments/3-solution.md index 5101c79..478de5a 100644 --- a/assignments/3-solution.md +++ b/assignments/3-solution.md @@ -45,13 +45,14 @@ Chapter 7: F<->G: 8 ``` - There are 6 simple paths + There are 7 simple paths ```plaintext | Path | | ---- | | a,b,c,g | | a,b,e,c,g | + | a,b,e,d,c,g | | a,d,c,g | | a,d,e,b,c,g | | a,d,e,c,g | @@ -60,13 +61,16 @@ Chapter 7: > b. What is the shortest path from node A to node G? What is the overall delay? - The shortest path has a distance of 10. The overall delay is 11. + The shortest path has a distance of 10. + The overall delay is 11 (`((11 + 10 + 13 + 11 + 15 + 10 + 11)/7) = 11`). + ```plaintext | Path | Total Distance | | ---- | -------------- | | a,b,c,g | 5+4+2 = 11 | | a,b,e,c,g | 5+2+1+2 = 10 | + | a,b,e,d,c,g | 5+2+1+3+2 = 13 | | a,d,c,g | 6+3+2 = 11 | | a,d,e,b,c,g | 6+1+2+4+2 = 15 | | a,d,e,c,g | 6+1+1+2 = 10 | @@ -95,6 +99,12 @@ Chapter 7: | a,f,g | 3+8 = 11 | ``` +The following code can be used to prove these results: + +```ruby +!include assignments/3/graph.rb +``` + Chapter 8: > 9. Using a Caesar cipher with s = 5, decode the received message RTAJ TZY FY IF diff --git a/assignments/3/graph.rb b/assignments/3/graph.rb new file mode 100644 index 0000000..f9cdaca --- /dev/null +++ b/assignments/3/graph.rb @@ -0,0 +1,113 @@ +#!/usr/bin/env ruby + +require 'set' + +def assert_equal(expected, actual) + raise [expected, actual].inspect unless expected == actual +end + +def assert_includes(expected, actual) + puts [expected, 'not found in', actual].inspect unless actual.include?(expected) +end + +class Graph + def initialize + @graph = Hash.new { |h, k| h[k] = Set.new } + end + + def connect(source, destination, _distance) + @graph[source] << destination + @graph[destination] << source + end + + def paths_between(source, destination) + visited = Hash.new { |h, k| h[k] = false } + [].tap do |paths| + traverse(source, destination, visited) do |found| + paths.push(found.dup) + end + end + end + + def inspect + @graph.inspect + end + + private + + def traverse(source, destination, visited, path = []) + visited[source] = true + path << source + + if source == destination + yield path + else + @graph[source].each do |i| + if visited[i] == false + traverse(i, destination, visited, path) do |path| + yield path + end + end + end + end + + path.pop + visited[source] = false + end +end + +graph = Graph.new +graph.connect(:a, :b, 5) +graph.connect(:a, :d, 6) +graph.connect(:a, :f, 3) +graph.connect(:b, :c, 4) +graph.connect(:b, :e, 2) +graph.connect(:c, :d, 3) +graph.connect(:c, :e, 1) +graph.connect(:c, :g, 2) +graph.connect(:d, :e, 1) +graph.connect(:f, :g, 8) +puts graph.inspect + +puts "" +puts "Paths from A to G" +results = graph.paths_between(:a, :g) +results.each do |result| + puts result.inspect +end +assert_includes([:a,:b,:c,:g], results) +assert_includes([:a,:b,:e,:c,:g], results) +assert_includes([:a,:b,:e,:d,:c,:g], results) +assert_includes([:a,:d,:c,:g], results) +assert_includes([:a,:d,:e,:b,:c,:g], results) +assert_includes([:a,:d,:e,:c,:g], results) +assert_includes([:a,:f,:g], results) +assert_equal([ + [:a,:b,:c,:g], + [:a,:b,:e,:c,:g], + [:a,:b,:e,:d,:c,:g], + [:a,:d,:c,:g], + [:a,:d,:e,:b,:c,:g], + [:a,:d,:e,:c,:g], + [:a,:f,:g] +], results) + +puts "Without E" +graph = Graph.new +graph.connect(:a, :b, 5) +graph.connect(:a, :d, 6) +graph.connect(:a, :f, 3) +graph.connect(:b, :c, 4) +graph.connect(:c, :d, 3) +graph.connect(:c, :g, 2) +graph.connect(:f, :g, 8) +puts graph.inspect +results = graph.paths_between(:a, :g) +results.each do |result| + puts result.inspect +end +assert_equal([ + [:a,:b,:c,:g], + [:a,:d,:c,:g], + [:a,:f,:g] +], results) diff --git a/assignments/3/main.rb b/assignments/3/main.rb deleted file mode 100644 index 3c13ca6..0000000 --- a/assignments/3/main.rb +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/env ruby - -require 'set' - -def assert_equal(expected, actual) - raise [expected, actual].inspect unless expected == actual -end - -def assert_includes(expected, actual) - puts [expected, 'not found in', actual].inspect unless actual.include?(expected) -end - -=begin - A<->B: 5 - A<->D: 6 - A<->F: 3 - B<->C: 4 - B<->E: 2 - C<->D: 3 - C<->E: 1 - C<->G: 2 - D<->E: 1 - F<->G: 8 -=end - -# class Edge -# attr_reader :source, :destination, :distance - -# def initialize(source, destination, distance) -# @source = source -# @destination = destination -# @distance = distance -# end - -# def to_s -# "#{source.title}->#{destination.title}: #{distance}" -# end - -# end - -# class Node -# attr_reader :title, :edges - -# def initialize(title:) -# @title = title -# @edges = [] -# end - -# def to(node, distance) -# @edges.push(Edge.new(self, node, distance)) -# end - -# def each -# @edges.each do |edge| -# yield edge -# end -# end - -# def to_s -# title -# end - -# def inspect -# to_s -# end -# end - -class Graph - def initialize - @nodes = Hash.new { |h, k| h[k] = Set.new } - end - - def connect(source, destination, weight) - @nodes[source] << destination - @nodes[destination] << source - end - - def simple_paths(source, destination) - return [source] if source == destination - - @nodes[source].each do |other| - puts other - items = simple_paths(other, destination) - # if items.any? - # return [source, items] - # end - end - - [] - end - - def inspect - @nodes.inspect - end -end - -# a = Node.new(title: "A") -# b = Node.new(title: "B") -# c = Node.new(title: "C") -# d = Node.new(title: "D") -# e = Node.new(title: "E") -# f = Node.new(title: "F") -# g = Node.new(title: "G") - - -# a.to(b, 5) -# a.to(d, 6) -# a.to(f, 3) -# b.to(c, 4) -# b.to(e, 2) -# c.to(d, 3) -# c.to(e, 1) -# c.to(g, 2) -# d.to(e, 1) -# f.to(g, 8) - -# [a,b,c,d,e,f,g].each do |node| -# node.each do |edge| -# puts edge.to_s -# end -# end - -# puts "" -# puts "Paths from A to G" -# assert_includes([a,b,c,g], results) -# assert_includes([a,b,e,c,g], results) -# assert_includes([a,d,c,g], results) -# assert_includes([a,d,e,b,c,g], results) -# assert_includes([a,d,e,c,g], results) -# assert_includes([a,f,g], results) -# assert_equal([ -# [a,b,c,g], -# [a,b,e,c,g], -# [a,d,c,g], -# [a,d,e,b,c,g], -# [a,d,e,c,g], -# [a,f,g] -# ], results) - - -graph = Graph.new -graph.connect(:a, :b, 5) -graph.connect(:a, :d, 6) -graph.connect(:a, :f, 3) -graph.connect(:b, :c, 4) -graph.connect(:b, :e, 2) -graph.connect(:c, :d, 3) -graph.connect(:c, :e, 1) -graph.connect(:c, :g, 2) -graph.connect(:d, :e, 1) -graph.connect(:f, :g, 8) - -puts graph.inspect - -puts "" -puts "Paths from A to G" - -graph.simple_paths(:a, :g) |
