From b9da1cba3b8ffb533d26529f8db5b471b131aa00 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Thu, 19 Apr 2018 14:23:27 +0200 Subject: [PATCH 01/28] Add generator for cycle graph --- loom.iml | 36 ++++++++++++++++++++++++++++++++++++ src/loom/gen.clj | 14 ++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 loom.iml diff --git a/loom.iml b/loom.iml new file mode 100644 index 0000000..12b3e5d --- /dev/null +++ b/loom.iml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/loom/gen.clj b/src/loom/gen.clj index 662c8cd..74b5b09 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -53,3 +53,17 @@ (-> g (add-nodes* nodes) (add-edges* edges)))) + +(defn gen-circle + "Adds num-nodes nodes to graph g and connects each one to degree + other nodes." + [g num-nodes degree] + {:pre [(even? degree)]} + (let [out-degree (/ degree 2) + nodes (range num-nodes) + edges (for [n nodes + d (range 1 (inc out-degree))] + [n (mod (+ n d) (count nodes))])] + (-> g + (add-nodes* nodes) + (add-edges* edges)))) From 2a3da41e47e1f8863742d7d7062eedd36c40a486 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Mon, 23 Apr 2018 11:04:24 +0200 Subject: [PATCH 02/28] Specify out-degree when generating a circle. Instead of degree, which then had to be divided by two. That required making sure we have an even number, which now is not neccessary anymore. --- src/loom/gen.clj | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/loom/gen.clj b/src/loom/gen.clj index 74b5b09..9f1cc47 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -55,12 +55,10 @@ (add-edges* edges)))) (defn gen-circle - "Adds num-nodes nodes to graph g and connects each one to degree + "Adds num-nodes nodes to graph g and connects each one to out-degree other nodes." - [g num-nodes degree] - {:pre [(even? degree)]} - (let [out-degree (/ degree 2) - nodes (range num-nodes) + [g num-nodes out-degree] + (let [nodes (range num-nodes) edges (for [n nodes d (range 1 (inc out-degree))] [n (mod (+ n d) (count nodes))])] From a88a01c6c7dfe05dd446ea0eeda7426016263b49 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Mon, 23 Apr 2018 11:14:37 +0200 Subject: [PATCH 03/28] Precodition on number of nodes in graph --- src/loom/gen.clj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/loom/gen.clj b/src/loom/gen.clj index 9f1cc47..d29ca5e 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -58,6 +58,7 @@ "Adds num-nodes nodes to graph g and connects each one to out-degree other nodes." [g num-nodes out-degree] + {:pre [(> num-nodes (* out-degree 2))]} (let [nodes (range num-nodes) edges (for [n nodes d (range 1 (inc out-degree))] From f8ec24b739ce4781e8af5d7b7cab344ffe4604e6 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Mon, 23 Apr 2018 14:48:25 +0200 Subject: [PATCH 04/28] Compute additional edges after Newman and Watts The function takes the number of nodes, a probability and a seed and returns a vector of additional nodes as described in Newman and Watts (1999). --- src/loom/gen.clj | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/loom/gen.clj b/src/loom/gen.clj index d29ca5e..6580708 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -66,3 +66,16 @@ (-> g (add-nodes* nodes) (add-edges* edges)))) + +(defn ^:private add-shortcuts + "Computes additional edges for a graph with num-nodes nodes as described + in Newman and Watts (1999)." + [num-nodes phi seed] + (reduce + #(when (.nextBoolean (java.util.Random. (+ seed %2))) + (let + [src (.nextInt (java.util.Random. (+ seed %2 42)) num-nodes) + dest (.nextInt (java.util.Random. (+ seed %2 -42)) num-nodes)] + (conj %1 [src dest]))) + [] + (range num-nodes))) From 39ee63811147b2a0619cf215ecbd37be0ad2bfa0 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Tue, 24 Apr 2018 11:19:42 +0200 Subject: [PATCH 05/28] Generator for Newman-Watts Small World Graph Functional composition of gen-circle and add-shortcuts. --- src/loom/gen.clj | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/loom/gen.clj b/src/loom/gen.clj index 6580708..f941630 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -68,14 +68,23 @@ (add-edges* edges)))) (defn ^:private add-shortcuts - "Computes additional edges for a graph with num-nodes nodes as described - in Newman and Watts (1999)." - [num-nodes phi seed] - (reduce - #(when (.nextBoolean (java.util.Random. (+ seed %2))) - (let - [src (.nextInt (java.util.Random. (+ seed %2 42)) num-nodes) - dest (.nextInt (java.util.Random. (+ seed %2 -42)) num-nodes)] - (conj %1 [src dest]))) - [] - (range num-nodes))) + "Computes additional edges for graph g as described in Newman and Watts (1999)." + ([g phi seed] + (let [rnd (java.util.Random. seed) + nodes (loom.graph/nodes g) + shortcuts (for [n nodes + :when (> phi (.nextDouble rnd))] + [n (.nextInt rnd (count nodes))])] + (-> g + (add-edges* shortcuts))))) + +(defn gen-newman-watts + "Generate a graph with small-world properties as described in Newman and Watts + (1999)." + ([g num-nodes out-degree phi seed] + (-> g + (gen-circle num-nodes out-degree) + (add-shortcuts phi seed))) + ([g num-nodes out-degree phi] + (gen-newman-watts g num-nodes out-degree (System/nanoTime)))) + From 72a6d29018d43a8fd8abf3fd5400f9ee39cb554a Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Tue, 24 Apr 2018 12:07:39 +0200 Subject: [PATCH 06/28] Fix bug in gen-newman-watts --- src/loom/gen.clj | 2 +- test/loom/test/gen.clj | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 test/loom/test/gen.clj diff --git a/src/loom/gen.clj b/src/loom/gen.clj index f941630..7fa6231 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -86,5 +86,5 @@ (gen-circle num-nodes out-degree) (add-shortcuts phi seed))) ([g num-nodes out-degree phi] - (gen-newman-watts g num-nodes out-degree (System/nanoTime)))) + (gen-newman-watts g num-nodes out-degree phi (System/nanoTime)))) diff --git a/test/loom/test/gen.clj b/test/loom/test/gen.clj new file mode 100644 index 0000000..f5f0dba --- /dev/null +++ b/test/loom/test/gen.clj @@ -0,0 +1 @@ +(ns loom.test.gen) From 2b7aba169fcdc8df4fcafc5ab5bb3272b27b2f09 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Tue, 24 Apr 2018 14:06:34 +0200 Subject: [PATCH 07/28] =?UTF-8?q?Add=20tests=20for=20generating=20circles?= =?UTF-8?q?=20f=C5=95om=20the=20different=20graph=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/loom/test/gen.clj | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/test/loom/test/gen.clj b/test/loom/test/gen.clj index f5f0dba..a229e0c 100644 --- a/test/loom/test/gen.clj +++ b/test/loom/test/gen.clj @@ -1 +1,21 @@ -(ns loom.test.gen) +(ns loom.test.gen + (:require [clojure.test :refer (deftest testing is)] + [loom.gen :refer (gen-circle gen-newman-watts)])) + +(deftest build-circle-test + (let [g1 (gen-circle (loom.graph/graph) 5 1) + g2 (gen-circle (loom.graph/graph) 20 3) + g3 (gen-circle (loom.graph/digraph) 25 2) + g4 (gen-circle (loom.graph/weighted-graph {0 {1 42 2 42} 1 {2 42 3 42} 2 {3 42 4 42}}) 10 1) + g5 (gen-circle (loom.graph/weighted-graph) 10 1) + g6 (gen-circle (loom.graph/weighted-digraph [0 1 42] [1 2 42] [2 3 42] [1 0 43] [2 1 43] [3 2 43]) 10 1) + g7 (gen-circle (loom.graph/weighted-digraph) 10 1) + ] + (testing "Generating circle-graphs from the different graph types" + (is (= (into #{} (range 5)) (loom.graph/nodes g1))) + (is (= (into #{} (range 20)) (loom.graph/nodes g2))) + (is (= (into #{} (range 25)) (loom.graph/nodes g3))) + (is (= (into #{} (range 10)) (loom.graph/nodes g4))) + (is (= (into #{} (range 10)) (loom.graph/nodes g5))) + (is (= (into #{} (range 10)) (loom.graph/nodes g6))) + (is (= (into #{} (range 10)) (loom.graph/nodes g7)))))) From c1969f04ac37a6e415bcbb81812b685cc2ec62d5 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Tue, 24 Apr 2018 16:18:41 +0200 Subject: [PATCH 08/28] Tests for nodes and edges in circle-graph --- test/loom/test/gen.clj | 58 +++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/test/loom/test/gen.clj b/test/loom/test/gen.clj index a229e0c..caa48a1 100644 --- a/test/loom/test/gen.clj +++ b/test/loom/test/gen.clj @@ -1,21 +1,45 @@ (ns loom.test.gen - (:require [clojure.test :refer (deftest testing is)] + (:require [clojure.test :refer (deftest testing is are)] + [loom.graph :refer (graph digraph weighted-graph weighted-digraph graph? nodes edges)] [loom.gen :refer (gen-circle gen-newman-watts)])) (deftest build-circle-test - (let [g1 (gen-circle (loom.graph/graph) 5 1) - g2 (gen-circle (loom.graph/graph) 20 3) - g3 (gen-circle (loom.graph/digraph) 25 2) - g4 (gen-circle (loom.graph/weighted-graph {0 {1 42 2 42} 1 {2 42 3 42} 2 {3 42 4 42}}) 10 1) - g5 (gen-circle (loom.graph/weighted-graph) 10 1) - g6 (gen-circle (loom.graph/weighted-digraph [0 1 42] [1 2 42] [2 3 42] [1 0 43] [2 1 43] [3 2 43]) 10 1) - g7 (gen-circle (loom.graph/weighted-digraph) 10 1) - ] - (testing "Generating circle-graphs from the different graph types" - (is (= (into #{} (range 5)) (loom.graph/nodes g1))) - (is (= (into #{} (range 20)) (loom.graph/nodes g2))) - (is (= (into #{} (range 25)) (loom.graph/nodes g3))) - (is (= (into #{} (range 10)) (loom.graph/nodes g4))) - (is (= (into #{} (range 10)) (loom.graph/nodes g5))) - (is (= (into #{} (range 10)) (loom.graph/nodes g6))) - (is (= (into #{} (range 10)) (loom.graph/nodes g7)))))) + (let [g1 (gen-circle (graph) 5 1) + g2 (gen-circle (graph) 6 2) + g3 (gen-circle (digraph) 6 2) + g4 (gen-circle (weighted-graph {0 {1 42 2 42} 1 {2 42 3 42} 2 {3 42 4 42}}) 10 1) + g5 (gen-circle (weighted-graph) 10 1) + g6 (gen-circle (weighted-digraph [0 1 42] [1 2 42] [2 3 42] [1 0 43] [2 1 43] [3 2 43]) 10 1) + g7 (gen-circle (weighted-digraph) 10 1) + ] + (testing "Generating circle-graphs from the different graph types" + (are [graphs] (graph? graphs) + g1 + g2 + g3 + g4 + g5 + g6 + g7)) + (testing "Nodes and Edges" + (are [expected got] (= expected got) + (into #{} (range 5)) (nodes g1) + (into #{} (range 6)) (nodes g2) + (into #{} (range 6)) (nodes g3) + (into #{} (range 10)) (nodes g4) + (into #{} (range 10)) (nodes g5) + (into #{} (range 10)) (nodes g6) + (into #{} (range 10)) (nodes g7) + #{[0 1] [1 0] [1 2] [2 1] [2 3] [3 2] [3 4] [4 3] [4 0] [0 4]} (set (edges g1)) + #{[0 1] [1 0] [1 2] [2 1] [2 3] [3 2] [3 4] [4 3] [4 5] [5 4] [5 0] [0 5] + [0 2] [2 0] [1 3] [3 1] [2 4] [4 2] [3 5] [5 3] [4 0] [0 4] [1 5] [5 1]} (set (edges g2)) + #{[0 1] [1 2] [2 3] [3 4] [4 5] [5 0] [0 2] [1 3] [2 4] [3 5] [4 0] [5 1]} (set (edges g3)) + #{[0 1] [1 2] [2 3] [3 4] [4 5] [5 6] [6 7] [7 8] [8 9] [9 0] + [0 2] [1 3] [2 4] + [1 0] [2 1] [3 2] [4 3] [5 4] [6 5] [7 6] [8 7] [9 8] [0 9] + [2 0] [3 1] [4 2]} (set (edges g4)) + #{[0 1] [1 2] [2 3] [3 4] [4 5] [5 6] [6 7] [7 8] [8 9] [9 0] + [1 0] [2 1] [3 2] [4 3] [5 4] [6 5] [7 6] [8 7] [9 8] [0 9]} (set (edges g5)) + #{[0 1] [1 2] [2 3] [3 4] [4 5] [5 6] [6 7] [7 8] [8 9] [9 0] + [1 0] [2 1] [3 2]} (set (edges g6)) + #{[0 1] [1 2] [2 3] [3 4] [4 5] [5 6] [6 7] [7 8] [8 9] [9 0]} (set (edges g7)))))) From 3c7a02eafc458f68c6edc498e61ee7e0334e6064 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Wed, 25 Apr 2018 11:33:52 +0200 Subject: [PATCH 09/28] Add function and test for clustering coefficient So far only the clustering coefficient for a single node can be computed. --- src/loom/alg.cljc | 31 ++++++++++++++++++++++++++++--- test/loom/test/alg.cljc | 15 ++++++++++++++- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/loom/alg.cljc b/src/loom/alg.cljc index b3008b1..f18f484 100644 --- a/src/loom/alg.cljc +++ b/src/loom/alg.cljc @@ -10,9 +10,11 @@ can use these functions." out-degree in-degree weighted? directed? graph digraph transpose] :as graph] [loom.alg-generic :refer [trace-path preds->span]] - #?(:clj [clojure.data.priority-map :as pm] - :cljs [tailrecursion.priority-map :as pm]) - [clojure.set :as clj.set])) + #?(:clj + [clojure.data.priority-map :as pm] + :cljs [tailrecursion.priority-map :as pm]) + [clojure.set :as clj.set] + [clojure.set :as set])) ;;; ;;; Convenience wrappers for loom.alg-generic functions @@ -792,3 +794,26 @@ can use these functions." (edges g1)))))) ;; ;; Todo: MST, coloring, matching, etc etc + +(defn clustering-coefficient + "Computing clustering coefficient for a node in graph g as described + in Watts, Duncan J., and Steven H. Strogatz. “Collective Dynamics of + ‘Small-World’ Networks.” Nature 393, no. 6684 (June 1998): 440–42. + https://doi.org/10.1038/30918." + [g node] + (let [neighbours (successors g node) + potential-connections (/ (* (count neighbours) (dec (count neighbours))) 2)] + (if (> potential-connections 1) + ;; how many connections between the neighbours of node + ;; are there? + (let [neighbour-overlaps (for [n neighbours] + (let [potential (clj.set/difference neighbours #{n}) + actual (successors g n) + overlap (clj.set/intersection potential actual)] + (count overlap))) + sum-overlaps (reduce + 0 neighbour-overlaps)] + (/ sum-overlaps potential-connections 2)) + ;; if there are not at least 2 neighbours, + ;; clustering-coefficient is set to zero + 0))) + diff --git a/test/loom/test/alg.cljc b/test/loom/test/alg.cljc index 25d9565..1782986 100644 --- a/test/loom/test/alg.cljc +++ b/test/loom/test/alg.cljc @@ -13,7 +13,8 @@ coloring? greedy-coloring prim-mst-edges prim-mst-edges prim-mst astar-path astar-dist degeneracy-ordering maximal-cliques - subgraph? eql? isomorphism?]] + subgraph? eql? isomorphism? + clustering-coefficient]] [loom.derived :refer [mapped-by]] clojure.walk #?@(:clj [[clojure.test :refer :all]] @@ -627,3 +628,15 @@ false (isomorphism? g7 (mapped-by inc g7) dec) false (isomorphism? (digraph) (graph) identity) false(isomorphism? (digraph [1 2]) (graph [1 2]) identity))) + +(deftest clustering-coefficient-test + (let [g1 (graph {0 #{}, 1 #{}, 2 #{}, 3 #{}}) ; empty graph + g2 (graph {0 #{1 2 3}, 1 #{0 2 3}, 2 #{0 1 3}, 3 #{0 1 2}}) ; fully connected + g3 (graph {0 #{1 4}, 1 #{2 0}, 2 #{3 1}, 3 #{4 2}, 4 #{0 3}}) ; circle + g4 (graph {0 #{1 2 3}, 1 #{0 3}, 2 #{0}, 3 #{0 1}})] + (testing "Clustering coefficient for single nodes" + (are [expected got] (= expected got) + (clustering-coefficient g1 0) 0 + (clustering-coefficient g2 1) 1 + (clustering-coefficient g3 0) 0 + (clustering-coefficient g4 0) (/ 1 3))))) From a41c002e3fb9d046714d406d3f1839bca3aff7dc Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Wed, 25 Apr 2018 14:58:24 +0200 Subject: [PATCH 10/28] Add function and test for global clustering coefficient As described in Watts and Strogatz (1998). This is really the average over all clustering coefficients. --- src/loom/alg.cljc | 46 +++++++++++++++++++++++------------------ test/loom/test/alg.cljc | 15 +++++++++++--- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/loom/alg.cljc b/src/loom/alg.cljc index f18f484..8f25f19 100644 --- a/src/loom/alg.cljc +++ b/src/loom/alg.cljc @@ -796,24 +796,30 @@ can use these functions." ;; ;; Todo: MST, coloring, matching, etc etc (defn clustering-coefficient - "Computing clustering coefficient for a node in graph g as described - in Watts, Duncan J., and Steven H. Strogatz. “Collective Dynamics of - ‘Small-World’ Networks.” Nature 393, no. 6684 (June 1998): 440–42. - https://doi.org/10.1038/30918." - [g node] - (let [neighbours (successors g node) - potential-connections (/ (* (count neighbours) (dec (count neighbours))) 2)] - (if (> potential-connections 1) - ;; how many connections between the neighbours of node - ;; are there? - (let [neighbour-overlaps (for [n neighbours] - (let [potential (clj.set/difference neighbours #{n}) - actual (successors g n) - overlap (clj.set/intersection potential actual)] - (count overlap))) - sum-overlaps (reduce + 0 neighbour-overlaps)] - (/ sum-overlaps potential-connections 2)) - ;; if there are not at least 2 neighbours, - ;; clustering-coefficient is set to zero - 0))) + "Computes clustering coefficient as described in Watts and Strogatz (1998). + When g and node are supplied as arguments, returns the local clustering + coefficient for node in g. When only g is supplied as an argument, returns + the average over all clustering coefficients. For details see + Watts, Duncan J., and Steven H. Strogatz. “Collective Dynamics of ‘Small-World’ + Networks.” Nature 393, no. 6684 (June 1998): 440–42. https://doi.org/10.1038/30918." + ([g node] + (let [neighbours (successors g node) + potential-connections (/ (* (count neighbours) (dec (count neighbours))) 2)] + (if (> (count neighbours) 1) + ;; how many connections between the neighbours + ;; of node are there? + (let [neighbour-overlaps (for [n neighbours] + (let [potential (clj.set/difference neighbours #{n}) + actual (successors g n) + overlap (clj.set/intersection potential actual)] + (count overlap))) + sum-overlaps (reduce + 0 neighbour-overlaps)] + (/ sum-overlaps potential-connections 2)) + ;; if there are not at least 2 neighbours, + ;; clustering-coefficient is set to zero + 0))) + ([g] + (let [nodeset (nodes g) + sum-coeffs (reduce #(+ %1 (clustering-coefficient g %2)) 0 nodeset)] + (/ sum-coeffs (count nodeset))))) diff --git a/test/loom/test/alg.cljc b/test/loom/test/alg.cljc index 1782986..56a8bdd 100644 --- a/test/loom/test/alg.cljc +++ b/test/loom/test/alg.cljc @@ -633,10 +633,19 @@ (let [g1 (graph {0 #{}, 1 #{}, 2 #{}, 3 #{}}) ; empty graph g2 (graph {0 #{1 2 3}, 1 #{0 2 3}, 2 #{0 1 3}, 3 #{0 1 2}}) ; fully connected g3 (graph {0 #{1 4}, 1 #{2 0}, 2 #{3 1}, 3 #{4 2}, 4 #{0 3}}) ; circle - g4 (graph {0 #{1 2 3}, 1 #{0 3}, 2 #{0}, 3 #{0 1}})] - (testing "Clustering coefficient for single nodes" + g4 (graph {0 #{1 2 3}, 1 #{0 3}, 2 #{0}, 3 #{0 1}}) + g5 (graph [0 1] [0 2] [0 3] [1 3])] + (testing "local clustering coefficients" (are [expected got] (= expected got) (clustering-coefficient g1 0) 0 (clustering-coefficient g2 1) 1 (clustering-coefficient g3 0) 0 - (clustering-coefficient g4 0) (/ 1 3))))) + (clustering-coefficient g4 0) (/ 1 3) + (clustering-coefficient g5 0) (/ 1 3))) + (testing "global clustering coefficients" + (are [expected got] (= expected got) + (clustering-coefficient g1) 0 + (clustering-coefficient g2) 1 + (clustering-coefficient g3) 0 + (clustering-coefficient g4) (/ 7 12) + (clustering-coefficient g4) (clustering-coefficient g5))))) From f9a9a08dee48ab1383a53a1bee585c4dddcdde93 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Wed, 25 Apr 2018 15:27:34 +0200 Subject: [PATCH 11/28] Add tests for Newman-Watts Graph --- test/loom/test/gen.clj | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/loom/test/gen.clj b/test/loom/test/gen.clj index caa48a1..60d4c2d 100644 --- a/test/loom/test/gen.clj +++ b/test/loom/test/gen.clj @@ -1,6 +1,7 @@ (ns loom.test.gen (:require [clojure.test :refer (deftest testing is are)] [loom.graph :refer (graph digraph weighted-graph weighted-digraph graph? nodes edges)] + [loom.alg :refer (clustering-coefficient)] [loom.gen :refer (gen-circle gen-newman-watts)])) (deftest build-circle-test @@ -43,3 +44,25 @@ #{[0 1] [1 2] [2 3] [3 4] [4 5] [5 6] [6 7] [7 8] [8 9] [9 0] [1 0] [2 1] [3 2]} (set (edges g6)) #{[0 1] [1 2] [2 3] [3 4] [4 5] [5 6] [6 7] [7 8] [8 9] [9 0]} (set (edges g7)))))) + +(deftest build-newman-watts-test + (let [g1 (gen-newman-watts (graph) 20 2 0.2) + g2 (gen-newman-watts (graph) 100 5 0.3)] + (testing "Construction, Nodes, Edges, Clustering coefficient for g1" + (is loom.graph/graph? g1) + (is (= 20 (count (nodes g1)))) + (is (and + (>= (count (edges g1)) (* 2 20 2)) + (<= (count (edges g1)) (+ (* 2 20 2) (* 20 2 0.35))))) + (is (and + (<= (- (/ 3 4) 0.5) (clustering-coefficient g1)) + (>= (+ (/ 3 4) 0.5) (clustering-coefficient g1))))) + (testing "Construction, Nodes, Edges, Clustering coefficient for g2" + (is loom.graph/graph? g2) + (is (= 100 (count (nodes g2)))) + (is (and + (>= (count (edges g2)) (* 2 100 5)) + (<= (count (edges g2)) (+ (* 2 100 5) (* 100 5 0.45))))) + (is (and + (<= (- (/ 3 4) 0.5) (clustering-coefficient g2)) + (>= (+ (/ 3 4) 0.5) (clustering-coefficient g2))))))) From e5a0a1c6f42bb03462379bffb78b010a995ac9cb Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Mon, 30 Apr 2018 11:09:00 +0200 Subject: [PATCH 12/28] Add test for special case in newman-watts-graph --- test/loom/test/gen.clj | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/loom/test/gen.clj b/test/loom/test/gen.clj index 60d4c2d..063609d 100644 --- a/test/loom/test/gen.clj +++ b/test/loom/test/gen.clj @@ -47,7 +47,8 @@ (deftest build-newman-watts-test (let [g1 (gen-newman-watts (graph) 20 2 0.2) - g2 (gen-newman-watts (graph) 100 5 0.3)] + g2 (gen-newman-watts (graph) 100 5 0.3) + g3 (gen-newman-watts (graph) 100 6 0)] (testing "Construction, Nodes, Edges, Clustering coefficient for g1" (is loom.graph/graph? g1) (is (= 20 (count (nodes g1)))) @@ -65,4 +66,11 @@ (<= (count (edges g2)) (+ (* 2 100 5) (* 100 5 0.45))))) (is (and (<= (- (/ 3 4) 0.5) (clustering-coefficient g2)) - (>= (+ (/ 3 4) 0.5) (clustering-coefficient g2))))))) + (>= (+ (/ 3 4) 0.5) (clustering-coefficient g2))))) + (testing "Construction, Nodes, Edges, Clustering coefficient for g3" + (is loom.graph/graph? g3) + (is (= 100 (count (nodes g2)))) + (is (= (count (edges g3)) (* 2 100 6))) + (is (and + (<= (- (/ 3 4) 0.2) (clustering-coefficient g2)) + (>= (+ (/ 3 4) 0.2) (clustering-coefficient g2))))))) From b8003bd07ab5d8b24f3b63faa12b1d6e37fd669f Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Tue, 12 Jun 2018 09:39:35 +0200 Subject: [PATCH 13/28] ignore .idea/* --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 433ea98..8d6a179 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ classes /.lein-* .nrepl-port out + +*iml +.idea/* From b03e89f280cdb6b5f435b21d6d47c7c12f5d3b0e Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Mon, 9 Jul 2018 13:17:21 +0200 Subject: [PATCH 14/28] Implement initial-barabasi-albert --- src/loom/gen.clj | 31 ++++++++++++++++++++++++++++++- test/loom/test/gen.clj | 7 ++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/loom/gen.clj b/src/loom/gen.clj index 7fa6231..03e8534 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -1,7 +1,7 @@ (ns ^{:doc "Graph-generating functions" :author "Justin Kramer"} loom.gen - (:require [loom.graph :refer [weighted? directed? add-nodes* add-edges*]])) + (:require [loom.graph :refer [weighted? directed? add-nodes* add-edges* nodes]])) (defn gen-rand "Adds num-nodes nodes and approximately num-edges edges to graph g. Nodes @@ -88,3 +88,32 @@ ([g num-nodes out-degree phi] (gen-newman-watts g num-nodes out-degree phi (System/nanoTime)))) + +(defn ^:private initial-barabasi-albert + "In the Barabasi-Albert model, the first new node that is + added to the graph has to be treated specially. It will have + exactly num-edges connections, and every node in the graph + will attach to it with equal probability." + ([g num-edges] + (initial-barabasi-albert g num-edges (System/nanoTime))) + ([g num-edges seed] + ;; there can't be more edges that nodes in the graph + {:pre [(<= num-edges (count (nodes g)))]} + (let [num-nodes (count (nodes g)) + new-node (inc num-nodes) + rnd (java.util.Random. seed) + draw-connecting-nodes (fn [g] + (loop [partners #{}] + (if (= (count partners) num-edges) + (vec partners) + (recur (conj partners (.nextInt rnd num-nodes)))))) + new-edges (map vector (repeat num-edges new-node) (draw-connecting-nodes g)) + ] + (add-edges* g new-edges)))) + +(defn gen-barabasi-albert + "Generate a preferential attachment graph as described in Barabasi and Albert + (1999)." + [g num-nodes num-edges] + (initial-barabasi-albert g num-edges (System/nanoTime))) + diff --git a/test/loom/test/gen.clj b/test/loom/test/gen.clj index 063609d..a87d45e 100644 --- a/test/loom/test/gen.clj +++ b/test/loom/test/gen.clj @@ -2,7 +2,7 @@ (:require [clojure.test :refer (deftest testing is are)] [loom.graph :refer (graph digraph weighted-graph weighted-digraph graph? nodes edges)] [loom.alg :refer (clustering-coefficient)] - [loom.gen :refer (gen-circle gen-newman-watts)])) + [loom.gen :refer (gen-circle gen-newman-watts gen-barabasi-albert)])) (deftest build-circle-test (let [g1 (gen-circle (graph) 5 1) @@ -74,3 +74,8 @@ (is (and (<= (- (/ 3 4) 0.2) (clustering-coefficient g2)) (>= (+ (/ 3 4) 0.2) (clustering-coefficient g2))))))) + +(deftest initial-barabasi-albert + (let [g (graph 0 1 2 3 4 5 6 7)] + (testing + (is (= 12 (count (edges (gen-barabasi-albert g 3 6)))))))) \ No newline at end of file From e7965a17eebf44004c20a66c9f9790ce6def5dec Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Thu, 12 Jul 2018 14:02:06 +0200 Subject: [PATCH 15/28] Add num-initial as argument to inital-barabasi-albert --- src/loom/gen.clj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/loom/gen.clj b/src/loom/gen.clj index 03e8534..11e42cc 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -94,11 +94,11 @@ added to the graph has to be treated specially. It will have exactly num-edges connections, and every node in the graph will attach to it with equal probability." - ([g num-edges] - (initial-barabasi-albert g num-edges (System/nanoTime))) - ([g num-edges seed] + ([g num-initial num-edges] + (initial-barabasi-albert g num-initial num-edges (System/nanoTime))) + ([g num-initial num-edges seed] ;; there can't be more edges that nodes in the graph - {:pre [(<= num-edges (count (nodes g)))]} + {:pre [(<= num-edges num-initial)]} (let [num-nodes (count (nodes g)) new-node (inc num-nodes) rnd (java.util.Random. seed) From 55a148fee66299e8c8609b041b3568366455a595 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Thu, 12 Jul 2018 14:06:03 +0200 Subject: [PATCH 16/28] Pass java.util.Random to initial-barabasi-albert instead of seed Because of this, the function is not variadic anymore. --- src/loom/gen.clj | 62 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/src/loom/gen.clj b/src/loom/gen.clj index 11e42cc..0a7a5b8 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -94,26 +94,48 @@ added to the graph has to be treated specially. It will have exactly num-edges connections, and every node in the graph will attach to it with equal probability." - ([g num-initial num-edges] - (initial-barabasi-albert g num-initial num-edges (System/nanoTime))) - ([g num-initial num-edges seed] - ;; there can't be more edges that nodes in the graph - {:pre [(<= num-edges num-initial)]} - (let [num-nodes (count (nodes g)) - new-node (inc num-nodes) - rnd (java.util.Random. seed) - draw-connecting-nodes (fn [g] - (loop [partners #{}] - (if (= (count partners) num-edges) - (vec partners) - (recur (conj partners (.nextInt rnd num-nodes)))))) - new-edges (map vector (repeat num-edges new-node) (draw-connecting-nodes g)) - ] - (add-edges* g new-edges)))) + [g num-initial num-edges rnd] + ;; there can't be more edges that nodes in the graph + {:pre [(<= num-edges num-initial)]} + (let [num-nodes (count (nodes g)) + new-node (inc num-nodes) + draw-connecting-nodes (fn [g] + (loop [partners #{}] + (if (= (count partners) num-edges) + (vec partners) + (recur (conj partners (.nextInt rnd num-initial)))))) + new-edges (map vector (repeat num-edges new-node) (draw-connecting-nodes g))] + (add-edges* g new-edges))) + + +;; collect all degrees in a list +;(map #(count (loom.graph/successors g0 %)) (nodes g0)) +;; sum over all degrees +;(reduce #(+ %1 (count (loom.graph/successors g0 %2))) 0 (nodes g0)) + +;(defn connect? +; "Should old be connected to a new node?" +; [g old degree-sum rnd] +; (let [degree-old (loom.graph/out-degree g old) +; p (/ degree-old degree-sum)] +; (<= p (.nextDouble rnd)))) +(defn connect-to? + "Higher-order function to decide wether node should be connected to. + pred-fn must return true or false." + [g node pred-fn] + (pred-fn g node)) + (defn gen-barabasi-albert - "Generate a preferential attachment graph as described in Barabasi and Albert - (1999)." - [g num-nodes num-edges] - (initial-barabasi-albert g num-edges (System/nanoTime))) + "Generate a preferential attachment graph as described in Barabasi + and Albert (1999)." + [g num-initial num-nodes num-edges seed] + (let [rnd (java.util.Random. seed) + g-0 (initial-barabasi-albert g num-initial num-edges seed) + connect-pred (fn [g node degree-sum rnd] + (let [d-node (count (loom.graph/successors g node)) + degree-sum (reduce #(+ %1 (count (loom.graph/successors g-0 %2))) 0 (nodes g-0))] + (<= (/ d-node degree-sum) (.nextDouble rnd))))] + g-0) + ) From dd12416d7c76c835627210342b154bac4ddefff2 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Thu, 12 Jul 2018 14:09:30 +0200 Subject: [PATCH 17/28] Fix value for new-node in initial-barabasi-albert --- src/loom/gen.clj | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/loom/gen.clj b/src/loom/gen.clj index 0a7a5b8..eb1aa6f 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -97,8 +97,7 @@ [g num-initial num-edges rnd] ;; there can't be more edges that nodes in the graph {:pre [(<= num-edges num-initial)]} - (let [num-nodes (count (nodes g)) - new-node (inc num-nodes) + (let [new-node (inc num-initial) draw-connecting-nodes (fn [g] (loop [partners #{}] (if (= (count partners) num-edges) @@ -131,7 +130,7 @@ and Albert (1999)." [g num-initial num-nodes num-edges seed] (let [rnd (java.util.Random. seed) - g-0 (initial-barabasi-albert g num-initial num-edges seed) + g-0 (initial-barabasi-albert g num-initial num-edges rnd) connect-pred (fn [g node degree-sum rnd] (let [d-node (count (loom.graph/successors g node)) degree-sum (reduce #(+ %1 (count (loom.graph/successors g-0 %2))) 0 (nodes g-0))] From d2713a95e4b794de8c4f011d979da9b95ef66237 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Thu, 12 Jul 2018 14:11:05 +0200 Subject: [PATCH 18/28] Change order of arguments for gen-barabasi-albert --- src/loom/gen.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loom/gen.clj b/src/loom/gen.clj index eb1aa6f..21d7bc4 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -128,7 +128,7 @@ (defn gen-barabasi-albert "Generate a preferential attachment graph as described in Barabasi and Albert (1999)." - [g num-initial num-nodes num-edges seed] + [g num-nodes num-initial num-edges seed] (let [rnd (java.util.Random. seed) g-0 (initial-barabasi-albert g num-initial num-edges rnd) connect-pred (fn [g node degree-sum rnd] From 9e0606b51beb387a1e29c635c0c71ee578ad282a Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Thu, 12 Jul 2018 14:12:15 +0200 Subject: [PATCH 19/28] Fix test for gen-barabasi-albert --- test/loom/test/gen.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/loom/test/gen.clj b/test/loom/test/gen.clj index a87d45e..44478f7 100644 --- a/test/loom/test/gen.clj +++ b/test/loom/test/gen.clj @@ -76,6 +76,6 @@ (>= (+ (/ 3 4) 0.2) (clustering-coefficient g2))))))) (deftest initial-barabasi-albert - (let [g (graph 0 1 2 3 4 5 6 7)] + (let [g (graph )] (testing - (is (= 12 (count (edges (gen-barabasi-albert g 3 6)))))))) \ No newline at end of file + (is (= 6 (count (edges (gen-barabasi-albert g 20 6 3 (System/nanoTime))))))))) \ No newline at end of file From c9dfd79064bcbb3031c4594073c920902414ec7f Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Wed, 18 Jul 2018 15:12:45 +0200 Subject: [PATCH 20/28] Implement function to generate Barabasi-Albert-Graph This is the preferential attachment graph. Remove to old initializing function and start with two connected nodes, to which a new one will attach with equal probability. First test checks for the number of nodes created and passes. --- src/loom/gen.clj | 74 +++++++++++++++++------------------------- test/loom/test/gen.clj | 5 +-- 2 files changed, 32 insertions(+), 47 deletions(-) diff --git a/src/loom/gen.clj b/src/loom/gen.clj index 21d7bc4..d6f2e25 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -88,53 +88,37 @@ ([g num-nodes out-degree phi] (gen-newman-watts g num-nodes out-degree phi (System/nanoTime)))) - -(defn ^:private initial-barabasi-albert - "In the Barabasi-Albert model, the first new node that is - added to the graph has to be treated specially. It will have - exactly num-edges connections, and every node in the graph - will attach to it with equal probability." - [g num-initial num-edges rnd] - ;; there can't be more edges that nodes in the graph - {:pre [(<= num-edges num-initial)]} - (let [new-node (inc num-initial) - draw-connecting-nodes (fn [g] - (loop [partners #{}] - (if (= (count partners) num-edges) - (vec partners) - (recur (conj partners (.nextInt rnd num-initial)))))) - new-edges (map vector (repeat num-edges new-node) (draw-connecting-nodes g))] - (add-edges* g new-edges))) - - -;; collect all degrees in a list -;(map #(count (loom.graph/successors g0 %)) (nodes g0)) -;; sum over all degrees -;(reduce #(+ %1 (count (loom.graph/successors g0 %2))) 0 (nodes g0)) - -;(defn connect? -; "Should old be connected to a new node?" -; [g old degree-sum rnd] -; (let [degree-old (loom.graph/out-degree g old) -; p (/ degree-old degree-sum)] -; (<= p (.nextDouble rnd)))) -(defn connect-to? - "Higher-order function to decide wether node should be connected to. - pred-fn must return true or false." - [g node pred-fn] - (pred-fn g node)) - - (defn gen-barabasi-albert "Generate a preferential attachment graph as described in Barabasi and Albert (1999)." - [g num-nodes num-initial num-edges seed] + [g num-nodes num-edges seed] (let [rnd (java.util.Random. seed) - g-0 (initial-barabasi-albert g num-initial num-edges rnd) - connect-pred (fn [g node degree-sum rnd] - (let [d-node (count (loom.graph/successors g node)) - degree-sum (reduce #(+ %1 (count (loom.graph/successors g-0 %2))) 0 (nodes g-0))] - (<= (/ d-node degree-sum) (.nextDouble rnd))))] - g-0) - ) + ;; initialize graph with two connected nodes + ;; with equal probability, a new node will attach to + ;; either one + g-0 (loom.graph/add-edges g [0 1]) + ;; predicate for deciding wether a node + ;; should be connected to a new node + connect? (fn [g node] + (let [degree-node (count (loom.graph/successors g node)) + degree-sum (reduce #(+ %1 (count (loom.graph/successors g %2))) 0 (nodes g))] + (<= (/ degree-node degree-sum) (.nextDouble rnd)))) + ;; go through all nodes in g and decide whether + ;; they connect to new + new-edges (fn [g new] + (for [n (nodes g) + :when (connect? g n)] + [new n])) + ;; compute num-edges edges for new in graph g + get-new-edges-and-connect (fn [g new num-edges] + (as-> g v + (new-edges v new) + (take num-edges v) + (filter #(= 2 (count %)) v) + (apply loom.graph/add-edges g v))) + ;; two nodes are already in the initialized graph + ;; the remaining notes will be added + remaining-nodes (range 2 num-nodes) + ] + (reduce #(get-new-edges-and-connect %1 %2 num-edges) g-0 remaining-nodes))) diff --git a/test/loom/test/gen.clj b/test/loom/test/gen.clj index 44478f7..5d42e2b 100644 --- a/test/loom/test/gen.clj +++ b/test/loom/test/gen.clj @@ -75,7 +75,8 @@ (<= (- (/ 3 4) 0.2) (clustering-coefficient g2)) (>= (+ (/ 3 4) 0.2) (clustering-coefficient g2))))))) -(deftest initial-barabasi-albert +(deftest gen-barabasi-albert-test (let [g (graph )] (testing - (is (= 6 (count (edges (gen-barabasi-albert g 20 6 3 (System/nanoTime))))))))) \ No newline at end of file + (is (= 200 (count (nodes (gen-barabasi-albert g 200 3 123))))) + ))) \ No newline at end of file From b2e18d3f4b40615924b7ecf2fd4ffcd67479399b Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Thu, 19 Jul 2018 14:19:35 +0200 Subject: [PATCH 21/28] Make gen-barabasi-albert a variadic function Either explicitly pass a random seed when creating the graph, or use System/nanoTime. --- src/loom/gen.clj | 62 +++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/loom/gen.clj b/src/loom/gen.clj index d6f2e25..cfa9abb 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -91,34 +91,36 @@ (defn gen-barabasi-albert "Generate a preferential attachment graph as described in Barabasi and Albert (1999)." - [g num-nodes num-edges seed] - (let [rnd (java.util.Random. seed) - ;; initialize graph with two connected nodes - ;; with equal probability, a new node will attach to - ;; either one - g-0 (loom.graph/add-edges g [0 1]) - ;; predicate for deciding wether a node - ;; should be connected to a new node - connect? (fn [g node] - (let [degree-node (count (loom.graph/successors g node)) - degree-sum (reduce #(+ %1 (count (loom.graph/successors g %2))) 0 (nodes g))] - (<= (/ degree-node degree-sum) (.nextDouble rnd)))) - ;; go through all nodes in g and decide whether - ;; they connect to new - new-edges (fn [g new] - (for [n (nodes g) - :when (connect? g n)] - [new n])) - ;; compute num-edges edges for new in graph g - get-new-edges-and-connect (fn [g new num-edges] - (as-> g v - (new-edges v new) - (take num-edges v) - (filter #(= 2 (count %)) v) - (apply loom.graph/add-edges g v))) - ;; two nodes are already in the initialized graph - ;; the remaining notes will be added - remaining-nodes (range 2 num-nodes) - ] + ([g num-nodes num-edges seed] + (let [rnd (java.util.Random. seed) + ;; initialize graph with two connected nodes + ;; with equal probability, a new node will attach to + ;; either one + g-0 (loom.graph/add-edges g [0 1]) + ;; predicate for deciding wether a node + ;; should be connected to a new node + connect? (fn [g node] + (let [degree-node (count (loom.graph/successors g node)) + degree-sum (reduce #(+ %1 (count (loom.graph/successors g %2))) 0 (nodes g))] + (<= (/ degree-node degree-sum) (.nextDouble rnd)))) + ;; go through all nodes in g and decide whether + ;; they connect to new + new-edges (fn [g new] + (for [n (nodes g) + :when (connect? g n)] + [new n])) + ;; compute num-edges edges for new in graph g + get-new-edges-and-connect (fn [g new num-edges] + (as-> g v + (new-edges v new) + (take num-edges v) + (filter #(= 2 (count %)) v) + (apply loom.graph/add-edges g v))) + ;; two nodes are already in the initialized graph + ;; the remaining notes will be added + remaining-nodes (range 2 num-nodes) + ] - (reduce #(get-new-edges-and-connect %1 %2 num-edges) g-0 remaining-nodes))) + (reduce #(get-new-edges-and-connect %1 %2 num-edges) g-0 remaining-nodes))) + ([g num-nodes num-edges] + (gen-barabasi-albert g num-nodes num-edges (System/nanoTime)))) From 93085c7d7bb38bf48041e4887f5e13dff8e9fef2 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Thu, 19 Jul 2018 14:26:22 +0200 Subject: [PATCH 22/28] Add tests for gen-barabasi-albert Test if function actually constructs a loom graph and for number of nodes and edges. --- test/loom/test/gen.clj | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/loom/test/gen.clj b/test/loom/test/gen.clj index 5d42e2b..6c27adf 100644 --- a/test/loom/test/gen.clj +++ b/test/loom/test/gen.clj @@ -76,7 +76,9 @@ (>= (+ (/ 3 4) 0.2) (clustering-coefficient g2))))))) (deftest gen-barabasi-albert-test - (let [g (graph )] - (testing + (let [g (graph)] + (testing "Construction, Nodes, Edges" + (is loom.graph/graph? (gen-barabasi-albert g 42 5)) (is (= 200 (count (nodes (gen-barabasi-albert g 200 3 123))))) + (is (= (* 2 (+ 1 (* 198 2))) (count (edges (gen-barabasi-albert g 200 2))))) ))) \ No newline at end of file From 25abdf77caa69823bf7af96353b97ecd7b6010f2 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Thu, 6 Sep 2018 18:56:17 +0200 Subject: [PATCH 23/28] Clean up a bit --- test/loom/test/gen.clj | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/test/loom/test/gen.clj b/test/loom/test/gen.clj index 6c27adf..15146d1 100644 --- a/test/loom/test/gen.clj +++ b/test/loom/test/gen.clj @@ -11,17 +11,10 @@ g4 (gen-circle (weighted-graph {0 {1 42 2 42} 1 {2 42 3 42} 2 {3 42 4 42}}) 10 1) g5 (gen-circle (weighted-graph) 10 1) g6 (gen-circle (weighted-digraph [0 1 42] [1 2 42] [2 3 42] [1 0 43] [2 1 43] [3 2 43]) 10 1) - g7 (gen-circle (weighted-digraph) 10 1) - ] + g7 (gen-circle (weighted-digraph) 10 1)] (testing "Generating circle-graphs from the different graph types" (are [graphs] (graph? graphs) - g1 - g2 - g3 - g4 - g5 - g6 - g7)) + g1 g2 g3 g4 g5 g6 g7)) (testing "Nodes and Edges" (are [expected got] (= expected got) (into #{} (range 5)) (nodes g1) @@ -80,5 +73,4 @@ (testing "Construction, Nodes, Edges" (is loom.graph/graph? (gen-barabasi-albert g 42 5)) (is (= 200 (count (nodes (gen-barabasi-albert g 200 3 123))))) - (is (= (* 2 (+ 1 (* 198 2))) (count (edges (gen-barabasi-albert g 200 2))))) - ))) \ No newline at end of file + (is (= (* 2 (+ 1 (* 198 2))) (count (edges (gen-barabasi-albert g 200 2)))))))) \ No newline at end of file From f8d617d8f007b587edc8b857cb1538978419e2e8 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Thu, 6 Sep 2018 22:18:33 +0200 Subject: [PATCH 24/28] Fix tests for Barabasi-Albert Graphs Sometimes Node or Edge count are lower than expected. This is because the construction of the graph involves probabilistic decisions. Because of this, test if actual number is bigger than some percentage of the expected count. --- test/loom/test/gen.clj | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/test/loom/test/gen.clj b/test/loom/test/gen.clj index 15146d1..4fb1873 100644 --- a/test/loom/test/gen.clj +++ b/test/loom/test/gen.clj @@ -69,8 +69,26 @@ (>= (+ (/ 3 4) 0.2) (clustering-coefficient g2))))))) (deftest gen-barabasi-albert-test - (let [g (graph)] - (testing "Construction, Nodes, Edges" - (is loom.graph/graph? (gen-barabasi-albert g 42 5)) - (is (= 200 (count (nodes (gen-barabasi-albert g 200 3 123))))) - (is (= (* 2 (+ 1 (* 198 2))) (count (edges (gen-barabasi-albert g 200 2)))))))) \ No newline at end of file + (let [g (graph) + percentage (fn [num percent] + (* (/ percent 100) num))] + (testing "Construction" + (are [graphs] loom.graph/graph? + (gen-barabasi-albert g 10 1) + (gen-barabasi-albert g 20 2) + (gen-barabasi-albert g 42 5))) + (testing "Node Count" + ;; Because creating the graph involves probabilistic decisions + ;; the actual number of nodes may be a bit lower than the expected count + (are [expected-count degree] (< (percentage expected-count 95) (count (nodes (gen-barabasi-albert g expected-count degree)))) + 200 3 + 100 1 + 567 7 + 980 20)) + (testing "Edge Count" + ;; same problem as with node count + (are [expected-count degree] (< (percentage expected-count 95) (count (edges (gen-barabasi-albert g expected-count degree)))) + 200 3 + 100 1 + 567 7 + 980 20)))) \ No newline at end of file From 1d4b1c7674e548079fe07527339a2be62bb81c9b Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Thu, 6 Sep 2018 22:44:56 +0200 Subject: [PATCH 25/28] Fix test for number of edges in Barabasi-Albert Graphs --- test/loom/test/gen.clj | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/loom/test/gen.clj b/test/loom/test/gen.clj index 4fb1873..423de5e 100644 --- a/test/loom/test/gen.clj +++ b/test/loom/test/gen.clj @@ -71,7 +71,9 @@ (deftest gen-barabasi-albert-test (let [g (graph) percentage (fn [num percent] - (* (/ percent 100) num))] + (* (/ percent 100) num)) + expected-edge-count (fn [num-nodes] + (+ 2 (* 2 (dec num-nodes))))] (testing "Construction" (are [graphs] loom.graph/graph? (gen-barabasi-albert g 10 1) @@ -80,14 +82,14 @@ (testing "Node Count" ;; Because creating the graph involves probabilistic decisions ;; the actual number of nodes may be a bit lower than the expected count - (are [expected-count degree] (< (percentage expected-count 95) (count (nodes (gen-barabasi-albert g expected-count degree)))) + (are [num-nodes degree] (< (percentage num-nodes 95) (count (nodes (gen-barabasi-albert g num-nodes degree)))) 200 3 100 1 567 7 980 20)) (testing "Edge Count" ;; same problem as with node count - (are [expected-count degree] (< (percentage expected-count 95) (count (edges (gen-barabasi-albert g expected-count degree)))) + (are [num-nodes degree] (< (percentage (expected-edge-count num-nodes) 95) (count (edges (gen-barabasi-albert g num-nodes degree)))) 200 3 100 1 567 7 From fb926669214fe8478cbe795a3211ea30d57ff375 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Wed, 12 Sep 2018 17:33:09 +0200 Subject: [PATCH 26/28] Remove gen-barabasi-albert and gen-barabasi-albert-test --- src/loom/gen.clj | 37 ------------------------------------- test/loom/test/gen.clj | 27 --------------------------- 2 files changed, 64 deletions(-) diff --git a/src/loom/gen.clj b/src/loom/gen.clj index cfa9abb..70eb8a3 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -87,40 +87,3 @@ (add-shortcuts phi seed))) ([g num-nodes out-degree phi] (gen-newman-watts g num-nodes out-degree phi (System/nanoTime)))) - -(defn gen-barabasi-albert - "Generate a preferential attachment graph as described in Barabasi - and Albert (1999)." - ([g num-nodes num-edges seed] - (let [rnd (java.util.Random. seed) - ;; initialize graph with two connected nodes - ;; with equal probability, a new node will attach to - ;; either one - g-0 (loom.graph/add-edges g [0 1]) - ;; predicate for deciding wether a node - ;; should be connected to a new node - connect? (fn [g node] - (let [degree-node (count (loom.graph/successors g node)) - degree-sum (reduce #(+ %1 (count (loom.graph/successors g %2))) 0 (nodes g))] - (<= (/ degree-node degree-sum) (.nextDouble rnd)))) - ;; go through all nodes in g and decide whether - ;; they connect to new - new-edges (fn [g new] - (for [n (nodes g) - :when (connect? g n)] - [new n])) - ;; compute num-edges edges for new in graph g - get-new-edges-and-connect (fn [g new num-edges] - (as-> g v - (new-edges v new) - (take num-edges v) - (filter #(= 2 (count %)) v) - (apply loom.graph/add-edges g v))) - ;; two nodes are already in the initialized graph - ;; the remaining notes will be added - remaining-nodes (range 2 num-nodes) - ] - - (reduce #(get-new-edges-and-connect %1 %2 num-edges) g-0 remaining-nodes))) - ([g num-nodes num-edges] - (gen-barabasi-albert g num-nodes num-edges (System/nanoTime)))) diff --git a/test/loom/test/gen.clj b/test/loom/test/gen.clj index 423de5e..4d9a8fe 100644 --- a/test/loom/test/gen.clj +++ b/test/loom/test/gen.clj @@ -67,30 +67,3 @@ (is (and (<= (- (/ 3 4) 0.2) (clustering-coefficient g2)) (>= (+ (/ 3 4) 0.2) (clustering-coefficient g2))))))) - -(deftest gen-barabasi-albert-test - (let [g (graph) - percentage (fn [num percent] - (* (/ percent 100) num)) - expected-edge-count (fn [num-nodes] - (+ 2 (* 2 (dec num-nodes))))] - (testing "Construction" - (are [graphs] loom.graph/graph? - (gen-barabasi-albert g 10 1) - (gen-barabasi-albert g 20 2) - (gen-barabasi-albert g 42 5))) - (testing "Node Count" - ;; Because creating the graph involves probabilistic decisions - ;; the actual number of nodes may be a bit lower than the expected count - (are [num-nodes degree] (< (percentage num-nodes 95) (count (nodes (gen-barabasi-albert g num-nodes degree)))) - 200 3 - 100 1 - 567 7 - 980 20)) - (testing "Edge Count" - ;; same problem as with node count - (are [num-nodes degree] (< (percentage (expected-edge-count num-nodes) 95) (count (edges (gen-barabasi-albert g num-nodes degree)))) - 200 3 - 100 1 - 567 7 - 980 20)))) \ No newline at end of file From 80bcd6dabc99855f9c3548b9fdb958c58978ebd0 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Wed, 12 Sep 2018 17:38:48 +0200 Subject: [PATCH 27/28] Format docstrings --- src/loom/gen.clj | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/loom/gen.clj b/src/loom/gen.clj index 70eb8a3..512e2fc 100644 --- a/src/loom/gen.clj +++ b/src/loom/gen.clj @@ -68,7 +68,8 @@ (add-edges* edges)))) (defn ^:private add-shortcuts - "Computes additional edges for graph g as described in Newman and Watts (1999)." + "Computes additional edges for graph g as described in Newman and + Watts (1999)." ([g phi seed] (let [rnd (java.util.Random. seed) nodes (loom.graph/nodes g) @@ -79,8 +80,8 @@ (add-edges* shortcuts))))) (defn gen-newman-watts - "Generate a graph with small-world properties as described in Newman and Watts - (1999)." + "Generate a graph with small-world properties as described in Newman + and Watts (1999)." ([g num-nodes out-degree phi seed] (-> g (gen-circle num-nodes out-degree) From 868c5ad9121b162ee7becc3a2abcf24fa384aa35 Mon Sep 17 00:00:00 2001 From: hpcjkour Date: Fri, 14 Sep 2018 22:10:33 +0200 Subject: [PATCH 28/28] Remove .iml-File form index --- loom.iml | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 loom.iml diff --git a/loom.iml b/loom.iml deleted file mode 100644 index 12b3e5d..0000000 --- a/loom.iml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file