├── .gitignore
├── README.md
├── example.edges
├── example.features
├── example.similar
├── focusco.bat
├── focusco.bib
├── focusco.log
├── focusco.out.dm
├── focusco.out.weighted.edges
├── focusco_main.m
├── java_src
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ ├── META-INF
│ │ └── MANIFEST.MF
│ │ └── edu
│ │ └── stonybrook
│ │ └── focused
│ │ ├── GraphReweighter.java
│ │ ├── Vertex.java
│ │ ├── community
│ │ ├── BookkeepingWeightedGraph.java
│ │ ├── GreedyLocalCommunityBuilder.java
│ │ ├── ICommunity.java
│ │ ├── LocalCommunityBuilder.java
│ │ ├── Outlier.java
│ │ ├── PrecomputedCommunity.java
│ │ ├── UnweightedCommunity.java
│ │ ├── WeightedCommunity.java
│ │ └── WeightedMeansCommunity.java
│ │ ├── io
│ │ ├── ascii
│ │ │ ├── Clustering.java
│ │ │ ├── Outliers.java
│ │ │ └── WeightedEdgeList.java
│ │ └── graphml
│ │ │ ├── AttributeGetter.java
│ │ │ ├── AttributeHandler.java
│ │ │ ├── AttributeProvider.java
│ │ │ ├── AttributeSetter.java
│ │ │ ├── AttributeType.java
│ │ │ ├── CommunityOutlierGraphMLExporter.java
│ │ │ ├── ContinousNumericIDProviders.java
│ │ │ └── GraphMLExporter.java
│ │ └── main
│ │ ├── CommunityClusterer.java
│ │ ├── CommunityHolder.java
│ │ └── FocuscoOptions.java
│ └── test
│ └── java
│ └── edu
│ └── stonybrook
│ └── focused
│ └── tests
│ ├── BookkeepingGraphTests.java
│ ├── CommunityTests.java
│ └── GraphIOTests.java
└── matlab_src
├── PGDM
├── D_constraint.m
├── D_constraint_sparse.m
├── D_objective.m
├── D_objective_sparse.m
├── Newton.m
├── Newton_sparse.m
├── Newton_sparse_top_k.m
├── fD.m
├── fD1.m
├── fS1.m
├── grad_projection.m
├── iter_projection_new2.m
├── opt.m
├── opt_sphere.m
├── packcolume.m
├── testPGDM.m
└── unroll.m
├── compute_A_goodness.m
├── distance_metric_learning_manual.m
├── io
└── load_edgelist.m
├── normc.m
├── reweigh.m
├── reweigh_sparse.m
├── savesparse.m
└── savevector.m
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Mobile Tools for Java (J2ME)
4 | .mtj.tmp/
5 |
6 | # Package Files #
7 | *.jar
8 | *.war
9 | *.ear
10 |
11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
12 | hs_err_pid*
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Focused Clustering and Outlier Detection in Large Attributed Graphs
2 |
3 | Bryan Perozzi
4 |
5 | ## Disclaimers
6 |
7 | 1. This code is very "research", and so is probably more useful as an example than a product
8 | 1. Distance Metric Learning based on original code from Eric Xing, [available here]( http://www.cs.cmu.edu/~epxing/papers/Old_papers/code_Metric_online.tar.gz)
9 |
10 | ## Implementation Overview
11 |
12 | There are two programs. The first is a matlab script which learns a distance metric and reweighs the input graph. The second is a java program which extracts communities & outliers from the reweighted graph
13 |
14 | ## Running
15 |
16 | An example batch file `focusco.bat` shows how to use the matlab program from the command line. (it'll run the whole thing soon). It can be run like so:
17 |
18 | `>focusco.bat example.edges example.features example.similar`
19 |
20 | Which will produce `focusco.out.weighted.edges`.
21 |
22 | ## Installation
23 |
24 | ### Requirements
25 | 1. A recent version of Matlab
26 | 2. Java 6+
27 |
28 | ### Setup
29 | The only required step should be to build the java, e.g. with maven:
30 |
31 | 1. `$ cd java_src`
32 | 1. `$ mvn clean install`
33 |
34 |
--------------------------------------------------------------------------------
/example.edges:
--------------------------------------------------------------------------------
1 | 1 2
2 | 1 3
3 | 2 1
4 | 2 3
5 | 3 1
6 | 3 2
7 | 3 4
8 | 4 3
9 | 4 5
10 | 4 6
11 | 5 4
12 | 5 6
13 | 6 4
14 | 6 5
--------------------------------------------------------------------------------
/example.features:
--------------------------------------------------------------------------------
1 | 0 1
2 | 0 1
3 | 0 0
4 | 1 0
5 | 1 0
6 | 1 0
--------------------------------------------------------------------------------
/example.similar:
--------------------------------------------------------------------------------
1 | 1 2
--------------------------------------------------------------------------------
/focusco.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | set CUR_DIR=%CD%
3 |
4 | set edge_file=%1
5 | set feature_file=%2
6 | set similar_file=%3
7 | if "%~4"=="" goto no_arg4
8 | set output_file=%4
9 | goto done_parse
10 | :no_arg4
11 | set output_file=focusco.out
12 | :done_parse
13 | set intermediate_file=%output_file%.weighted.edges
14 |
15 | echo Focused Cluster and Outliers - Distance Metric Learning
16 | echo %CUR_DIR%\distance_metric_learning(arg1,arg2)
17 | echo edge file=%edge_file%
18 | echo feature file=%feature_file%
19 | echo node similarity file=%similar_file%
20 | echo distance metric file=%intermediate_file%
21 | echo output file=%output_file%
22 | start matlab -nosplash -nodesktop -minimize -r focusco_main('%edge_file%','%feature_file%','%similar_file%','file_output','%intermediate_file%') -logfile focusco.log
--------------------------------------------------------------------------------
/focusco.bib:
--------------------------------------------------------------------------------
1 | @inproceedings{2014-kdd-perozzi-focused,
2 | author = {Bryan Perozzi and Leman Akoglu and Patricia Iglesias Sanchez and Emmanuel Muller},
3 | title = {Focused Clustering and Outlier Detection in Large Attributed Graphs},
4 | booktitle = {Proceedings of the 20th ACM SIGKDD International Conference on Knowledge Discovery and Data Mining},
5 | series = {KDD '14},
6 | year = {2014},
7 | location = {New York, NY, USA},
8 | publisher = {ACM},
9 | address = {New York, NY, USA},
10 | month = {August},
11 | }
12 |
--------------------------------------------------------------------------------
/focusco.log:
--------------------------------------------------------------------------------
1 | [Warning: Name is nonexistent or not a directory: io]
2 |
3 | To get started, type one of these: helpwin, helpdesk, or demo.
4 | For product information, visit www.mathworks.com.
5 |
6 |
7 | Student License -- for use in conjunction with courses offered at a
8 | degree-granting institution. Professional and commercial use prohibited.
9 |
10 | FocusCO Distance Metric Learning
11 | -------------------------------------
12 | Gamma: 1.000000
13 | # Dissimilar pairs: 4
14 | Distance Metric Learning Data Type: sparse
15 | # Features to consider (if dml_datatype == sparse): 2
16 | Type of graph reweighting (sparse or dense similarity): sparse
17 | Graph Output File: focusco.out.weighted.edges
18 |
19 | [Warning: Name is nonexistent or not a directory: PGDM]
20 | [> In path at 110
21 | In addpath at 87
22 | In distance_metric_learning_manual at 10
23 | In focusco_main at 49]
24 | Iteration: 1
25 | Objective: 2.825059
26 | Iteration: 2
27 | Objective: 2.871824
28 | Distance metric:
29 |
30 | DM =
31 |
32 | (2,2) 1.2620
33 |
34 |
35 | ans =
36 |
37 | (2,1) 1.0000
38 | (3,1) 0.4709
39 | (1,2) 1.0000
40 | (3,2) 0.4709
41 | (1,3) 0.4709
42 | (2,3) 0.4709
43 | (4,3) 0.4709
44 | (3,4) 0.4709
45 | (5,4) 0.4709
46 | (6,4) 0.4709
47 | (4,5) 0.4709
48 | (6,5) 0.4709
49 | (4,6) 0.4709
50 | (5,6) 0.4709
51 |
52 |
--------------------------------------------------------------------------------
/focusco.out.dm:
--------------------------------------------------------------------------------
1 | 2 1 1.000000
2 | 3 1 1.000000
3 | 1 2 1.000000
4 | 3 2 1.000000
5 | 1 3 1.000000
6 | 2 3 1.000000
7 | 4 3 0.471716
8 | 3 4 0.471716
9 | 5 4 0.471716
10 | 6 4 0.471716
11 | 4 5 0.471716
12 | 6 5 0.471716
13 | 4 6 0.471716
14 | 5 6 0.471716
15 |
--------------------------------------------------------------------------------
/focusco.out.weighted.edges:
--------------------------------------------------------------------------------
1 | 2 1 1.000000
2 | 3 1 0.470942
3 | 1 2 1.000000
4 | 3 2 0.470942
5 | 1 3 0.470942
6 | 2 3 0.470942
7 | 4 3 0.470942
8 | 3 4 0.470942
9 | 5 4 0.470942
10 | 6 4 0.470942
11 | 4 5 0.470942
12 | 6 5 0.470942
13 | 4 6 0.470942
14 | 5 6 0.470942
15 |
--------------------------------------------------------------------------------
/focusco_main.m:
--------------------------------------------------------------------------------
1 | function [WeightedA] = focusco_main(graph_file, data_file, similar_nodes_file, varargin)
2 |
3 | addpath('matlab_src/PGDM')
4 | addpath('matlab_src/io')
5 | addpath('matlab_src')
6 |
7 | % open and load files
8 | X = load(data_file);
9 | A = load_edgelist(graph_file);
10 | similar_pairs = load(similar_nodes_file);
11 |
12 | % pull out some useful variables
13 | num_vertices = size(A,1);
14 |
15 | % parse remaining arguments
16 | p = inputParser;
17 | defaultGamma = 1;
18 | defaultDissimilarSamples = 2*size(similar_pairs,2);
19 | default_topk_features = size(X,2);
20 | default_dml = 'sparse';
21 | default_file_out = '';
22 | default_reweight_type = 'sparse';
23 |
24 | addOptional(p, 'gamma', defaultGamma,@isnumeric);
25 | addOptional(p, 'size_D', defaultDissimilarSamples,@isnumeric);
26 | addOptional(p, 'top_k_features', default_topk_features, @isnumeric);
27 | addOptional(p, 'dml_datatype', default_dml, @(x) strcmp(x, 'sparse') || strcmp(x, 'dense'));
28 | addOptional(p, 'file_output', default_file_out, @isstr);
29 | addOptional(p, 'reweight_type', default_reweight_type, @isstr);
30 |
31 | parse(p, varargin{:});
32 |
33 | gamma = p.Results.gamma;
34 | num_dissimilar_pairs = p.Results.size_D;
35 | top_k_features = p.Results.top_k_features;
36 | dml_datatype = p.Results.dml_datatype;
37 | dm_file_out = p.Results.file_output;
38 | reweight_type = p.Results.reweight_type;
39 |
40 | fprintf('FocusCO Distance Metric Learning\n-------------------------------------\n')
41 | fprintf('Gamma: %f\n', gamma)
42 | fprintf('# Dissimilar pairs: %d\n', num_dissimilar_pairs)
43 | fprintf('Distance Metric Learning Data Type: %s\n', dml_datatype)
44 | fprintf('# Features to consider (if dml_datatype == sparse): %d\n', top_k_features)
45 | fprintf('Type of graph reweighting (sparse or dense similarity): %s\n', reweight_type)
46 | fprintf('Graph Output File: %s\n\n', dm_file_out)
47 |
48 | % use dense or sparse DML?
49 | [ DM, S, D ] = distance_metric_learning_manual(X, similar_pairs, num_dissimilar_pairs, num_vertices , gamma, top_k_features, dml_datatype);
50 |
51 | fprintf('Distance metric:\n');
52 | DM
53 |
54 | if strcmp(reweight_type, 'sparse')
55 | WeightedA = reweigh_sparse(A, X, DM);
56 | else
57 | WeightedA = reweigh(A, X, DM);
58 | end
59 |
60 | if ~strcmp(dm_file_out, '')
61 | savesparse(dm_file_out, WeightedA);
62 | end
63 | %exit
64 | end
65 |
--------------------------------------------------------------------------------
/java_src/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | edu.stonybrook.focused
8 | LocalFocusedGraphClustering
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 |
14 | org.apache.maven.plugins
15 | maven-compiler-plugin
16 | 3.1
17 |
18 | 1.7
19 | 1.7
20 |
21 |
22 |
23 |
24 |
25 |
26 | maven-assembly-plugin
27 |
28 |
29 | package
30 |
31 | attached
32 |
33 |
34 |
35 |
36 |
37 | jar-with-dependencies
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | ca.umontreal.iro
47 | ssj
48 | 2.5
49 |
50 |
51 |
52 | args4j
53 | args4j
54 | 2.0.16
55 |
56 |
57 |
58 |
59 | net.sf.jgrapht
60 | jgrapht
61 | 0.8.3
62 |
63 |
64 | junit
65 | junit
66 | 4.10
67 |
68 |
69 |
70 | com.google.guava
71 | guava
72 | 15.0
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/java_src/src/main/java/META-INF/MANIFEST.MF:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 | Main-Class: edu.stonybrook.focused.main.CommunityClusterer
3 |
4 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/GraphReweighter.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused;
2 |
3 | /**
4 | * User: hubris (Bryan Perozzi)
5 | *
6 |
7 | */
8 | public class GraphReweighter {
9 | }
10 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/Vertex.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused;
2 |
3 | /**
4 | * Author: hubris(Bryan Perozzi)
5 | *
6 |
7 | */
8 | public class Vertex {
9 | public Long id;
10 | }
11 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/community/BookkeepingWeightedGraph.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused.community;
2 |
3 | import org.jgrapht.graph.DefaultWeightedEdge;
4 | import org.jgrapht.graph.SimpleWeightedGraph;
5 |
6 | import java.util.HashMap;
7 |
8 | /**
9 | * Author: Bryan Perozzi
10 | *
11 |
12 | */
13 | public class BookkeepingWeightedGraph extends SimpleWeightedGraph {
14 |
15 | protected HashMap weightedOutDegree = new HashMap();
16 |
17 | double totalWeightedVolume = 0.0;
18 |
19 | public BookkeepingWeightedGraph() {
20 | super(DefaultWeightedEdge.class);
21 | }
22 |
23 | @Override
24 | public DefaultWeightedEdge addEdge(Integer v, Integer v1) {
25 | double weight = DEFAULT_EDGE_WEIGHT;
26 | weightedOutDegree.put(v, weightedOutDegree.get(v) + weight);
27 | weightedOutDegree.put(v1, weightedOutDegree.get(v1) + weight);
28 | totalWeightedVolume += 2 * weight;
29 |
30 | return super.addEdge(v, v1);
31 | }
32 |
33 | @Override
34 | public boolean addVertex(Integer v){
35 | if (!weightedOutDegree.containsKey(v)){
36 | weightedOutDegree.put(v, 0.0);
37 | }
38 | return super.addVertex(v);
39 | }
40 |
41 | @Override
42 | public boolean addEdge(Integer v, Integer v1, DefaultWeightedEdge e) {
43 | double weight = getEdgeWeight(e);
44 | weightedOutDegree.put(v, weightedOutDegree.get(v) + weight);
45 | weightedOutDegree.put(v1, weightedOutDegree.get(v1) + weight);
46 | totalWeightedVolume += 2 * weight;
47 |
48 | return super.addEdge(v, v1, e);
49 | }
50 |
51 | @Override
52 | public void setEdgeWeight(DefaultWeightedEdge e, double val) {
53 | double weight = getEdgeWeight(e);
54 |
55 | Integer v1 = getEdgeSource(e);
56 | Integer v2 = getEdgeTarget(e);
57 |
58 | if (v1 != null || v2 != null){
59 | weightedOutDegree.put(v1, weightedOutDegree.get(v1) - weight);
60 | weightedOutDegree.put(v2, weightedOutDegree.get(v2) - weight);
61 | totalWeightedVolume -= 2 * weight;
62 |
63 | weightedOutDegree.put(v1, weightedOutDegree.get(v1) + val);
64 | weightedOutDegree.put(v2, weightedOutDegree.get(v2) + val);
65 | totalWeightedVolume += 2 * val;
66 | }
67 |
68 | super.setEdgeWeight(e, val);
69 | }
70 |
71 | public double getWeightedVolume() {
72 | return totalWeightedVolume;
73 | }
74 |
75 | public double getWeightedOutDegreeOf(int v) {
76 | return weightedOutDegree.get(v);
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/community/GreedyLocalCommunityBuilder.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused.community;
2 |
3 | import org.jgrapht.Graph;
4 | import org.jgrapht.Graphs;
5 | import org.jgrapht.graph.DefaultWeightedEdge;
6 |
7 | import java.util.ArrayList;
8 | import java.util.HashSet;
9 | import java.util.logging.Logger;
10 |
11 | /**
12 | * User: hubris (Bryan Perozzi)
13 | *
14 |
15 | */
16 | public class GreedyLocalCommunityBuilder implements LocalCommunityBuilder {
17 |
18 | Logger logger = Logger.getLogger(GreedyLocalCommunityBuilder.class.getName());
19 |
20 | public int GREEDY_STRUCTUAL_NODES_REMOVED_CNT = 0;
21 | public int GREEDY_FOCUSED_NODES_REMOVED_CNT = 0;
22 |
23 | final public int MAX_MISTEPS = 0;
24 |
25 | final public double MIN_DELTA = -0.000001;
26 |
27 | final public int MAX_ITER = 5;
28 |
29 | // inputs
30 | Graph structuralGraph;
31 | Graph focusedGraph;
32 | Iterable seedSet;
33 |
34 | // outputs
35 | UnweightedCommunity structuralCommunity;
36 | WeightedCommunity focusedCommunity;
37 |
38 | // types of outliers
39 | HashSet outliers = new HashSet();
40 | HashSet inliers = new HashSet();
41 |
42 | public GreedyLocalCommunityBuilder(Graph structural, Graph focused, Iterable seeds, double EDGE_VARIANCE) {
43 | structuralGraph = structural;
44 | focusedGraph = focused;
45 | seedSet = seeds;
46 |
47 | structuralCommunity = new UnweightedCommunity(structural);
48 | focusedCommunity = new WeightedMeansCommunity(focused, EDGE_VARIANCE);
49 |
50 | buildCommunities();
51 | }
52 |
53 | protected void buildCommunities() {
54 | HashSet bestStructuralNodes = new HashSet();
55 |
56 | // Greedy Focused UnweightedCommunity Algorithm:
57 | // 1. initialize community with seed set
58 | // 2. iterate over neighbors to expand set
59 | // 2.a. get candidate nodes (neighbors of community for greedy)
60 | // 2.b. find best structural node and best focused node to add
61 | // 2.c. add best nodes if they exist
62 | // 3. do the time warp (check to see if removing any node decrease conductance, and remove it)
63 | // 4. record outliers
64 |
65 | // 1. initialize community with seed set
66 | for (Integer i : seedSet) {
67 | structuralCommunity.add(i);
68 | focusedCommunity.add(i);
69 | }
70 |
71 | // 2. iterate over neighbors to expand set
72 | ArrayList candidateNodes = new ArrayList();
73 | Integer bestNode = null;
74 | Integer bestStructuralNode = null;
75 |
76 | // for backtracking greedy
77 | double minConductanceSeenSoFar = 1.0;
78 | ArrayList backtrackList = new ArrayList();
79 |
80 | boolean any_focused_community_change = false;
81 |
82 | // found a case where it infitinately adds/removes?
83 | int iter = 0;
84 |
85 | do {
86 | any_focused_community_change = false;
87 |
88 | int missteps = 0;
89 |
90 | do {
91 | bestNode = null;
92 | bestStructuralNode = null;
93 | double bestDeltaPhi = Double.POSITIVE_INFINITY;
94 | double bestDeltaPhi_s = Double.POSITIVE_INFINITY;
95 |
96 | // 2.a. get candidate nodes (neighbors of community for greedy)
97 | neighbors(focusedCommunity, candidateNodes);
98 |
99 | // 2.b. find best structural node and best focused node to add
100 | for (Integer n : candidateNodes) {
101 | // check whether 'n' decreases conductance for either of the sets
102 | double deltaPhi_s = structuralCommunity.getDeltaConductance(n, true);
103 | double deltaPhi = focusedCommunity.getDeltaConductance(n, true);
104 |
105 | if (deltaPhi_s < bestDeltaPhi_s) {
106 | bestStructuralNode = n;
107 | bestDeltaPhi_s = deltaPhi_s;
108 | }
109 |
110 | if (deltaPhi < bestDeltaPhi) {
111 | bestNode = n;
112 | bestDeltaPhi = deltaPhi;
113 | }
114 | }
115 |
116 | // 2.c. add best nodes if they exist
117 | if (bestNode != null) {
118 |
119 | // add node, if its good, or if we have backtracking steps left
120 | if (bestDeltaPhi > MIN_DELTA && missteps < MAX_MISTEPS) {
121 | focusedCommunity.add(bestNode);
122 | structuralCommunity.add(bestNode);
123 | missteps++;
124 | backtrackList.add(bestNode);
125 | } else if (bestDeltaPhi <= MIN_DELTA) {
126 | focusedCommunity.add(bestNode);
127 | structuralCommunity.add(bestNode);
128 | if (missteps > 0) {
129 | backtrackList.add(bestNode);
130 | }
131 | any_focused_community_change = true;
132 | } else {
133 | // go back to minimum
134 | for (Integer i : backtrackList) {
135 | focusedCommunity.remove(i);
136 | }
137 | bestNode = null;
138 | }
139 |
140 | // if the backtrack made things better in the long run, reset it
141 | if (focusedCommunity.getConductance() < minConductanceSeenSoFar) {
142 | missteps = 0;
143 | minConductanceSeenSoFar = focusedCommunity.getConductance();
144 | backtrackList.clear();
145 | }
146 |
147 | }
148 | if (bestStructuralNode != null) {
149 | bestStructuralNodes.add(bestStructuralNode);
150 | }
151 |
152 | // logger.info("best: [" + bestNode + " : " + bestDeltaPhi + " , " + bestStructuralNode + " : " + bestDeltaPhi_s + "]");
153 | } while (bestNode != null);
154 |
155 | // System.err.println("Done Adding. Current conductance: " + focusedCommunity.getConductance() + "size: " + focusedCommunity.size());
156 |
157 | // 3. do the time warp (check to see if removing any node decreases conductance, and remove it)
158 | boolean removed = false;
159 |
160 | do {
161 | removed = false;
162 | bestNode = null;
163 | double bestDeltaPhi = 0.0;
164 |
165 | for (Integer n : focusedCommunity) {
166 | // check whether removing n decreases conductance. if so, do it
167 | double deltaPhi = focusedCommunity.getDeltaConductance(n, false);
168 | if (deltaPhi < bestDeltaPhi) {
169 | bestNode = n;
170 | bestDeltaPhi = deltaPhi;
171 | }
172 | }
173 |
174 | if (bestNode != null) {
175 | // logger.info("best: [" + bestNode + " : " + bestDeltaPhi + "]");
176 | removed = true;
177 | focusedCommunity.remove(bestNode);
178 | any_focused_community_change = true;
179 | GREEDY_FOCUSED_NODES_REMOVED_CNT++;
180 | }
181 |
182 | } while (removed);
183 |
184 | // System.err.println("Done Removing. Current conductance: " + focusedCommunity.getConductance() + "size: " + focusedCommunity.size());
185 | iter++;
186 |
187 | } while (any_focused_community_change && iter < MAX_ITER);
188 |
189 | // 4. record outliers.
190 | // we define outliers to be nodes that were in the focused community, but were not in the structural community
191 | bestStructuralNodes.removeAll(focusedCommunity);
192 | outliers.addAll(bestStructuralNodes);
193 |
194 | // we define an inlier here as something that was added to the focused community, but then later removed
195 | inliers.addAll(structuralCommunity);
196 | inliers.removeAll(focusedCommunity);
197 | }
198 |
199 | protected void neighbors(HashSet input, ArrayList output) {
200 | output.clear();
201 |
202 | HashSet added = new HashSet();
203 |
204 | // TODO (bperozzi) perhaps this should sort by edge weight
205 | for (Integer i : input) {
206 | for (DefaultWeightedEdge e : structuralGraph.edgesOf(i)) {
207 | Integer target = Graphs.getOppositeVertex(structuralGraph, e, i);
208 |
209 | if (!input.contains(target) && !added.contains(target)) {
210 | output.add(target);
211 | added.add(target);
212 | }
213 | }
214 | }
215 | }
216 |
217 | @Override
218 | public UnweightedCommunity getStructuralCommunity() {
219 | return structuralCommunity;
220 | }
221 |
222 | @Override
223 | public WeightedCommunity getFocusedCommunity() {
224 | return focusedCommunity;
225 | }
226 |
227 | @Override
228 | public HashSet getOutliers() {
229 | return outliers;
230 | }
231 |
232 | @Override
233 | public HashSet getInliers() {
234 | return inliers;
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/community/ICommunity.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused.community;
2 |
3 | import java.util.Set;
4 |
5 | /**
6 | * Author: Bryan Perozzi
7 | *
8 |
9 | */
10 | public interface ICommunity extends Set {
11 | double getConductance();
12 |
13 | double getVolume();
14 |
15 | double getDeltaConductance(Integer vertex, boolean toAdd);
16 | }
17 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/community/LocalCommunityBuilder.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused.community;
2 |
3 | import java.util.HashSet;
4 |
5 | /**
6 | * User: hubris
7 | *
8 |
9 | */
10 | public interface LocalCommunityBuilder {
11 |
12 | public UnweightedCommunity getStructuralCommunity();
13 |
14 | public WeightedCommunity getFocusedCommunity();
15 |
16 | public HashSet getOutliers();
17 |
18 | public HashSet getInliers();
19 | }
20 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/community/Outlier.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused.community;
2 |
3 | /**
4 | * Author: Bryan Perozzi
5 | *
6 |
7 | */
8 | public class Outlier {
9 | public int id = -1;
10 | public int votesOutlier = 1;
11 | public int votes = 1;
12 | public int notInCommunity = 0;
13 |
14 | public Outlier(int id) {
15 | this.id = id;
16 | }
17 |
18 | public double outlierRatio() {
19 | return (votesOutlier / (double) votes);
20 | }
21 |
22 | @Override
23 | public boolean equals(Object o) {
24 | Outlier other = (Outlier) o;
25 | if (other != null) {
26 | return other.id == id;
27 | }
28 | return false;
29 | }
30 |
31 | @Override
32 | // TODO this probably needs to be better
33 | public int hashCode() {
34 | return id;
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | return "[" + id + "," + outlierRatio() + "," + notInCommunity + "]";
40 | }
41 | }
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/community/PrecomputedCommunity.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused.community;
2 |
3 | import java.util.Collection;
4 | import java.util.Iterator;
5 | import java.util.List;
6 |
7 | /**
8 | * Author: Bryan Perozzi
9 | *
10 |
11 | */
12 | public class PrecomputedCommunity implements ICommunity{
13 |
14 | List community;
15 | double conductance;
16 | double volume;
17 |
18 | public PrecomputedCommunity(List community, double conductance, double volume){
19 | this.community = community;
20 | this.conductance = conductance;
21 | this.volume = volume;
22 | }
23 |
24 | @Override
25 | public double getConductance() {
26 | return conductance;
27 | }
28 |
29 | @Override
30 | public double getVolume() {
31 | return volume;
32 | }
33 |
34 | @Override
35 | public double getDeltaConductance(Integer vertex, boolean toAdd) {
36 | throw new UnsupportedOperationException ();
37 | }
38 |
39 | @Override
40 | public int size() {
41 | return community.size();
42 | }
43 |
44 | @Override
45 | public boolean isEmpty() {
46 | return community.isEmpty();
47 | }
48 |
49 | @Override
50 | public boolean contains(Object o) {
51 | throw new UnsupportedOperationException ();
52 | }
53 |
54 | @Override
55 | public Iterator iterator() {
56 | return community.iterator();
57 | }
58 |
59 | @Override
60 | public Object[] toArray() {
61 | return community.toArray();
62 | }
63 |
64 | @Override
65 | public T[] toArray(T[] a) {
66 | return community.toArray(a);
67 | }
68 |
69 | @Override
70 | public boolean add(Integer integer) {
71 | throw new UnsupportedOperationException ();
72 | }
73 |
74 | @Override
75 | public boolean remove(Object o) {
76 | throw new UnsupportedOperationException ();
77 | }
78 |
79 | @Override
80 | public boolean containsAll(Collection> c) {
81 | throw new UnsupportedOperationException ();
82 | }
83 |
84 | @Override
85 | public boolean addAll(Collection extends Integer> c) {
86 | throw new UnsupportedOperationException ();
87 | }
88 |
89 | @Override
90 | public boolean retainAll(Collection> c) {
91 | throw new UnsupportedOperationException ();
92 | }
93 |
94 | @Override
95 | public boolean removeAll(Collection> c) {
96 | throw new UnsupportedOperationException ();
97 | }
98 |
99 | @Override
100 | public void clear() {
101 | throw new UnsupportedOperationException ();
102 | }
103 |
104 | @Override
105 | public String toString() {
106 | StringBuffer buffer = new StringBuffer();
107 |
108 | buffer.append("GenericCommunity Container:\n");
109 | buffer.append("\t volume: " + volume + "\n");
110 | buffer.append("\t conductance: " + conductance + "\n");
111 | buffer.append("\t members: " + size() + "\n");
112 |
113 | if (size() < 50) {
114 | buffer.append("\t {");
115 | for (Integer i : this) {
116 | buffer.append(i + ", ");
117 | }
118 | buffer.append(" }\n");
119 | }
120 |
121 |
122 | return buffer.toString();
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/community/UnweightedCommunity.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused.community;
2 |
3 | import com.google.common.collect.Lists;
4 | import org.jgrapht.Graph;
5 | import org.jgrapht.graph.DefaultWeightedEdge;
6 |
7 | import java.util.ArrayList;
8 | import java.util.Collections;
9 | import java.util.HashSet;
10 | import java.util.Set;
11 |
12 | /**
13 | * Author: Bryan Perozzi
14 | *
15 |
16 | */
17 | public class UnweightedCommunity extends HashSet implements ICommunity {
18 |
19 | Graph graph;
20 |
21 | public UnweightedCommunity(Graph g) {
22 | graph = g;
23 |
24 | totalEdges = graph.edgeSet().size();
25 | totalVolume = 2 * totalEdges;
26 | }
27 |
28 | protected double conductance = 1.0;
29 |
30 | protected long external_edges = 0;
31 | protected long denominator = 0;
32 | protected long volume = 0;
33 |
34 | protected long totalEdges = 0;
35 | protected long totalVolume = 0;
36 |
37 | public long countExternalEdges(Integer i, Set neighborSet) {
38 |
39 | int numberExternalEdges = 0;
40 |
41 | // count number of external edges
42 | for (DefaultWeightedEdge edge : neighborSet) {
43 |
44 | // no easy way to get 'other' out of JGraph's undirected graph edge traversal... ugh!
45 | Integer src = graph.getEdgeSource(edge);
46 | Integer dst = graph.getEdgeTarget(edge);
47 | Integer other = src.equals(i) ? dst : src;
48 |
49 | if (contains(other)) {
50 | numberExternalEdges -= 1;
51 | } else {
52 | numberExternalEdges += 1;
53 | }
54 | }
55 |
56 | return numberExternalEdges;
57 | }
58 |
59 | @Override
60 | public boolean add(Integer i) {
61 | // maintain unweighted volume
62 | Set neighborSet = graph.edgesOf(i);
63 | volume += neighborSet.size();
64 |
65 | // maintain correct denominator to compute conductance with
66 | denominator = Math.min(volume, totalVolume - volume);
67 |
68 | // count how many external edges this node has with the community
69 | external_edges += countExternalEdges(i, neighborSet);
70 |
71 | conductance = external_edges / (double) denominator;
72 |
73 | return super.add(i);
74 | }
75 |
76 | @Override
77 | public boolean remove(Object o) {
78 | Integer i = (Integer) o;
79 | // maintain unweighted volume
80 | Set neighborSet = graph.edgesOf(i);
81 | volume -= neighborSet.size();
82 |
83 | // maintain correct denominator to compute conductance with
84 | denominator = Math.min(volume, totalVolume - volume);
85 |
86 | boolean retValue = super.remove(i);
87 |
88 | // count how many external edges this node has with the community, and remove them (opposite of add)
89 | external_edges -= countExternalEdges(i, neighborSet);
90 |
91 | conductance = external_edges / (double) denominator;
92 |
93 | return retValue;
94 | }
95 |
96 | public long getExternalEdges() {
97 | return external_edges;
98 | }
99 |
100 | @Override
101 | public double getConductance() {
102 | return conductance;
103 | }
104 |
105 | @Override
106 | public double getVolume() {
107 | return volume;
108 | }
109 |
110 | /**
111 | * Return the change in conductance which would occur from adding a particular vertex to the set.
112 | * This is linear in the degree of the vertex. ie., O(degree(toAdd))
113 | */
114 | @Override
115 | public double getDeltaConductance(Integer vertex, boolean add) {
116 |
117 | Set neighborSet = graph.edgesOf(vertex);
118 |
119 | int degree_U = neighborSet.size();
120 | long delta_E = 0;
121 |
122 | delta_E = countExternalEdges(vertex, neighborSet);
123 |
124 | if (!add) {
125 | delta_E = -1 * delta_E;
126 | degree_U = -1 * degree_U;
127 | }
128 |
129 | long new_volume = volume + degree_U;
130 | long new_denom = Math.min(new_volume, totalVolume - new_volume);
131 | double rescaled_conductance = ((denominator) / (double) (new_denom)) * conductance;
132 | double final_conductance = rescaled_conductance + (delta_E) / (double) (new_denom);
133 |
134 | // this is the change in conductance if one were to add node u
135 | return final_conductance - conductance;
136 | }
137 |
138 | @Override
139 | public String toString() {
140 | StringBuffer buffer = new StringBuffer();
141 |
142 | buffer.append("UnweightedCommunity:\n");
143 | buffer.append("\t outgoing edges: " + external_edges + "\n");
144 | buffer.append("\t volume: " + volume + "\n");
145 | buffer.append("\t conductance: " + conductance + "\n");
146 | buffer.append("\t members: " + size() + "\n");
147 |
148 | ArrayList members = Lists.newArrayList(this);
149 | Collections.sort(members);
150 |
151 | if (size() < 50) {
152 | buffer.append("\t {");
153 | for (Integer i : members) {
154 | buffer.append(i + ", ");
155 | }
156 | buffer.append(" }\n");
157 | }
158 |
159 | return buffer.toString();
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/community/WeightedCommunity.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused.community;
2 |
3 | import com.google.common.collect.Lists;
4 | import org.jgrapht.Graph;
5 | import org.jgrapht.graph.DefaultWeightedEdge;
6 |
7 | import java.util.*;
8 |
9 | /**
10 | * Author: Bryan Perozzi
11 | *
12 |
13 | */
14 | public class WeightedCommunity extends HashSet implements ICommunity {
15 |
16 | public final double MIN_VERTEX_VOLUME = 0.0000001;
17 |
18 | Graph graph;
19 |
20 | public WeightedCommunity(Graph g) {
21 | graph = g;
22 |
23 | totalEdges = graph.edgeSet().size();
24 |
25 | // sum up total edge weights
26 | // TODO (bperozzi) find a more stable way to do this?
27 | for (DefaultWeightedEdge edge : graph.edgeSet()) {
28 | totalVolume += graph.getEdgeWeight(edge);
29 | }
30 | totalVolume *= 2;
31 | }
32 |
33 | protected double conductance = 1.0;
34 |
35 | protected double external_edges = 0;
36 | protected double internal_edges_sum = 0;
37 | protected double internal_edges_sum_squares = 0;
38 | protected int internal_edges_cnt = 0;
39 | protected double denominator = 0;
40 | protected double volume = 0;
41 |
42 | protected double totalEdges = 0;
43 | protected double totalVolume = 0;
44 |
45 | @Override
46 | public boolean add(Integer i) {
47 | Set neighborSet = graph.edgesOf(i);
48 |
49 | // maintain unweighted volume and
50 | // count number of external edges
51 | for (DefaultWeightedEdge edge : neighborSet) {
52 |
53 | // no easy way to get 'other' out of JGraph's undirected graph edge traversal... ugh!
54 | Integer src = graph.getEdgeSource(edge);
55 | Integer dst = graph.getEdgeTarget(edge);
56 |
57 | Double weight = graph.getEdgeWeight(edge);
58 | Integer other = src.equals(i) ? dst : src;
59 |
60 | if (weight > MIN_VERTEX_VOLUME) {
61 | if (contains(other)) {
62 | external_edges -= weight;
63 | internal_edges_sum += weight;
64 | internal_edges_sum_squares += Math.pow(weight, 2);
65 | internal_edges_cnt++;
66 | } else {
67 | external_edges += weight;
68 | }
69 | volume += weight;
70 | }
71 | }
72 |
73 | // did floating point mess up the math?
74 | if (external_edges < 0) {
75 | external_edges = 0.0;
76 | }
77 |
78 | // maintain correct denominator to compute conductance with
79 | denominator = Math.min(volume, totalVolume - volume);
80 |
81 | // what if we've added the entire graph?
82 | if ((totalVolume - volume) < MIN_VERTEX_VOLUME) {
83 | denominator = 1.0;
84 | }
85 |
86 | conductance = external_edges / (double) denominator;
87 |
88 | return super.add(i);
89 | }
90 |
91 | @Override
92 | public boolean remove(Object o) {
93 | Integer i = (Integer) o;
94 |
95 | Set neighborSet = graph.edgesOf(i);
96 |
97 | double weightedDegree_U = 0;
98 | double delta_E = 0L;
99 |
100 | for (DefaultWeightedEdge edge : neighborSet) {
101 |
102 | // no easy way to get 'other' out of JGraph's undirected graph edge traversal... ugh!
103 | Integer src = graph.getEdgeSource(edge);
104 | Integer dst = graph.getEdgeTarget(edge);
105 | Integer other = src.equals(i) ? dst : src;
106 | Double weight = graph.getEdgeWeight(edge);
107 |
108 | if (contains(other)) {
109 | delta_E -= weight;
110 | internal_edges_sum -= weight;
111 | internal_edges_sum_squares -= Math.pow(weight, 2);
112 | internal_edges_cnt--;
113 | } else {
114 | delta_E += weight;
115 | }
116 | weightedDegree_U += weight;
117 | }
118 |
119 | // maintain weighted volume
120 | if (weightedDegree_U > MIN_VERTEX_VOLUME) {
121 | volume -= weightedDegree_U;
122 | }
123 |
124 | // maintain correct denominator to compute conductance with
125 | denominator = Math.min(volume, totalVolume - volume);
126 |
127 | // what if we've added the entire graph?
128 | if ((totalVolume - volume) < MIN_VERTEX_VOLUME) {
129 | denominator = 1.0;
130 | }
131 |
132 | boolean retValue = super.remove(i);
133 |
134 | // count how many external edges this node has with the community, and remove them (opposite of add)
135 | if (Math.abs(delta_E) > MIN_VERTEX_VOLUME) {
136 | external_edges -= delta_E;
137 | }
138 |
139 | // did floating point mess up the math?
140 | if (external_edges < 0) {
141 | external_edges = 0;
142 | }
143 |
144 | conductance = external_edges / (double) denominator;
145 |
146 | return retValue;
147 | }
148 |
149 | public double getExternalEdges() {
150 | return external_edges;
151 | }
152 |
153 | @Override
154 | public double getConductance() {
155 | return conductance;
156 | }
157 |
158 | @Override
159 | public double getVolume() {
160 | return volume;
161 | }
162 |
163 | /**
164 | * Return the change in conductance which would occur from adding a particular vertex to the set.
165 | * This is linear in the degree of the vertex. ie., O(degree(toAdd))
166 | */
167 | @Override
168 | public double getDeltaConductance(Integer vertex, boolean add) {
169 |
170 | Set neighborSet = graph.edgesOf(vertex);
171 |
172 | double weightedDegree_U = 0;
173 | double delta_E = 0L;
174 |
175 | for (DefaultWeightedEdge edge : neighborSet) {
176 |
177 | // no easy way to get 'other' out of JGraph's undirected graph edge traversal... ugh!
178 | Integer src = graph.getEdgeSource(edge);
179 | Integer dst = graph.getEdgeTarget(edge);
180 | Integer other = src.equals(vertex) ? dst : src;
181 | Double weight = graph.getEdgeWeight(edge);
182 |
183 | if (contains(other)) {
184 | delta_E -= weight;
185 | } else {
186 | delta_E += weight;
187 | }
188 | weightedDegree_U += weight;
189 | }
190 |
191 | // what if the node has 0 volume? ie, all edges about 0.0
192 | double absVolume = Math.abs(weightedDegree_U);
193 | if (absVolume < MIN_VERTEX_VOLUME) {
194 | return 0.0;
195 | }
196 |
197 | if (!add) {
198 | delta_E = -1 * delta_E;
199 | weightedDegree_U = -1 * weightedDegree_U;
200 | }
201 |
202 | double new_volume = volume + weightedDegree_U;
203 | double new_denom = Math.min(new_volume, totalVolume - new_volume);
204 | double rescaled_conductance = ((denominator) / (double) (new_denom)) * conductance;
205 | double final_conductance = rescaled_conductance + (delta_E) / (double) (new_denom);
206 |
207 | // this is the change in conductance if one were to add node u
208 | return final_conductance - conductance;
209 | }
210 |
211 | @Override
212 | public String toString() {
213 | StringBuffer buffer = new StringBuffer();
214 |
215 | buffer.append("WeightedCommunity:\n");
216 | buffer.append("\t outgoing edges: " + external_edges + "\n");
217 | buffer.append("\t volume: " + volume + "\n");
218 | buffer.append("\t conductance: " + conductance + "\n");
219 | buffer.append("\t members: " + size() + "\n");
220 |
221 | ArrayList members = Lists.newArrayList(this);
222 | Collections.sort(members);
223 |
224 | if (size() < 5000) {
225 | buffer.append("\t {");
226 | for (Integer i : members) {
227 | buffer.append(i + ", ");
228 | }
229 | buffer.append(" }\n");
230 | }
231 |
232 |
233 | return buffer.toString();
234 | }
235 | }
236 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/community/WeightedMeansCommunity.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused.community;
2 |
3 | import org.jgrapht.Graph;
4 | import org.jgrapht.graph.DefaultWeightedEdge;
5 | import umontreal.iro.lecuyer.probdist.NormalDistQuick;
6 |
7 | import java.util.Set;
8 |
9 | /**
10 | * Author: Bryan Perozzi
11 | *
12 |
13 | */
14 | public class WeightedMeansCommunity extends WeightedCommunity {
15 |
16 | public final double P_VALUE = 0.05;
17 | public final double CLUSTER_VARIANCE;
18 |
19 | public final double MAP_BETA = 5;
20 |
21 | public WeightedMeansCommunity(Graph g, double variance) {
22 | super(g);
23 | CLUSTER_VARIANCE = variance;
24 | }
25 |
26 | public double getPValue(double x) {
27 | if (internal_edges_cnt == 0) {
28 | return 1.0;
29 | }
30 |
31 | double mean = internal_edges_sum / internal_edges_cnt;
32 |
33 | // double varianceMLE = (internal_edges_sum_squares - (Math.pow(internal_edges_sum, 2)/internal_edges_cnt))/internal_edges_cnt;
34 | // double varianceMAP = CLUSTER_VARIANCE / (1 + internal_edges_cnt) + (internal_edges_cnt * varianceMLE) / (internal_edges_cnt + 1);
35 | // return NormalDistQuick.cdf(mean, varianceMAP, x);
36 |
37 | return NormalDistQuick.cdf(mean, CLUSTER_VARIANCE, x);
38 | }
39 |
40 | // /**
41 | // * We want this to return the weighted means conductance here, so the sorting will perhaps be more meaningful?
42 | // *
43 | // * @return
44 | // */
45 | // @Override
46 | // public double getConductance() {
47 | //
48 | // double internal = 0;
49 | // double external = 0;
50 | //
51 | // if (internal_edges_cnt > 0) {
52 | // for (Integer vertex : this) {
53 | // Set neighborSet = graph.edgesOf(vertex);
54 | //
55 | // for (DefaultWeightedEdge edge : neighborSet) {
56 | // // no easy way to get 'other' out of JGraph's undirected graph edge traversal... ugh!
57 | // Integer src = graph.getEdgeSource(edge);
58 | // Integer dst = graph.getEdgeTarget(edge);
59 | // Integer other = src.equals(vertex) ? dst : src;
60 | // Double weight = graph.getEdgeWeight(edge);
61 | //
62 | // if (contains(other)) {
63 | // // does this edge fit in the distribution? (p < 0.05)
64 | // // if not, don't give credit for including it
65 | // if (getPValue(weight) > P_VALUE) {
66 | // internal += weight;
67 | // }
68 | // } else {
69 | // if (getPValue(weight) > P_VALUE) {
70 | // external += weight;
71 | // }
72 | // }
73 | // }
74 | // }
75 | //
76 | //// internal = Math.min(internal, totalVolume - internal);
77 | //
78 | // if (internal < MIN_VERTEX_VOLUME)
79 | // return 0.0;
80 | //
81 | // return external / internal;
82 | // }
83 | //
84 | // return 0;
85 | // }
86 |
87 | /**
88 | * Return the change in conductance which would occur from adding a particular vertex to the set.
89 | * This is linear in the degree of the vertex. ie., O(degree(toAdd))
90 | */
91 | @Override
92 | public double getDeltaConductance(Integer vertex, boolean add) {
93 |
94 | Set neighborSet = graph.edgesOf(vertex);
95 |
96 | double weightedDegree_U = 0;
97 | double delta_E = 0L;
98 |
99 | for (DefaultWeightedEdge edge : neighborSet) {
100 |
101 | // no easy way to get 'other' out of JGraph's undirected graph edge traversal... ugh!
102 | Integer src = graph.getEdgeSource(edge);
103 | Integer dst = graph.getEdgeTarget(edge);
104 | Integer other = src.equals(vertex) ? dst : src;
105 | Double weight = graph.getEdgeWeight(edge);
106 |
107 | if (contains(other)) {
108 | // does this edge fit in the distribution? (p < 0.05)
109 | // if not, don't give credit for including it
110 | if (getPValue(weight) > P_VALUE) {
111 | delta_E -= weight;
112 | }
113 | } else {
114 | delta_E += weight;
115 | }
116 | weightedDegree_U += weight;
117 | }
118 |
119 | // what if the node has 0 volume? ie, all edges about 0.0
120 | double absVolume = Math.abs(weightedDegree_U);
121 | if (absVolume < MIN_VERTEX_VOLUME) {
122 | return 0.0;
123 | }
124 |
125 | if (!add) {
126 | delta_E = -1 * delta_E;
127 | weightedDegree_U = -1 * weightedDegree_U;
128 | }
129 |
130 | double new_volume = volume + weightedDegree_U;
131 | double new_denom = Math.min(new_volume, totalVolume - new_volume);
132 |
133 | // what if we've added the entire graph?
134 | if ((totalVolume - new_volume) < MIN_VERTEX_VOLUME) {
135 | new_denom = 1.0;
136 | }
137 |
138 | double rescaled_conductance = ((denominator) / (double) (new_denom)) * conductance;
139 | double final_conductance = rescaled_conductance + (delta_E) / (double) (new_denom);
140 |
141 | // this is the change in conductance if one were to add node u
142 | return final_conductance - conductance;
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/io/ascii/Clustering.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused.io.ascii;
2 |
3 | import java.io.IOException;
4 | import java.io.PrintWriter;
5 | import java.io.Writer;
6 | import java.util.*;
7 |
8 | /**
9 | * Author: Bryan Perozzi
10 | *
11 |
12 | */
13 | public class Clustering {
14 |
15 | public static void write(Writer writer, List> clustering) throws IOException {
16 | HashMap key = new HashMap();
17 |
18 | // assign each cluster a label
19 | for(int i=0; i cluster = clustering.get(i);
21 | for(Integer v : cluster){
22 | key.put(v, i+1);
23 | }
24 | }
25 |
26 | ArrayList vertices = new ArrayList(key.keySet());
27 | Collections.sort(vertices);
28 |
29 | PrintWriter printWriter = new PrintWriter(writer);
30 |
31 | for(Integer v : vertices){
32 | printWriter.append(v.toString());
33 | printWriter.append(" ");
34 | printWriter.append(key.get(v).toString());
35 | printWriter.append("\n");
36 | }
37 |
38 | printWriter.close();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/io/ascii/Outliers.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused.io.ascii;
2 |
3 | import edu.stonybrook.focused.community.Outlier;
4 |
5 | import java.io.IOException;
6 | import java.io.PrintWriter;
7 | import java.io.Writer;
8 | import java.util.List;
9 |
10 | /**
11 | * Author: Bryan Perozzi
12 | *
13 |
14 | */
15 | public class Outliers {
16 | public static void write(Writer writer, List clustering) throws IOException {
17 |
18 | PrintWriter printWriter = new PrintWriter(writer);
19 |
20 | int k = 1;
21 | for (Outlier o : clustering) {
22 | printWriter.append(Integer.toString(k));
23 | printWriter.append(" ");
24 | printWriter.append(Integer.toString(o.id));
25 | printWriter.append("\n");
26 | k++;
27 | }
28 |
29 | printWriter.close();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/io/ascii/WeightedEdgeList.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused.io.ascii;
2 |
3 | import edu.stonybrook.focused.community.BookkeepingWeightedGraph;
4 | import org.jgrapht.Graph;
5 | import org.jgrapht.Graphs;
6 | import org.jgrapht.graph.DefaultWeightedEdge;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.IOException;
10 | import java.io.Reader;
11 |
12 | /**
13 | * Author: Bryan Perozzi
14 | *
15 |
16 | */
17 | public class WeightedEdgeList {
18 | public static Graph read(Reader reader) throws IOException {
19 |
20 | int SELF_LOOPS = 0;
21 |
22 | Graph graph = new BookkeepingWeightedGraph();
23 |
24 | BufferedReader in = new BufferedReader(reader);
25 | String line = null;
26 | while ((line = in.readLine()) != null) {
27 | String[] entries = line.split("\\s+");
28 |
29 | Integer src = Integer.parseInt(entries[0]);
30 | Integer dst = Integer.parseInt(entries[1]);
31 |
32 | if (src.equals(dst)) {
33 | SELF_LOOPS++;
34 | continue;
35 | }
36 |
37 | Graphs.addEdgeWithVertices(graph, src, dst, Double.parseDouble(entries[2]));
38 | }
39 |
40 | System.err.println("Loaded " + graph.edgeSet().size() + " edges. Self loops removed: " + SELF_LOOPS);
41 |
42 | return graph;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/io/graphml/AttributeGetter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, Søren Atmakuri Davidsen
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * 1. Redistributions of source code must retain the above copyright notice, this
9 | * list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright notice,
11 | * this list of conditions and the following disclaimer in the documentation
12 | * and/or other materials provided with the distribution.
13 | *
14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 | */
25 |
26 | package edu.stonybrook.focused.io.graphml;
27 |
28 | import java.util.Set;
29 |
30 | /**
31 | * Provides an callback for retrieving items from the XML-backed graphml document.
32 | *
33 | * @author Soren A. Davidsen
34 | */
35 | public interface AttributeGetter {
36 | /**
37 | * Retrieve an element
38 | * @param clazz the type required
39 | * @param key the attribute name
40 | * @param
41 | * @return
42 | */
43 | public T get(Class clazz, String key);
44 |
45 | /**
46 | * Check if an attribute is available for the given element
47 | * @param clazz the type required
48 | * @param key the attribute name
49 | * @param
50 | * @return
51 | */
52 | public boolean has(Class clazz, String key);
53 |
54 | /**
55 | * Get all available attributes by key.
56 | * @return An array of the keys, empty array if no keys.
57 | */
58 | public Set keys();
59 | }
60 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/io/graphml/AttributeHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, Søren Atmakuri Davidsen
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * 1. Redistributions of source code must retain the above copyright notice, this
9 | * list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright notice,
11 | * this list of conditions and the following disclaimer in the documentation
12 | * and/or other materials provided with the distribution.
13 | *
14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 | */
25 |
26 | package edu.stonybrook.focused.io.graphml;
27 |
28 | /**
29 | * @author Soren
30 | */
31 | public interface AttributeHandler {
32 | public void handle(T obj, String id, AttributeGetter getter);
33 | }
34 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/io/graphml/AttributeProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, Søren Atmakuri Davidsen
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * 1. Redistributions of source code must retain the above copyright notice, this
9 | * list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright notice,
11 | * this list of conditions and the following disclaimer in the documentation
12 | * and/or other materials provided with the distribution.
13 | *
14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 | */
25 |
26 | package edu.stonybrook.focused.io.graphml;
27 |
28 | /**
29 | * Provider for attributes for an object.
30 | *
31 | * @author Soren A. Davidsen
32 | */
33 | public interface AttributeProvider {
34 | public void provide(T obj, AttributeSetter setter);
35 | }
36 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/io/graphml/AttributeSetter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, Søren Atmakuri Davidsen
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * 1. Redistributions of source code must retain the above copyright notice, this
9 | * list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright notice,
11 | * this list of conditions and the following disclaimer in the documentation
12 | * and/or other materials provided with the distribution.
13 | *
14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 | */
25 |
26 | package edu.stonybrook.focused.io.graphml;
27 |
28 | /**
29 | * Callback for providing attributes into the backing graphml XML, without modifying XML Document.
30 | *
31 | * @author Soren A. Davidsen
32 | */
33 | public interface AttributeSetter {
34 | /**
35 | * Set an attribute in the backing graphml XML.
36 | * @param clazz
37 | * @param key
38 | * @param value
39 | * @param
40 | */
41 | public void set(Class clazz, String key, T value);
42 | }
43 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/io/graphml/AttributeType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, Søren Atmakuri Davidsen
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * 1. Redistributions of source code must retain the above copyright notice, this
9 | * list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright notice,
11 | * this list of conditions and the following disclaimer in the documentation
12 | * and/or other materials provided with the distribution.
13 | *
14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 | */
25 |
26 | package edu.stonybrook.focused.io.graphml;
27 |
28 | /**
29 | * Representation of attr.type field.
30 | *
31 | * @author Soren A. Davidsen
32 | */
33 | public enum AttributeType {
34 |
35 | // 'attr.type' of . Values of this attribute ('boolean', 'int', 'long', 'float', 'double', and 'string')
36 | type_boolean,
37 | type_int,
38 | type_long,
39 | type_float,
40 | type_double,
41 | type_string;
42 |
43 | public String xmlValue() {
44 | return name().substring(5);
45 | }
46 | }
47 |
48 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/io/graphml/CommunityOutlierGraphMLExporter.java:
--------------------------------------------------------------------------------
1 | package edu.stonybrook.focused.io.graphml;
2 |
3 | import edu.stonybrook.focused.community.ICommunity;
4 | import org.jgrapht.Graph;
5 | import org.jgrapht.graph.DefaultWeightedEdge;
6 |
7 | import java.util.HashSet;
8 |
9 | /**
10 | * Author: Bryan Perozzi
11 | *
12 |
13 | */
14 | public class CommunityOutlierGraphMLExporter extends GraphMLExporter {
15 |
16 | public CommunityOutlierGraphMLExporter(final Graph graph, final ICommunity community, final HashSet outliers, final HashSet inliers) {
17 | this.edgeAttributeProvider(new AttributeProvider() {
18 | @Override
19 | public void provide(DefaultWeightedEdge obj, AttributeSetter setter) {
20 | setter.set(Double.class, "weight", graph.getEdgeWeight(obj));
21 | }
22 | });
23 |
24 | this.vertexAttributeProvider(new AttributeProvider() {
25 | @Override
26 | public void provide(Integer obj, AttributeSetter setter) {
27 |
28 | setter.set(String.class, "Label", obj.toString());
29 |
30 | if (community.contains(obj)) {
31 | setter.set(String.class, "Community", "Member");
32 | } else if(outliers.contains(obj)){
33 | setter.set(String.class, "Community", "Outlier");
34 | }
35 | else if(inliers.contains(obj)){
36 | setter.set(String.class, "Community", "Other Outlier");
37 | }
38 | else {
39 | setter.set(String.class, "Community", "Unassigned");
40 | }
41 | }
42 | });
43 |
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/io/graphml/ContinousNumericIDProviders.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, Søren Atmakuri Davidsen
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * 1. Redistributions of source code must retain the above copyright notice, this
9 | * list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright notice,
11 | * this list of conditions and the following disclaimer in the documentation
12 | * and/or other materials provided with the distribution.
13 | *
14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 | */
25 |
26 | package edu.stonybrook.focused.io.graphml;
27 |
28 | import org.jgrapht.ext.EdgeNameProvider;
29 | import org.jgrapht.ext.VertexNameProvider;
30 |
31 | import java.util.HashMap;
32 | import java.util.Map;
33 |
34 | /**
35 | * @author Soren A. Davidsen
36 | */
37 | public class ContinousNumericIDProviders {
38 |
39 | public static class ContinousNumericVertexNameProvider implements VertexNameProvider {
40 | private Map map = new HashMap();
41 | private int i = 0;
42 | @Override
43 | public String getVertexName(V v) {
44 | if (!map.containsKey(v))
45 | map.put(v, i++);
46 |
47 | return "n" + map.get(v);
48 | }
49 | }
50 |
51 | public static class ContinousNumericEdgeNameProvider implements EdgeNameProvider {
52 | private Map map = new HashMap();
53 | private int i = 0;
54 | @Override
55 | public String getEdgeName(E e) {
56 | if (!map.containsKey(e))
57 | map.put(e, i++);
58 |
59 | return "e" + map.get(e);
60 | }
61 | }
62 |
63 | public static class IntegerVertexNameProvider implements VertexNameProvider {
64 | @Override
65 | public String getVertexName(Integer v) {
66 | return "n" + v;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/java_src/src/main/java/edu/stonybrook/focused/io/graphml/GraphMLExporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, Søren Atmakuri Davidsen
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * 1. Redistributions of source code must retain the above copyright notice, this
9 | * list of conditions and the following disclaimer.
10 | * 2. Redistributions in binary form must reproduce the above copyright notice,
11 | * this list of conditions and the following disclaimer in the documentation
12 | * and/or other materials provided with the distribution.
13 | *
14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 | */
25 |
26 | package edu.stonybrook.focused.io.graphml;
27 |
28 | import com.google.common.collect.Lists;
29 | import org.jgrapht.DirectedGraph;
30 | import org.jgrapht.Graph;
31 | import org.jgrapht.ext.EdgeNameProvider;
32 | import org.jgrapht.ext.VertexNameProvider;
33 |
34 | import javax.xml.stream.XMLOutputFactory;
35 | import javax.xml.stream.XMLStreamException;
36 | import javax.xml.stream.XMLStreamWriter;
37 | import java.io.OutputStream;
38 | import java.util.*;
39 |
40 | /**
41 | * Class for exporting to GraphML. This exporter supports additional attributes of edges and
42 | * vertices to be exported.
43 | * See {@link "http://graphml.graphdrawing.org/primer/graphml-primer.html"} for
44 | * more information on GraphML.
45 | *
46 | *
Create the exporter. Default is to use "n0..n10" for node IDs, and "e0..e10" for edge IDs.
47 | *
To make more meaningful IDs use {@link GraphMLExporter#edgeIDProvider(org.jgrapht.ext.EdgeNameProvider)} and {@link GraphMLExporter#vertexIDProvider}
48 | *
To map GraphML supported attributes, use {@link GraphMLExporter#edgeAttributeProvider(AttributeProvider)} and {@link GraphMLExporter#vertexAttributeProvider(AttributeProvider)}