networkx 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -2
- data/README.md +20 -22
- data/lib/networkx/auxillary_functions/cliques.rb +4 -4
- data/lib/networkx/auxillary_functions/cycles.rb +1 -1
- data/lib/networkx/auxillary_functions/dag.rb +3 -3
- data/lib/networkx/auxillary_functions/eccentricity.rb +2 -2
- data/lib/networkx/auxillary_functions/mis.rb +4 -2
- data/lib/networkx/auxillary_functions/mst.rb +2 -2
- data/lib/networkx/auxillary_functions/vitality.rb +1 -1
- data/lib/networkx/converters/to_csv.rb +1 -1
- data/lib/networkx/flow/capacityscaling.rb +14 -12
- data/lib/networkx/flow/edmondskarp.rb +2 -2
- data/lib/networkx/flow/preflowpush.rb +3 -3
- data/lib/networkx/flow/shortestaugmentingpath.rb +3 -3
- data/lib/networkx/flow/utils.rb +1 -1
- data/lib/networkx/graph.rb +2 -3
- data/lib/networkx/link_analysis/hits.rb +1 -1
- data/lib/networkx/link_analysis/pagerank.rb +3 -47
- data/lib/networkx/operators/binary.rb +24 -13
- data/lib/networkx/operators/product.rb +8 -8
- data/lib/networkx/operators/unary.rb +2 -2
- data/lib/networkx/shortest_path/dense.rb +1 -1
- data/lib/networkx/shortest_path/unweighted.rb +3 -3
- data/lib/networkx/shortest_path/weighted.rb +10 -10
- data/lib/networkx/to_matrix.rb +2 -2
- data/lib/networkx/traversals/dfs.rb +1 -1
- data/lib/networkx/version.rb +1 -1
- data/networkx.gemspec +5 -1
- metadata +6 -6
- data/.github/workflows/gem-push.yml +0 -45
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4bce7e05d9da7dd9774ad976cb82c8de0bd5847be9fb0dfc07af1042568446a9
|
4
|
+
data.tar.gz: '085683454ca374c50f594509e13da7c3114131e54936a11f6daf4dd3f4924b29'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 91cdd246c4692b87a90405676f58a330257ecc02d6cdc9e55c79428afc4d22a9d621fd175d6408e0a7f6aafec50deaa8cd2eb9a0d5ef49360befd5ae8e88dd30
|
7
|
+
data.tar.gz: 79bade11b9709a78102bb83d13d77a3abe661fbaf75bdc18dbc5f822e71d6c5ecd53c8b7c46324cf9d6eda1df570f299c77191e8079426c50e4fd5b3f87e7ffd
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -1,23 +1,37 @@
|
|
1
1
|
# NetworkX.rb
|
2
2
|
|
3
|
+
[](https://badge.fury.io/rb/networkx)
|
4
|
+
|
3
5
|
[NetworkX](https://networkx.github.io/) is a very popular Python library, that handles various use-cases of the Graph Data Structure.
|
4
6
|
This project intends to provide a working alternative to the Ruby community, by closely mimicing as many features as possible.
|
5
7
|
|
6
8
|
## List of contents
|
7
9
|
|
8
10
|
- [Installing](#installing)
|
11
|
+
- [Usage](#Usage)
|
9
12
|
- [Document](#document)
|
10
|
-
- [Roadmap](#roadmap)
|
11
13
|
- [Contributing](#contributing)
|
12
14
|
- [License](#license)
|
13
15
|
|
14
16
|
## Installing
|
15
17
|
|
16
|
-
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
- install it yourself as:
|
19
|
+
```console
|
20
|
+
$ gem install networkx
|
21
|
+
```
|
22
|
+
|
23
|
+
|
24
|
+
- Or use Bundler & Gemfile
|
25
|
+
1. add this line to your application's Gemfile:
|
26
|
+
```ruby
|
27
|
+
gem 'networkx'
|
28
|
+
```
|
29
|
+
2. And then execute:
|
30
|
+
```console
|
31
|
+
$ bundle install
|
32
|
+
```
|
33
|
+
|
34
|
+
## Usage
|
21
35
|
|
22
36
|
```ruby
|
23
37
|
require 'networkx'
|
@@ -30,22 +44,6 @@ g.add_edge('start', 'stop')
|
|
30
44
|
|
31
45
|
You can read [Document](https://SciRuby.github.io/networkx.rb/) for this library.
|
32
46
|
|
33
|
-
## Roadmap
|
34
|
-
|
35
|
-
Quite easily, any networkx user would be able to understand the number of details that have been implemented in the Python library. As a humble start towards the release of v0.1.0, the following could be the goals to achieve :
|
36
|
-
|
37
|
-
- `Node` : This class should be capable of handling different types of nodes (not just `String` / `Integer`).
|
38
|
-
A possible complex use-case could be XML nodes.
|
39
|
-
|
40
|
-
- `Edge` : This class should be capable of handling different types of edges.
|
41
|
-
Though a basic undirected Graph doesn't store any metadata in the edges, weighted edges and parametric edges are something that need to be handled.
|
42
|
-
|
43
|
-
- `Graph` : The simplest of graphs.
|
44
|
-
This class handles just connections between different `Node`s via `Edge`s.
|
45
|
-
|
46
|
-
- `DirectedGraph` : Inherits from `Graph` class.
|
47
|
-
Uses directions between `Edge`s.
|
48
|
-
|
49
47
|
## Contributing
|
50
48
|
|
51
49
|
Your contributions are always welcome!
|
@@ -5,15 +5,15 @@ module NetworkX
|
|
5
5
|
#
|
6
6
|
# @return [Array<Array<Object>>] Arrays of nodes in the cliques
|
7
7
|
def self.find_cliques(graph)
|
8
|
-
return nil if graph.nodes.empty?
|
8
|
+
return nil if graph.nodes(data: true).empty?
|
9
9
|
|
10
10
|
q = [nil]
|
11
11
|
adj = {}
|
12
|
-
graph.nodes.each_key { |u| adj[u] = [] }
|
12
|
+
graph.nodes(data: true).each_key { |u| adj[u] = [] }
|
13
13
|
graph.adj.each { |u, u_edges| u_edges.each_key { |v| adj[u] << v if u != v } }
|
14
14
|
|
15
|
-
subg = graph.nodes.keys
|
16
|
-
cand = graph.nodes.keys
|
15
|
+
subg = graph.nodes(data: true).keys
|
16
|
+
cand = graph.nodes(data: true).keys
|
17
17
|
u = subg.max { |n1, n2| (cand & adj[n1]).length <=> (cand & adj[n2]).length }
|
18
18
|
ext_u = cand - adj[u]
|
19
19
|
stack = []
|
@@ -6,7 +6,7 @@ module NetworkX
|
|
6
6
|
#
|
7
7
|
# @return [Array<Array<Object>>] Arrays of nodes in the cycles
|
8
8
|
def self.cycle_basis(graph, root = nil)
|
9
|
-
gnodes = graph.nodes.keys
|
9
|
+
gnodes = graph.nodes(data: true).keys
|
10
10
|
cycles = []
|
11
11
|
until gnodes.empty?
|
12
12
|
root = gnodes.shift if root.nil?
|
@@ -34,14 +34,14 @@ module NetworkX
|
|
34
34
|
raise ArgumentError, 'Topological Sort not defined on undirected graphs!' unless graph.directed?
|
35
35
|
|
36
36
|
nodes = []
|
37
|
-
indegree_map = graph.nodes.each_key.map do |u|
|
37
|
+
indegree_map = graph.nodes(data: true).each_key.map do |u|
|
38
38
|
[u, graph.in_degree(u)] if graph.in_degree(u).positive?
|
39
39
|
end.compact.to_h
|
40
|
-
zero_indegree = graph.nodes.each_key.select { |u| graph.in_degree(u).zero? }
|
40
|
+
zero_indegree = graph.nodes(data: true).each_key.select { |u| graph.in_degree(u).zero? }
|
41
41
|
|
42
42
|
until zero_indegree.empty?
|
43
43
|
node = zero_indegree.shift
|
44
|
-
raise ArgumentError, 'Graph changed during iteration!' unless graph.nodes.has_key?(node)
|
44
|
+
raise ArgumentError, 'Graph changed during iteration!' unless graph.nodes(data: true).has_key?(node)
|
45
45
|
|
46
46
|
graph.adj[node].each_key do |child|
|
47
47
|
indegree_map[child] -= 1
|
@@ -7,10 +7,10 @@ module NetworkX
|
|
7
7
|
# @return [Array<Numeric>, Numeric] eccentricity/eccentricites of all nodes
|
8
8
|
def self.eccentricity(graph, node = nil)
|
9
9
|
e = {}
|
10
|
-
graph.nodes.each do |u, _|
|
10
|
+
graph.nodes(data: true).each do |u, _|
|
11
11
|
length = single_source_shortest_path_length(graph, u)
|
12
12
|
l = length.length
|
13
|
-
raise ArgumentError, 'Found infinite path length!' unless l == graph.nodes.length
|
13
|
+
raise ArgumentError, 'Found infinite path length!' unless l == graph.nodes(data: true).length
|
14
14
|
|
15
15
|
e[u] = length.max_by { |a| a[1] }[1]
|
16
16
|
end
|
@@ -6,13 +6,15 @@ module NetworkX
|
|
6
6
|
#
|
7
7
|
# @return [Numeric] radius of the graph
|
8
8
|
def self.maximal_independent_set(graph, nodes)
|
9
|
-
|
9
|
+
if (graph.nodes(data: true).keys - nodes).empty?
|
10
|
+
raise 'The array containing the nodes should be a subset of the graph!'
|
11
|
+
end
|
10
12
|
|
11
13
|
neighbours = []
|
12
14
|
nodes.each { |u| graph.adj[u].each { |v, _| neighbours |= [v] } }
|
13
15
|
raise 'Nodes is not an independent set of graph!' if (neighbours - nodes).empty?
|
14
16
|
|
15
|
-
available_nodes = graph.nodes.keys - (neighbours | nodes)
|
17
|
+
available_nodes = graph.nodes(data: true).keys - (neighbours | nodes)
|
16
18
|
until available_nodes.empty?
|
17
19
|
node = available_nodes.sample
|
18
20
|
nodes << node
|
@@ -20,8 +20,8 @@ module NetworkX
|
|
20
20
|
mst = Marshal.load(Marshal.dump(graph))
|
21
21
|
mst.clear
|
22
22
|
edges = get_edges_weights(graph).sort_by { |a| a[1] }
|
23
|
-
union_find = UnionFind.new(graph.nodes.keys)
|
24
|
-
while edges.any? && mst.nodes.length <= graph.nodes.length
|
23
|
+
union_find = UnionFind.new(graph.nodes(data: true).keys)
|
24
|
+
while edges.any? && mst.nodes(data: true).length <= graph.nodes(data: true).length
|
25
25
|
edge = edges.shift
|
26
26
|
unless union_find.connected?(edge[0][0], edge[0][1])
|
27
27
|
union_find.union(edge[0][0], edge[0][1])
|
@@ -7,7 +7,7 @@ module NetworkX
|
|
7
7
|
# @return [Numeric] closeness vitality of the given node
|
8
8
|
def self.closeness_vitality(graph, node)
|
9
9
|
before = wiener_index(graph)
|
10
|
-
after = wiener_index(graph.subgraph(graph.nodes.keys - [node]))
|
10
|
+
after = wiener_index(graph.subgraph(graph.nodes(data: true).keys - [node]))
|
11
11
|
before - after
|
12
12
|
end
|
13
13
|
end
|
@@ -11,7 +11,7 @@ module NetworkX
|
|
11
11
|
# @return [Boolean] whether there exists a negative cycle in graph
|
12
12
|
def self.negative_edge_cycle(graph)
|
13
13
|
newnode = generate_unique_node
|
14
|
-
graph.add_edges(graph.nodes.keys.map { |n| [newnode, n] })
|
14
|
+
graph.add_edges(graph.nodes(data: true).keys.map { |n| [newnode, n] })
|
15
15
|
begin
|
16
16
|
bellmanford_predecesor_distance(graph, newnode)
|
17
17
|
rescue ArgumentError
|
@@ -25,10 +25,10 @@ module NetworkX
|
|
25
25
|
# Detects the unboundedness in the residual graph
|
26
26
|
def self._detect_unboundedness(residual)
|
27
27
|
g = NetworkX::DiGraph.new
|
28
|
-
g.add_nodes(residual.nodes.keys.zip(residual.nodes.values))
|
28
|
+
g.add_nodes(residual.nodes(data: true).keys.zip(residual.nodes(data: true).values))
|
29
29
|
inf = residual.graph[:inf]
|
30
30
|
|
31
|
-
residual.nodes.each do |u, _attr|
|
31
|
+
residual.nodes(data: true).each do |u, _attr|
|
32
32
|
residual.adj[u].each do |v, uv_attrs|
|
33
33
|
w = inf
|
34
34
|
uv_attrs.each { |_key, edge_attrs| w = [w, edge_attrs[:weight]].min if edge_attrs[:capacity] == inf }
|
@@ -41,10 +41,10 @@ module NetworkX
|
|
41
41
|
# Returns the residual graph of the given graph
|
42
42
|
def self._build_residual_network(graph)
|
43
43
|
raise ArgumentError, 'Sum of demands should be 0!' unless \
|
44
|
-
graph.nodes.values.map { |attr| attr[:demand] || 0 }.inject(0, :+).zero?
|
44
|
+
graph.nodes(data: true).values.map { |attr| attr[:demand] || 0 }.inject(0, :+).zero?
|
45
45
|
|
46
46
|
residual = NetworkX::MultiDiGraph.new(inf: 0)
|
47
|
-
residual.add_nodes(graph.nodes.map { |u, attr| [u, {excess: (attr[:demand] || 0) * -1, potential: 0}] })
|
47
|
+
residual.add_nodes(graph.nodes(data: true).map { |u, attr| [u, {excess: (attr[:demand] || 0) * -1, potential: 0}] })
|
48
48
|
inf = Float::INFINITY
|
49
49
|
edge_list = []
|
50
50
|
|
@@ -66,9 +66,11 @@ module NetworkX
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
temp_inf = [residual.nodes
|
70
|
-
|
71
|
-
|
69
|
+
temp_inf = [residual.nodes(data: true).map do |_u, attrs|
|
70
|
+
attrs[:excess].abs
|
71
|
+
end.inject(0, :+), edge_list.map do |_, _, _, e|
|
72
|
+
(e.has_key?(:capacity) && e[:capacity] != inf ? e[:capacity] : 0)
|
73
|
+
end.inject(0, :+) * 2].max
|
72
74
|
inf = temp_inf.zero? ? 1 : temp_inf
|
73
75
|
|
74
76
|
edge_list.each do |u, v, k, e|
|
@@ -88,7 +90,7 @@ module NetworkX
|
|
88
90
|
inf = Float::INFINITY
|
89
91
|
|
90
92
|
if graph.multigraph?
|
91
|
-
graph.nodes.each_key do |u|
|
93
|
+
graph.nodes(data: true).each_key do |u|
|
92
94
|
flow_dict[u] = {}
|
93
95
|
graph.adj[u].each do |v, uv_edges|
|
94
96
|
flow_dict[u][v] = uv_edges.transform_values do |e|
|
@@ -102,7 +104,7 @@ module NetworkX
|
|
102
104
|
end
|
103
105
|
end
|
104
106
|
else
|
105
|
-
graph.nodes.each_key do |u|
|
107
|
+
graph.nodes(data: true).each_key do |u|
|
106
108
|
flow_dict[u] = graph.adj[u].to_h do |v, e|
|
107
109
|
[v, u != v || (e[:capacity] || inf) <= 0 || (e[:weight] || 0) >= 0 ? 0 : e[:capacity]]
|
108
110
|
end
|
@@ -163,7 +165,7 @@ module NetworkX
|
|
163
165
|
s_set = Set.new
|
164
166
|
t_set = Set.new
|
165
167
|
|
166
|
-
residual.nodes.each do |u, _attrs|
|
168
|
+
residual.nodes(data: true).each do |u, _attrs|
|
167
169
|
excess = r_nodes[u][:excess]
|
168
170
|
if excess >= delta
|
169
171
|
s_set.add(u)
|
@@ -236,7 +238,7 @@ module NetworkX
|
|
236
238
|
|
237
239
|
r_nodes.each_value { |attrs| raise ArgumentError, 'No flow satisfying all demands!' if attrs[:excess] != 0 }
|
238
240
|
|
239
|
-
residual.nodes.each_key do |node|
|
241
|
+
residual.nodes(data: true).each_key do |node|
|
240
242
|
residual.adj[node].each_value do |uv_edges|
|
241
243
|
uv_edges.each_value do |k_attrs|
|
242
244
|
flow = k_attrs[:flow]
|
@@ -84,8 +84,8 @@ module NetworkX
|
|
84
84
|
|
85
85
|
# Helper function for the edmondskarp function
|
86
86
|
def self.edmondskarp_impl(graph, source, target, residual, cutoff)
|
87
|
-
raise ArgumentError, 'Source not in graph!' unless graph.nodes.has_key?(source)
|
88
|
-
raise ArgumentError, 'Target not in graph!' unless graph.nodes.has_key?(target)
|
87
|
+
raise ArgumentError, 'Source not in graph!' unless graph.nodes(data: true).has_key?(source)
|
88
|
+
raise ArgumentError, 'Target not in graph!' unless graph.nodes(data: true).has_key?(target)
|
89
89
|
raise ArgumentError, 'Source and target are same node!' if source == target
|
90
90
|
|
91
91
|
res_graph = residual.nil? ? build_residual_network(graph) : residual.clone
|
@@ -12,8 +12,8 @@ module NetworkX
|
|
12
12
|
|
13
13
|
# Helper function to apply the preflow push algorithm
|
14
14
|
def self.preflowpush_impl(graph, source, target, residual, globalrelabel_freq, value_only)
|
15
|
-
raise ArgumentError, 'Source not in graph!' unless graph.nodes.has_key?(source)
|
16
|
-
raise ArgumentError, 'Target not in graph!' unless graph.nodes.has_key?(target)
|
15
|
+
raise ArgumentError, 'Source not in graph!' unless graph.nodes(data: true).has_key?(source)
|
16
|
+
raise ArgumentError, 'Target not in graph!' unless graph.nodes(data: true).has_key?(target)
|
17
17
|
raise ArgumentError, 'Source and Target are same!' if source == target
|
18
18
|
|
19
19
|
globalrelabel_freq = 0 if globalrelabel_freq.nil?
|
@@ -38,7 +38,7 @@ module NetworkX
|
|
38
38
|
return r_network
|
39
39
|
end
|
40
40
|
|
41
|
-
n = r_network.nodes.length
|
41
|
+
n = r_network.nodes(data: true).length
|
42
42
|
max_height = heights.map { |u, h| u == source ? -1 : h }.max
|
43
43
|
heights[source] = n
|
44
44
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module NetworkX
|
2
2
|
# Helper function for running the shortest augmenting path algorithm
|
3
3
|
def self.shortest_augmenting_path_impl(graph, source, target, residual, two_phase, cutoff)
|
4
|
-
raise ArgumentError, 'Source is not in the graph!' unless graph.nodes.has_key?(source)
|
5
|
-
raise ArgumentError, 'Target is not in the graph!' unless graph.nodes.has_key?(target)
|
4
|
+
raise ArgumentError, 'Source is not in the graph!' unless graph.nodes(data: true).has_key?(source)
|
5
|
+
raise ArgumentError, 'Target is not in the graph!' unless graph.nodes(data: true).has_key?(target)
|
6
6
|
raise ArgumentError, 'Source and Target are the same!' if source == target
|
7
7
|
|
8
8
|
residual = residual.nil? ? build_residual_network(graph) : residual
|
@@ -35,7 +35,7 @@ module NetworkX
|
|
35
35
|
return residual
|
36
36
|
end
|
37
37
|
|
38
|
-
n = graph.nodes.length
|
38
|
+
n = graph.nodes(data: true).length
|
39
39
|
m = residual.size / 2
|
40
40
|
|
41
41
|
r_nodes.each do |node, attrs|
|
data/lib/networkx/flow/utils.rb
CHANGED
@@ -62,7 +62,7 @@ module NetworkX
|
|
62
62
|
raise NotImplementedError, 'MultiGraph and MultiDiGraph not supported!' if graph.multigraph?
|
63
63
|
|
64
64
|
r_network = NetworkX::DiGraph.new(inf: 0, flow_value: 0)
|
65
|
-
r_network.add_nodes(graph.nodes.keys)
|
65
|
+
r_network.add_nodes(graph.nodes(data: true).keys)
|
66
66
|
inf = Float::INFINITY
|
67
67
|
edge_list = []
|
68
68
|
|
data/lib/networkx/graph.rb
CHANGED
@@ -213,14 +213,13 @@ module NetworkX
|
|
213
213
|
end
|
214
214
|
end
|
215
215
|
|
216
|
-
#
|
217
|
-
# [Alert] Change the default in the futher. Please specify the `data`.
|
216
|
+
# Return nodes of graph
|
218
217
|
#
|
219
218
|
# @param data [bool] true if you want data of each edge
|
220
219
|
#
|
221
220
|
# @return [Hash | Array] if data is true, it returns hash including data.
|
222
221
|
# otherwise, simple nodes array.
|
223
|
-
def nodes(data:
|
222
|
+
def nodes(data: false)
|
224
223
|
if data
|
225
224
|
@nodes
|
226
225
|
else
|
@@ -8,7 +8,7 @@ module NetworkX
|
|
8
8
|
#
|
9
9
|
# @return [Array<Numeric, Numeric>] hits and authority scores
|
10
10
|
def self.hits(graph, max_iter = 100, tol = 1e-8, nstart)
|
11
|
-
return [{}, {}] if graph.nodes.empty?
|
11
|
+
return [{}, {}] if graph.nodes(data: true).empty?
|
12
12
|
|
13
13
|
h = nstart
|
14
14
|
sum = h.values.sum
|
@@ -2,61 +2,16 @@ module NetworkX
|
|
2
2
|
# Computes pagerank values for the graph
|
3
3
|
#
|
4
4
|
# @param graph [Graph] a graph
|
5
|
-
# @param init [Array<Numeric>] initial pagerank values for the nodes
|
6
5
|
# @param alpha [Numeric] the alpha value to compute the pagerank
|
7
6
|
# @param eps [Numeric] tolerence to check for convergence
|
8
7
|
# @param max_iter [Integer] max iterations for the pagerank algorithm to run
|
9
8
|
#
|
10
|
-
# @return [
|
11
|
-
def self.pagerank(graph,
|
12
|
-
dim = graph.nodes.length
|
13
|
-
if init.nil?
|
14
|
-
init = graph.nodes(data: false).to_h{ |i| [i, 1.0 / dim] }
|
15
|
-
else
|
16
|
-
s = init.values.sum.to_f
|
17
|
-
init = init.transform_values { |v| v / s }
|
18
|
-
end
|
19
|
-
raise ArgumentError, 'Init array needs to have same length as number of graph nodes!' \
|
20
|
-
unless dim == init.length
|
21
|
-
|
22
|
-
matrix = []
|
23
|
-
elem_ind = {}
|
24
|
-
p = []
|
25
|
-
curr = init.values
|
26
|
-
init.keys.each_with_index { |n, i| elem_ind[n] = i }
|
27
|
-
graph.adj.each do |_u, u_edges|
|
28
|
-
adj_arr = Array.new(dim, 0)
|
29
|
-
u_edges.each do |v, _|
|
30
|
-
adj_arr[elem_ind[v]] = 1
|
31
|
-
end
|
32
|
-
matrix << adj_arr
|
33
|
-
end
|
34
|
-
(0..(dim - 1)).each do |i|
|
35
|
-
p[i] = []
|
36
|
-
(0..(dim - 1)).each { |j| p[i][j] = matrix[i][j] / (matrix[i].sum * 1.0) }
|
37
|
-
end
|
38
|
-
|
39
|
-
max_iter.times do |_|
|
40
|
-
prev = curr.clone
|
41
|
-
dim.times do |i|
|
42
|
-
ip = 0
|
43
|
-
dim.times { |j| ip += p.transpose[i][j] * prev[j] }
|
44
|
-
curr[i] = (alpha * ip) + ((1 - alpha) / (dim * 1.0))
|
45
|
-
end
|
46
|
-
err = 0
|
47
|
-
dim.times { |i| err += (prev[i] - curr[i]).abs }
|
48
|
-
return curr if err < eps
|
49
|
-
end
|
50
|
-
raise ArgumentError, 'PageRank failed to converge!'
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.pagerank2(graph, alpha: 0.85, personalization: nil, eps: 1e-6, max_iter: 100)
|
9
|
+
# @return [Hash of Object => Float] pagerank values of the graph
|
10
|
+
def self.pagerank(graph, alpha: 0.85, personalization: nil, eps: 1e-6, max_iter: 100)
|
54
11
|
n = graph.number_of_nodes
|
55
12
|
|
56
13
|
matrix, index_to_node = NetworkX.to_matrix(graph, 0)
|
57
14
|
|
58
|
-
# index_to_node = {0=>0, 1=>1, 2=>2, 3=>3}
|
59
|
-
|
60
15
|
index_from_node = index_to_node.invert
|
61
16
|
|
62
17
|
probabilities = Array.new(n) do |i|
|
@@ -84,6 +39,7 @@ module NetworkX
|
|
84
39
|
err = (0...n).map{|i| (prev[i] - curr[i]).abs }.sum
|
85
40
|
return (0...n).map{|i| [index_to_node[i], curr[i]] }.sort.to_h if err < eps
|
86
41
|
end
|
42
|
+
warn "pagerank() failed within #{max_iter} iterations. Please inclease max_iter: or loosen eps:"
|
87
43
|
(0...n).map{|i| [index_to_node[i], curr[i]] }.sort.to_h
|
88
44
|
end
|
89
45
|
end
|
@@ -27,12 +27,12 @@ module NetworkX
|
|
27
27
|
def self.convert_to_distinct_labels(graph, starting_int = -1)
|
28
28
|
new_graph = graph.class.new
|
29
29
|
|
30
|
-
idx_dict = graph.nodes.keys.to_h do |v|
|
30
|
+
idx_dict = graph.nodes(data: true).keys.to_h do |v|
|
31
31
|
starting_int += 1
|
32
32
|
[v, starting_int]
|
33
33
|
end
|
34
34
|
|
35
|
-
graph.nodes.each do |u, attrs|
|
35
|
+
graph.nodes(data: true).each do |u, attrs|
|
36
36
|
new_graph.add_node(u.to_s + idx_dict[u].to_s, **attrs)
|
37
37
|
end
|
38
38
|
|
@@ -60,9 +60,12 @@ module NetworkX
|
|
60
60
|
result = g1.class.new
|
61
61
|
|
62
62
|
raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
|
63
|
-
raise ArgumentError, 'Node sets must be equal!' unless (g1.nodes.keys - g2.nodes.keys).empty?
|
64
63
|
|
65
|
-
g1.nodes.
|
64
|
+
unless (g1.nodes(data: true).keys - g2.nodes(data: true).keys).empty?
|
65
|
+
raise ArgumentError, 'Node sets must be equal!'
|
66
|
+
end
|
67
|
+
|
68
|
+
g1.nodes(data: true).each { |u, attrs| result.add_node(u, **attrs) }
|
66
69
|
|
67
70
|
g1, g2 = g2, g1 if g1.number_of_edges > g2.number_of_edges
|
68
71
|
g1.adj.each do |u, u_edges|
|
@@ -91,9 +94,12 @@ module NetworkX
|
|
91
94
|
result = g1.class.new
|
92
95
|
|
93
96
|
raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
|
94
|
-
raise ArgumentError, 'Node sets must be equal!' unless (g1.nodes.keys - g2.nodes.keys).empty?
|
95
97
|
|
96
|
-
g1.nodes.
|
98
|
+
unless (g1.nodes(data: true).keys - g2.nodes(data: true).keys).empty?
|
99
|
+
raise ArgumentError, 'Node sets must be equal!'
|
100
|
+
end
|
101
|
+
|
102
|
+
g1.nodes(data: true).each { |u, attrs| result.add_node(u, **attrs) }
|
97
103
|
|
98
104
|
g1.adj.each do |u, u_edges|
|
99
105
|
u_edges.each do |v, uv_attrs|
|
@@ -121,9 +127,12 @@ module NetworkX
|
|
121
127
|
result = g1.class.new
|
122
128
|
|
123
129
|
raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
|
124
|
-
raise ArgumentError, 'Node sets must be equal!' unless (g1.nodes.keys - g2.nodes.keys).empty?
|
125
130
|
|
126
|
-
g1.nodes.
|
131
|
+
unless (g1.nodes(data: true).keys - g2.nodes(data: true).keys).empty?
|
132
|
+
raise ArgumentError, 'Node sets must be equal!'
|
133
|
+
end
|
134
|
+
|
135
|
+
g1.nodes(data: true).each { |u, attrs| result.add_node(u, **attrs) }
|
127
136
|
|
128
137
|
g1.adj.each do |u, u_edges|
|
129
138
|
u_edges.each do |v, uv_attrs|
|
@@ -166,8 +175,8 @@ module NetworkX
|
|
166
175
|
|
167
176
|
raise ArgumentError, 'Arguments must be both Graphs or MultiGraphs!' unless g1.multigraph? == g2.multigraph?
|
168
177
|
|
169
|
-
result.add_nodes(g1.nodes.map { |u, attrs| [u, attrs] })
|
170
|
-
result.add_nodes(g2.nodes.map { |u, attrs| [u, attrs] })
|
178
|
+
result.add_nodes(g1.nodes(data: true).map { |u, attrs| [u, attrs] })
|
179
|
+
result.add_nodes(g2.nodes(data: true).map { |u, attrs| [u, attrs] })
|
171
180
|
|
172
181
|
if g1.multigraph?
|
173
182
|
g1.adj.each { |u, e| e.each { |v, uv_edges| uv_edges.each_value { |attrs| result.add_edge(u, v, **attrs) } } }
|
@@ -192,14 +201,16 @@ module NetworkX
|
|
192
201
|
new_graph.graph.merge!(g1.graph)
|
193
202
|
new_graph.graph.merge!(g2.graph)
|
194
203
|
|
195
|
-
|
204
|
+
unless (g1.nodes(data: true).keys & g2.nodes(data: true).keys).empty?
|
205
|
+
raise ArgumentError, 'Graphs must be disjoint!'
|
206
|
+
end
|
196
207
|
|
197
208
|
g1_edges = get_edges(g1)
|
198
209
|
g2_edges = get_edges(g2)
|
199
210
|
|
200
|
-
new_graph.add_nodes(g1.nodes.keys)
|
211
|
+
new_graph.add_nodes(g1.nodes(data: true).keys)
|
201
212
|
new_graph.add_edges(g1_edges)
|
202
|
-
new_graph.add_nodes(g2.nodes.keys)
|
213
|
+
new_graph.add_nodes(g2.nodes(data: true).keys)
|
203
214
|
new_graph.add_edges(g2_edges)
|
204
215
|
|
205
216
|
new_graph
|
@@ -28,8 +28,8 @@ module NetworkX
|
|
28
28
|
# Returns the node product of nodes of two graphs
|
29
29
|
def self.node_product(g1, g2)
|
30
30
|
n_product = []
|
31
|
-
g1.nodes.each do |k1, attrs1|
|
32
|
-
g2.nodes.each do |k2, attrs2|
|
31
|
+
g1.nodes(data: true).each do |k1, attrs1|
|
32
|
+
g2.nodes(data: true).each do |k2, attrs2|
|
33
33
|
n_product << [[k1, k2], hash_product(attrs1, attrs2)]
|
34
34
|
end
|
35
35
|
end
|
@@ -62,7 +62,7 @@ module NetworkX
|
|
62
62
|
def self.edges_cross_nodes(g1, g2)
|
63
63
|
result = []
|
64
64
|
edges_in_array(g1).each do |u, v, d|
|
65
|
-
g2.nodes.each_key do |x|
|
65
|
+
g2.nodes(data: true).each_key do |x|
|
66
66
|
result << [[u, x], [v, x], d]
|
67
67
|
end
|
68
68
|
end
|
@@ -72,7 +72,7 @@ module NetworkX
|
|
72
72
|
# Returns the product of directed nodes with edges
|
73
73
|
def self.nodes_cross_edges(g1, g2)
|
74
74
|
result = []
|
75
|
-
g1.nodes.each_key do |x|
|
75
|
+
g1.nodes(data: true).each_key do |x|
|
76
76
|
edges_in_array(g2).each do |u, v, d|
|
77
77
|
result << [[x, u], [x, v], d]
|
78
78
|
end
|
@@ -84,8 +84,8 @@ module NetworkX
|
|
84
84
|
def self.edges_cross_nodes_and_nodes(g1, g2)
|
85
85
|
result = []
|
86
86
|
edges_in_array(g1).each do |u, v, d|
|
87
|
-
g2.nodes.each_key do |x|
|
88
|
-
g2.nodes.each_key do |y|
|
87
|
+
g2.nodes(data: true).each_key do |x|
|
88
|
+
g2.nodes(data: true).each_key do |y|
|
89
89
|
result << [[u, x], [v, y], d]
|
90
90
|
end
|
91
91
|
end
|
@@ -174,8 +174,8 @@ module NetworkX
|
|
174
174
|
raise ArgumentError, 'Power must be a positive quantity!' if pow <= 0
|
175
175
|
|
176
176
|
result = NetworkX::Graph.new
|
177
|
-
result.add_nodes(graph.nodes.map { |n, attrs| [n, attrs] })
|
178
|
-
graph.nodes.each do |n, _attrs|
|
177
|
+
result.add_nodes(graph.nodes(data: true).map { |n, attrs| [n, attrs] })
|
178
|
+
graph.nodes(data: true).each do |n, _attrs|
|
179
179
|
seen = {}
|
180
180
|
level = 1
|
181
181
|
next_level = graph.adj[n]
|
@@ -8,9 +8,9 @@ module NetworkX
|
|
8
8
|
result = Marshal.load(Marshal.dump(graph))
|
9
9
|
result.clear
|
10
10
|
|
11
|
-
result.add_nodes(graph.nodes.map { |u, attrs| [u, attrs] })
|
11
|
+
result.add_nodes(graph.nodes(data: true).map { |u, attrs| [u, attrs] })
|
12
12
|
graph.adj.each do |u, u_edges|
|
13
|
-
graph.nodes.each { |v, attrs| result.add_edge(u, v, **attrs) if !u_edges.has_key?(v) && u != v }
|
13
|
+
graph.nodes(data: true).each { |v, attrs| result.add_edge(u, v, **attrs) if !u_edges.has_key?(v) && u != v }
|
14
14
|
end
|
15
15
|
result
|
16
16
|
end
|
@@ -7,7 +7,7 @@ module NetworkX
|
|
7
7
|
# b/w all pairs of nodes
|
8
8
|
def self.floyd_warshall(graph)
|
9
9
|
a, index = to_matrix(graph, Float::INFINITY, 'min')
|
10
|
-
nodelen = graph.nodes.length
|
10
|
+
nodelen = graph.nodes(data: true).length
|
11
11
|
(0..(nodelen - 1)).each { |i| a[i, i] = 0 }
|
12
12
|
(0..(nodelen - 1)).each do |k|
|
13
13
|
(0..(nodelen - 1)).each do |i|
|
@@ -34,7 +34,7 @@ module NetworkX
|
|
34
34
|
|
35
35
|
cutoff = Float::INFINITY if cutoff.nil?
|
36
36
|
nextlevel = {source => 1}
|
37
|
-
help_single_shortest_path_length(graph.adj, nextlevel, cutoff).take(graph.nodes.length)
|
37
|
+
help_single_shortest_path_length(graph.adj, nextlevel, cutoff).take(graph.nodes(data: true).length)
|
38
38
|
end
|
39
39
|
|
40
40
|
# Computes shortest path values to all nodes from all nodes
|
@@ -45,7 +45,7 @@ module NetworkX
|
|
45
45
|
# @return [Array<Object, Array<Object, Numeric>>] path lengths for all nodes from all nodes
|
46
46
|
def self.all_pairs_shortest_path_length(graph, cutoff = nil)
|
47
47
|
shortest_paths = []
|
48
|
-
graph.nodes.each_key { |n| shortest_paths << [n, single_source_shortest_path_length(graph, n, cutoff)] }
|
48
|
+
graph.nodes(data: true).each_key { |n| shortest_paths << [n, single_source_shortest_path_length(graph, n, cutoff)] }
|
49
49
|
shortest_paths
|
50
50
|
end
|
51
51
|
|
@@ -93,7 +93,7 @@ module NetworkX
|
|
93
93
|
# @return [Array<Object, Hash {Object => Array<Object> }>] paths for all nodes from all nodes
|
94
94
|
def self.all_pairs_shortest_path(graph, cutoff = nil)
|
95
95
|
shortest_paths = []
|
96
|
-
graph.nodes.each_key { |n| shortest_paths << [n, single_source_shortest_path(graph, n, cutoff)] }
|
96
|
+
graph.nodes(data: true).each_key { |n| shortest_paths << [n, single_source_shortest_path(graph, n, cutoff)] }
|
97
97
|
shortest_paths
|
98
98
|
end
|
99
99
|
|
@@ -188,7 +188,7 @@ module NetworkX
|
|
188
188
|
# paths and path lengths between all nodes
|
189
189
|
def self.all_pairs_dijkstra(graph, cutoff = nil)
|
190
190
|
path = []
|
191
|
-
graph.nodes.each_key { |n| path << [n, singlesource_dijkstra(graph, n, nil, cutoff)] }
|
191
|
+
graph.nodes(data: true).each_key { |n| path << [n, singlesource_dijkstra(graph, n, nil, cutoff)] }
|
192
192
|
path
|
193
193
|
end
|
194
194
|
|
@@ -200,7 +200,7 @@ module NetworkX
|
|
200
200
|
# @return [Array<Object, Hash{ Object => Numeric }>] path lengths between all nodes
|
201
201
|
def self.all_pairs_dijkstra_path_length(graph, cutoff = nil)
|
202
202
|
path_lengths = []
|
203
|
-
graph.nodes.each_key { |n| path_lengths << [n, singlesource_dijkstra_path_length(graph, n, cutoff)] }
|
203
|
+
graph.nodes(data: true).each_key { |n| path_lengths << [n, singlesource_dijkstra_path_length(graph, n, cutoff)] }
|
204
204
|
path_lengths
|
205
205
|
end
|
206
206
|
|
@@ -212,7 +212,7 @@ module NetworkX
|
|
212
212
|
# @return [Array<Object, Hash{ Object => Array<Object> }>] path lengths between all nodes
|
213
213
|
def self.all_pairs_dijkstra_path(graph, cutoff = nil)
|
214
214
|
paths = []
|
215
|
-
graph.nodes.each_key { |n| paths << singlesource_dijkstra_path(graph, n, cutoff) }
|
215
|
+
graph.nodes(data: true).each_key { |n| paths << singlesource_dijkstra_path(graph, n, cutoff) }
|
216
216
|
paths
|
217
217
|
end
|
218
218
|
|
@@ -221,7 +221,7 @@ module NetworkX
|
|
221
221
|
pred = sources.product([[]]).to_h if pred.nil?
|
222
222
|
dist = sources.product([0]).to_h if dist.nil?
|
223
223
|
|
224
|
-
inf, n, count, q, in_q = Float::INFINITY, graph.nodes.length, {}, sources.clone, Set.new(sources)
|
224
|
+
inf, n, count, q, in_q = Float::INFINITY, graph.nodes(data: true).length, {}, sources.clone, Set.new(sources)
|
225
225
|
until q.empty?
|
226
226
|
u = q.shift
|
227
227
|
in_q.delete(u)
|
@@ -281,7 +281,7 @@ module NetworkX
|
|
281
281
|
# TODO: Detection of selfloop edges
|
282
282
|
dist = {source => 0}
|
283
283
|
pred = {source => []}
|
284
|
-
return [pred, dist] if graph.nodes.length == 1
|
284
|
+
return [pred, dist] if graph.nodes(data: true).length == 1
|
285
285
|
|
286
286
|
dist = help_bellman_ford(graph, [source], weight, pred, nil, dist, cutoff, target)
|
287
287
|
[pred, dist]
|
@@ -360,7 +360,7 @@ module NetworkX
|
|
360
360
|
# @return [Array<Object, Hash{ Object => Numeric }>] path lengths from source to all nodes
|
361
361
|
def self.allpairs_bellmanford_path_length(graph, cutoff = nil)
|
362
362
|
path_lengths = []
|
363
|
-
graph.nodes.each_key { |n| path_lengths << [n, singlesource_bellmanford_path_length(graph, n, cutoff)] }
|
363
|
+
graph.nodes(data: true).each_key { |n| path_lengths << [n, singlesource_bellmanford_path_length(graph, n, cutoff)] }
|
364
364
|
path_lengths
|
365
365
|
end
|
366
366
|
|
@@ -372,13 +372,13 @@ module NetworkX
|
|
372
372
|
# @return [Array<Object, Hash{ Object => Array<Object> }>] path lengths from source to all nodes
|
373
373
|
def self.allpairs_bellmanford_path(graph, cutoff = nil)
|
374
374
|
paths = []
|
375
|
-
graph.nodes.each_key { |n| paths << [n, singlesource_bellmanford_path(graph, n, cutoff)] }
|
375
|
+
graph.nodes(data: true).each_key { |n| paths << [n, singlesource_bellmanford_path(graph, n, cutoff)] }
|
376
376
|
paths
|
377
377
|
end
|
378
378
|
|
379
379
|
# Helper function to get sources
|
380
380
|
def self.get_sources(graph)
|
381
|
-
graph.nodes.collect { |k, _v| k }
|
381
|
+
graph.nodes(data: true).collect { |k, _v| k }
|
382
382
|
end
|
383
383
|
|
384
384
|
# Helper function to get distances
|
@@ -393,7 +393,7 @@ module NetworkX
|
|
393
393
|
# Helper function to set path lengths for Johnson algorithm
|
394
394
|
def self.set_path_lengths_johnson(graph, dist_path, new_weight)
|
395
395
|
path_lengths = []
|
396
|
-
graph.nodes.each_key { |n| path_lengths << [n, dist_path.call(graph, n, new_weight)] }
|
396
|
+
graph.nodes(data: true).each_key { |n| path_lengths << [n, dist_path.call(graph, n, new_weight)] }
|
397
397
|
path_lengths
|
398
398
|
end
|
399
399
|
|
@@ -405,7 +405,7 @@ module NetworkX
|
|
405
405
|
def self.johnson(graph)
|
406
406
|
dist, pred = {}, {}
|
407
407
|
sources = get_sources(graph)
|
408
|
-
graph.nodes.each_key do |n|
|
408
|
+
graph.nodes(data: true).each_key do |n|
|
409
409
|
dist[n], pred[n] = 0, []
|
410
410
|
end
|
411
411
|
weight = get_weight(graph)
|
data/lib/networkx/to_matrix.rb
CHANGED
@@ -2,14 +2,14 @@ module NetworkX
|
|
2
2
|
def self.to_matrix(graph, val, multigraph_weight = 'sum')
|
3
3
|
is_undirected = !graph.directed?
|
4
4
|
is_multigraph = graph.multigraph?
|
5
|
-
nodelen = graph.nodes.length
|
5
|
+
nodelen = graph.nodes(data: true).length
|
6
6
|
|
7
7
|
m = Matrix.build(nodelen) { val }
|
8
8
|
index = {}
|
9
9
|
inv_index = {}
|
10
10
|
ind = 0
|
11
11
|
|
12
|
-
graph.nodes.each do |u, _|
|
12
|
+
graph.nodes(data: true).each do |u, _|
|
13
13
|
index[u] = ind
|
14
14
|
inv_index[ind] = u
|
15
15
|
ind += 1
|
@@ -11,7 +11,7 @@ module NetworkX
|
|
11
11
|
raise KeyError, "There exists no node names #{source} in the given graph." unless graph.node?(source)
|
12
12
|
|
13
13
|
depth_limit += 1 if depth_limit
|
14
|
-
depth_limit = graph.nodes.length if depth_limit.nil?
|
14
|
+
depth_limit = graph.nodes(data: true).length if depth_limit.nil?
|
15
15
|
dfs_edges = []
|
16
16
|
visited = [source]
|
17
17
|
stack = [[-1, source, depth_limit, graph.neighbours(source)]]
|
data/lib/networkx/version.rb
CHANGED
data/networkx.gemspec
CHANGED
@@ -13,13 +13,15 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.email = ['athityakumar@gmail.com']
|
14
14
|
spec.summary = 'A Ruby implemenation of the well-known graph library called networkx.'
|
15
15
|
spec.description = NetworkX::DESCRIPTION
|
16
|
-
spec.homepage = 'https://github.com/
|
16
|
+
spec.homepage = 'https://github.com/SciRuby/networkx.rb'
|
17
17
|
spec.license = 'MIT'
|
18
18
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
19
|
spec.bindir = 'bin'
|
20
20
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = ['lib']
|
22
22
|
|
23
|
+
spec.required_ruby_version = '>= 2.7'
|
24
|
+
|
23
25
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
24
26
|
spec.add_development_dependency 'rake', '~> 13.0'
|
25
27
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
@@ -34,4 +36,6 @@ Gem::Specification.new do |spec|
|
|
34
36
|
|
35
37
|
spec.add_runtime_dependency 'matrix', '~> 0.4'
|
36
38
|
spec.add_runtime_dependency 'rb_heap', '~> 1.0'
|
39
|
+
|
40
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
37
41
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: networkx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Athitya Kumar
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-11-
|
11
|
+
date: 2022-11-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -207,7 +207,6 @@ files:
|
|
207
207
|
- ".github/PULL_REQUEST_TEMPLATE.md"
|
208
208
|
- ".github/workflows/ci.yml"
|
209
209
|
- ".github/workflows/doc.yml"
|
210
|
-
- ".github/workflows/gem-push.yml"
|
211
210
|
- ".gitignore"
|
212
211
|
- ".rspec"
|
213
212
|
- ".rubocop.yml"
|
@@ -259,10 +258,11 @@ files:
|
|
259
258
|
- lib/networkx/traversals/edge_dfs.rb
|
260
259
|
- lib/networkx/version.rb
|
261
260
|
- networkx.gemspec
|
262
|
-
homepage: https://github.com/
|
261
|
+
homepage: https://github.com/SciRuby/networkx.rb
|
263
262
|
licenses:
|
264
263
|
- MIT
|
265
|
-
metadata:
|
264
|
+
metadata:
|
265
|
+
rubygems_mfa_required: 'true'
|
266
266
|
post_install_message:
|
267
267
|
rdoc_options: []
|
268
268
|
require_paths:
|
@@ -271,7 +271,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
271
271
|
requirements:
|
272
272
|
- - ">="
|
273
273
|
- !ruby/object:Gem::Version
|
274
|
-
version: '
|
274
|
+
version: '2.7'
|
275
275
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
276
276
|
requirements:
|
277
277
|
- - ">="
|
@@ -1,45 +0,0 @@
|
|
1
|
-
name: Ruby Gem
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
branches: [ main ]
|
6
|
-
pull_request:
|
7
|
-
branches: [ main ]
|
8
|
-
|
9
|
-
jobs:
|
10
|
-
build:
|
11
|
-
name: Build + Publish
|
12
|
-
runs-on: ubuntu-latest
|
13
|
-
permissions:
|
14
|
-
contents: read
|
15
|
-
packages: write
|
16
|
-
|
17
|
-
steps:
|
18
|
-
- uses: actions/checkout@v2
|
19
|
-
- name: Set up Ruby 2.6
|
20
|
-
uses: actions/setup-ruby@v1
|
21
|
-
with:
|
22
|
-
ruby-version: 2.6.x
|
23
|
-
|
24
|
-
- name: Publish to GPR
|
25
|
-
run: |
|
26
|
-
mkdir -p $HOME/.gem
|
27
|
-
touch $HOME/.gem/credentials
|
28
|
-
chmod 0600 $HOME/.gem/credentials
|
29
|
-
printf -- "---\n:github: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
30
|
-
gem build *.gemspec
|
31
|
-
gem push --KEY github --host https://rubygems.pkg.github.com/${OWNER} *.gem
|
32
|
-
env:
|
33
|
-
GEM_HOST_API_KEY: "Bearer ${{secrets.GITHUB_TOKEN}}"
|
34
|
-
OWNER: ${{ github.repository_owner }}
|
35
|
-
|
36
|
-
- name: Publish to RubyGems
|
37
|
-
run: |
|
38
|
-
mkdir -p $HOME/.gem
|
39
|
-
touch $HOME/.gem/credentials
|
40
|
-
chmod 0600 $HOME/.gem/credentials
|
41
|
-
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
42
|
-
gem build *.gemspec
|
43
|
-
gem push *.gem
|
44
|
-
env:
|
45
|
-
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
|