-
Notifications
You must be signed in to change notification settings - Fork 6
Graph class #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Graph class #13
Conversation
ee8c2c8 to
2d5762c
Compare
lib/networkx/digraph.rb
Outdated
| def number_of_edges | ||
| num = 0 | ||
| @adj.each { |_, v| num += v.length } | ||
| num |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if how this is better performance-wise, but you can probably also try it out.
def number_of_edges
@adj.values.map(&:length).inject(:+)
end
lib/networkx/digraph.rb
Outdated
| @adj[node].length | ||
| end | ||
|
|
||
| # Returns the reversed version of a the graph |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a the -> the
In general, just double-check triple-check the YARD comments for any typos. 😄
lib/networkx/digraph.rb
Outdated
| # graph.to_undirected | ||
| def to_undirected | ||
| new_graph = NetworkX::Graph.new(@graph) | ||
| @nodes.each_key { |k| new_graph.add_node(k, @nodes[k]) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any specific reason for not using the more obvious each rather than each_key when we anyway have to access the value (@nodes[k]) too? Maybe change it to:
@nodes.each { |k, v| new_graph.add_node(k, v) }| @nodes.each_key { |k| new_graph.add_node(k, @nodes[k]) } | ||
| @adj.each_key do |k| | ||
| @adj[k].each_key { |v| new_graph.add_edge(v, k, @adj[k][v]) } | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, use Hash#each rather than Hash#each_key 😄
| sub_graph = NetworkX::DiGraph.new(@graph) | ||
| nodes.each do |u, _| | ||
| raise KeyError, "#{u} does not exist in the current graph!" unless @nodes.key?(u) | ||
| sub_graph.add_node(u, @nodes[u]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yet again, each vs each_key 😄
lib/networkx/digraph.rb
Outdated
| end | ||
| end | ||
|
|
||
| # Returns subgraph conisting of given edges |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: conisting -> consisting
| # | ||
| # @param edges [Array<Object, Object>] the array of edges | ||
| # @param weight [Array<Integer>] the array of weights | ||
| def add_weighted_edges(edges, weights) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The args provided in the documentation and the args of the method don't match. Have a look at this again.
lib/networkx/graph.rb
Outdated
| # | ||
| # @param node [Object] the node to be checked | ||
| def node?(node) | ||
| @node.key?(node) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: @node -> @nodes
How did this not come up in the unit tests? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method was quite trivial like some other methods like edge? etc. Do I need to add tests for such trivial methods as well? 😥
lib/networkx/graph.rb
Outdated
| # @param node_1 [Object] the first node of the edge to be checked | ||
| # @param node_2 [Object] the second node of the edge to be checked | ||
| def edge?(node_1, node_2) | ||
| return true if @nodes.key?(node_1) && @adj[node_1].key?(node_2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not re-use the key? method here instead of writing @nodes.key? again?
lib/networkx/graph.rb
Outdated
| # @param node_2 [Object] the second node of the edge to be checked | ||
| def edge?(node_1, node_2) | ||
| return true if @nodes.key?(node_1) && @adj[node_1].key?(node_2) | ||
| false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the explicit true and false really required here? The method could simply be just 1-line. 😄
def edge?(node_1, node_2)
node?(node_1) && @adj[node_1].key?(node_2)
end
lib/networkx/graph.rb
Outdated
| # | ||
| # @param node [Object] the node whose data is to be fetched | ||
| def get_node_data(node) | ||
| return @nodes[node] if @nodes.key?(node) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, the above node? method could be used rather than re-writing @nodes.key?(node)
lib/networkx/graph.rb
Outdated
| # @param node [Object] the node whose data is to be fetched | ||
| def get_node_data(node) | ||
| return @nodes[node] if @nodes.key?(node) | ||
| raise ArgumentError, 'No such node exists!' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the other way round would be more readable?
def get_node_data(node)
raise ArgumentError, 'No such node exists' unless node?(node)
@nodes[node]
endThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Follow this for the next 2 methods too (with KeyError, and node? instead of @nodes.key). Let's keep the review DRY. 😉
| num = 0 | ||
| @adj.each { |_, v| num += v.length } | ||
| num / 2 | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refer to the map + inject combination I had mentioned in an earlier comment.
lib/networkx/graph.rb
Outdated
| # @example | ||
| # graph.size(true) | ||
| # | ||
| # @praram is_weighted [Bool] if we want weighted size of unweighted size |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make same documentation comment changes, as mentioned to the same method in the previous file. (Logic explanation moved to params + typo)
| def new_edge_key(node_1, node_2) | ||
| return 0 if @adj[node_1][node_2].nil? | ||
| key = @adj[node_1][node_2].length | ||
| key += 1 while @adj[node_1][node_2].key?(key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this to handle deletion on intermediate key edges? If so, you can use maintain a last_key and use it here rather than #length and loop for coming to last_key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then we would have to store the last_key attribute for every edge. Wouldn't that be an overhead? Also, we'd like to reuse the keys after deleting them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I took the reference of networkx for the implementation of this method.
| raise KeyError, "#{node_2} is not a valid node" unless @nodes.key?(node_2) | ||
| raise KeyError, 'The given edge is not a valid one.' unless @adj[node_1].key?(node_2) | ||
| raise KeyError, 'The given edge is not a valid one.' unless @adj[node_1][node_2].key?(key) | ||
| @adj[node_1][node_2].delete(key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These raise checks come up in the DiGraph class too, right? Maybe the raise checks can be put as a separate method to be called from both remove_edge methods.
| super(node_1, node_2) if key.nil? | ||
| return true if @nodes.key?(node_1) && @adj[node_1].key?(node_2) && @adj[node_1][node_2].key?(key) | ||
| false | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refer to the "explicit true-false" comment above. ![]()
| # graph.to_undirected | ||
| def to_undirected | ||
| graph = NetworkX::Graph.new(@graph) | ||
| @nodes.each { |node, node_attr| graph.add_node(node, node_attr) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't MultiDiGraph#to_undirected supposed to written Multigraph`? Have a good look at this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| @adj[node_1][node_2].each_key { |key| edge_attrs.merge!(@adj[node_1][node_2][key]) } | ||
| graph.add_edge(node_1, node_2, edge_attrs) | ||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remember the each vs each_key comment? ![]()
lib/networkx/multidigraph.rb
Outdated
| graph | ||
| end | ||
|
|
||
| # Returns the reversed version of a the graph |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: a the -> the
| @adj.each_key do |u| | ||
| @adj[u].each_key { |v| @adj[u][v].each_key { |k| new_graph.add_edge(v, u, @adj[u][v][k]) } } | ||
| end | ||
| new_graph |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... And the each vs each_key again
| in_degree_no = 0 | ||
| @pred[node].each_key { |u| in_degree_no += @pred[node][u].length } | ||
| in_degree_no | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refer to the map + inject comment
lib/networkx/multidigraph.rb
Outdated
| def out_degree(node) | ||
| out_degree_no = 0 | ||
| @adj[node].each_key { |u| out_degree_no += @adj[node][u].length } | ||
| out_degree_no |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refer to the map + inject comment above
| no_of_edges = 0 | ||
| @adj.each_key { |node_1| @adj[node_1].each_key { |node_2| no_of_edges += @adj[node_1][node_2].length } } | ||
| no_of_edges | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you might have guessed by now, map + inject again. 😉
| end | ||
| end | ||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refer to the comments mentioned in the MultiDiGraph class
athityakumar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @npochhi. Pretty good PR, but there have been lots of suggestions as there are multiple Graph classes with very similar things to fix. To mention some,
map+injecteachvseach_key- Explicit true/false returns from a method
- Typos
Also, I found a method that had a typo in it's code (variable). That's what unit tests are supposed to prevent, but Travis CI build seemingly passed. Which means, the unit-tests are not complete. Can you please add the unit-tests to all the methods?
athityakumar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work with this PR. 👍
Description
Implements all the basic classes