diff --git a/README.md b/README.md index 6b93f80..5b073c0 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,11 @@ will be identified through a message to standard out. (sample graphviz command: neato -Tpdf -o tree.pdf tree.dot). * ./bin/td_viz -f ./sample_graphs/1dc.64.dimacs -t ./sample_graphs/1dc.64.tree -e +###Calculate graph statistics +Generates a set of output files containing the results of your selection of a broad spectrum of graph statistics (run with -h to see all options) when +calculated on the specified input graph. The single value statistics are stored in sample_graphs/pkt-stats.stats, and that file lists where to find any features that create a vector (or more) of data. Note that without BOOST, distance-based features may not be available. +* ./bin/graph_stats -i ./sample_graphs/1dc.64.dimacs -t dimacs -p ./sample_graphs/pkt-stats -m edge_density,degree_dist,global_cc,avg_cc,assortativity,eccentricity,expansion,avg_shortest_path -r + More information on the output formats for the weighted independent set executables is in the README in max_wis. ##Getting Help diff --git a/lib_graphd/inc/Graph.h b/lib_graphd/inc/Graph.h index 7a927a1..ae7d068 100644 --- a/lib_graphd/inc/Graph.h +++ b/lib_graphd/inc/Graph.h @@ -35,19 +35,46 @@ #ifndef HAS_METIS #define omp_get_num_threads() 1 #define omp_get_thread_num() 0 + #define omp_get_max_threads() 1 #endif #endif + #ifdef HAS_PETSC + #include + #endif + #if WIN32 #define strncasecmp strncmp #endif #include "GraphInterface.h" #include "Node.h" + #include "GraphException.h" + #include "Log.h" #include + #ifdef HAS_BOOST + #include + #include + #include + + #include "boost/graph/adjacency_list.hpp" + #include "boost/graph/topological_sort.hpp" + #include + #endif + using namespace std; + #define INDDGO_INFINITY INT_MAX - 16 + + #ifdef HAS_BOOST +typedef boost::property EdgeWeightProperty; +typedef boost::property CentralityMap; +typedef boost::adjacency_list BoostUndirected; +typedef boost::graph_traits < BoostUndirected >::vertex_descriptor vertex_descriptor; +typedef boost::graph_traits < BoostUndirected >::edge_descriptor edge_descriptor; + #endif //HAS_BOOST + namespace Graph { class Graph : public GraphInterface { @@ -69,7 +96,17 @@ namespace Graph { vector xadj; vector adjncy; vector adj_vec; - vector< vector > apsp_dist; + vector< vector > *apsp_dist; + + // Currently this is only calculated if you have Boost. + vector betweenness; + #ifdef HAS_BOOST + BoostUndirected *boost_graph; + #endif //HAS_BOOST + + #ifdef HAS_PETSC + Mat PetscMat; + #endif public: Graph(); @@ -95,7 +132,9 @@ namespace Graph { /** \brief Try to pre-allocate memory for node and degree vectors **/ void resize(int n); /** \brief set shortest path distances **/ - void set_shortest_path_dist(vector< vector > apsp_dist); + void set_shortest_path_dist(vector< vector > *apsp_dist); + /** \brief set betweenness centrality vector **/ + void set_betweenness(vector bc); vector get_adj_vec() const; vector *get_adj_vec_ptr(); @@ -113,8 +152,12 @@ namespace Graph { int get_num_edges() const; int get_num_edges_in_subgraph(list *vertices); int get_num_nodes() const; + int get_num_connected_components() const; vector get_xadj() const; + /** \brief get a const ref to the betweenness vector **/ + const vector &get_betweenness_ref(); + virtual bool is_edge(int i, int j) const; bool is_canonical() const; bool is_simple() const; @@ -152,6 +195,14 @@ namespace Graph { /** \brief get shortest path distances from vertex u to all **/ const vector &get_u_shortest_path_dist(int u); + inline Node *get_node_inline(int i){ + if(i > capacity){ + FERROR("%s: element is out of bounds", __FUNCTION__); + throw GraphException("element is out of bounds\n"); + } + return &nodes[i]; + } + friend class GraphUtil; friend class GraphProperties; friend class GraphDisplay; diff --git a/lib_graphd/inc/GraphCreator.h b/lib_graphd/inc/GraphCreator.h index e6cfd0b..c45f1ba 100644 --- a/lib_graphd/inc/GraphCreator.h +++ b/lib_graphd/inc/GraphCreator.h @@ -43,6 +43,14 @@ namespace Graph { // Specialized induced subgraph functionality for components. Sets num_connected_components to 1. virtual VertexWeightedGraph *create_component(VertexWeightedGraph *g, list *members, bool make_simple); + /** + * \brief Create an induced subgraph on g + */ + virtual Graph *create_induced_subgraph(Graph *g, list *members, bool make_simple); + /** + * \brief Create a component graph of g + */ + virtual Graph *create_component(Graph *g, list *members, bool make_simple); // Recursive and non-recursive functions that create all connected components of the graph, // which it places in the given vector diff --git a/lib_graphd/inc/GraphCreatorFile.h b/lib_graphd/inc/GraphCreatorFile.h index 609b173..c67a2b2 100644 --- a/lib_graphd/inc/GraphCreatorFile.h +++ b/lib_graphd/inc/GraphCreatorFile.h @@ -22,6 +22,12 @@ #ifndef GRAPHCREATORFILE_H_ #define GRAPHCREATORFILE_H_ +#ifdef HAS_BOOST + #ifdef HAS_GTEST + #define GTEST_HAS_TR1_TUPLE 0 + #endif +#endif + #include "GraphCreator.h" #include "GraphReader.h" #include diff --git a/lib_graphd/inc/GraphDecomposition.h b/lib_graphd/inc/GraphDecomposition.h index 5437c3a..c7f7f12 100644 --- a/lib_graphd/inc/GraphDecomposition.h +++ b/lib_graphd/inc/GraphDecomposition.h @@ -46,6 +46,19 @@ #include #include #include + +#ifdef HAS_BOOST + #ifdef HAS_GTEST + #define GTEST_HAS_TR1_TUPLE 0 + #endif + #include +#endif + +#ifndef HAS_BOOST + #include +#endif + + #include #include #include @@ -117,7 +130,7 @@ static const char EO_NAMES[][30] = { // Include header files #include "GraphDecomposition.h" #include "Graph.h" -#include "Graph.h" +//#include "Graph.h" #include "DIMACSGraphReader.h" #include "DIMACSGraphWriter.h" #include "GraphDisplay.h" diff --git a/lib_graphd/inc/GraphProperties.h b/lib_graphd/inc/GraphProperties.h index d7d860f..816ddc8 100644 --- a/lib_graphd/inc/GraphProperties.h +++ b/lib_graphd/inc/GraphProperties.h @@ -23,6 +23,15 @@ #define GRAPHPROPERTIES_H_ #include "GraphDecomposition.h" +#ifdef HAS_BOOST + #ifdef HAS_GTEST + #define GTEST_HAS_TR1_TUPLE 0 + #endif + #include "boost/graph/adjacency_list.hpp" + #include "boost/graph/topological_sort.hpp" + #include "boost/graph/betweenness_centrality.hpp" +#endif + using namespace std; namespace Graph { @@ -72,6 +81,24 @@ namespace Graph { */ void paths_dijkstra_single(Graph *g, vector &p, int source); + #ifdef HAS_BOOST + /** + * \brief returns shortest paths from source to all other nodes + */ + void paths_dijkstra_boost_single(Graph *g, vector &dists, vector &preds, int source); + + /** + * \brief returns shortest paths from all nodes to all nodes + */ + void paths_dijkstra_boost_all(Graph *g, vector< vector > &p); + + /** + * \brief calculations betweenness centrality for all vertices + */ + void betweenness_centrality(Graph *g, vector &bc); + + #endif + /** * \brief returns shortest paths from all nodes to all nodes */ @@ -112,15 +139,37 @@ namespace Graph { */ void avg_degree(Graph *g, float &ad); + /** + * \brief Calculates the average shortest path length of the specified graph + */ + void avg_path_length(Graph *g, double &pl); + /** * \brief Calculates the degree distribution of the specified graph */ void deg_dist(Graph *g, vector &dist); + #ifdef HAS_BOOST + /** + * \brief Fits the degree distribution of the specified graph to a power law distribution + */ + void powerlaw(Graph *g, int &xmin, double &alpha, double &KS, double start = 1.5, double inc = 0.01, double end = 3.5); + #endif + /** * \brief Returns the degree assortativity coefficient of a graph */ void deg_assortativity(Graph *g, double &coeff); + + /** + * \brief Returns the delta hyperbolicity of a graph + */ + void delta_hyperbolicity(Graph *g, double &max_delta, vector > &delta); + + /** + * \brief Calculates the eign spectrum. By default it does the top 5 and bottom 5. + */ + void eigen_spectrum(Graph *g, vector &eigen_values, int spread = 5); }; } diff --git a/lib_graphd/inc/GraphUtil.h b/lib_graphd/inc/GraphUtil.h index 8f81683..0e2bbf2 100644 --- a/lib_graphd/inc/GraphUtil.h +++ b/lib_graphd/inc/GraphUtil.h @@ -64,6 +64,13 @@ namespace Graph { void populate_CRS(Graph *g); void free_CRS(Graph *g); + #ifdef HAS_BOOST + /** + * \brief Populate the boost version of the graph + */ + void populate_boost(Graph *g); + #endif + //uses V as a vertex separator of G. Returns the number of components in G\V, and fills in members with their vertex lists.. int vertex_separator(Graph *g, list *V, vector *> *members); @@ -83,13 +90,28 @@ namespace Graph { //Find the eccentricity of each vertex and store it in ecc. void find_ecc(Graph *g, vector *ecc); - //Find the k-core number of each vertex and store it in kcore. - //Return degeneracy. + /** + * \brief Find the k-core number of each vertex and store it in kcore. Return degeneracy. + */ int find_kcore(Graph *g, vector *kcore); - //Calculate the maximum distance between nodes within a subset of vertices - //given as a list + /** + * \brief Calculate max distance between nodes in subset list + */ int subset_max_dist(Graph *g, vector subset); + /** + * \brief Populate adjacency matrix as a Petsc Matrix + */ + void populate_PetscMat(Graph *g); + /** + * \brief Releases PetscMat. + */ + void free_PetscMat(Graph *g); + + /** + * \brief returns a new graph that is the largest component of g + */ + Graph *get_largest_component_graph(Graph *g); }; void create_largestcomponent_graph(char *graph_file, VertexWeightedGraph *&G); diff --git a/lib_graphd/inc/Util.h b/lib_graphd/inc/Util.h index da654ba..398b70c 100644 --- a/lib_graphd/inc/Util.h +++ b/lib_graphd/inc/Util.h @@ -92,7 +92,51 @@ const char *eo_name(int eo_id); std::string str_to_up(std::string s); void split(const std::string& s, char sep, vector& v); // used in metisgraph reader +/** + * \brief write a degree distribution out to a file + */ void write_degree_distribution(string filename, const vector &dist); + +/** + * \brief write an eccentricity distribution out to a file + */ +void write_eccentricity_distribution(string filename, const vector &dist); + +/** + * \brief write a k_core list out to a file + */ +void write_kcores(string filename, const vector &kcores); + +/** + * \brief write an eccentricity list out to a file + */ +void write_eccentricity(string filename, const vector &ecc); + +/** + * \brief write a betweenness centrality list out to a file + */ +void write_betweenness(string filename, const vector &bc); + +/** + * \brief write a delta hyperbolicity distribution out to a file + */ +void write_delta_hyperbolicity(string filename, const vector< vector > &delta); + +/** + * \brief write an expansion list out to a file + */ +void write_expansion(string filename, const vector &expansion); + +/** + * \brief Write an all pairs shortest path matrix out to file. + */ +void write_apsp_matrix(string filename, vector< vector > &apsp); + +/** + * \brief Reads an all pairs shortest path matrix from file + */ +void read_apsp_matrix(string filename, vector< vector > &apsp); + int_int mylog2(int x); #endif /* UTIL_H_ */ diff --git a/lib_graphd/src/Graph.cpp b/lib_graphd/src/Graph.cpp index f7598d1..3ec81fe 100644 --- a/lib_graphd/src/Graph.cpp +++ b/lib_graphd/src/Graph.cpp @@ -34,7 +34,8 @@ void omp_set_num_threads(int num_threads){ return; } -int omp_get_num_threads(){ + +int omp_get_num_threads(void){ return 1; } @@ -84,6 +85,10 @@ namespace Graph { this->simple = true; //FIXME: check if this is correct behavior this->canonical = true; this->key = 0; + this->apsp_dist = NULL; + #ifdef HAS_BOOST + this->boost_graph = NULL; + #endif } Graph::Graph(int n){ @@ -97,9 +102,17 @@ namespace Graph { nodes[i].set_label(i + 1); } this->next_label = n + 1; + this->apsp_dist = NULL; + #ifdef HAS_BOOST + this->boost_graph = NULL; + #endif } Graph::~Graph(){ + #ifdef HAS_BOOST + delete boost_graph; + boost_graph = NULL; + #endif } void Graph::set_canonical(bool c){ @@ -154,6 +167,10 @@ namespace Graph { return this->degree[v]; } + int Graph::get_num_connected_components() const { + return this->num_connected_components; + } + /** * \param[in] n number of elements * */ @@ -820,34 +837,52 @@ namespace Graph { /** * \param[in] apsp_dist all pairs shortest paths distances **/ - void Graph::set_shortest_path_dist(vector< vector > apsp_dist){ + void Graph::set_shortest_path_dist(vector< vector > *apsp_dist){ this->apsp_dist = apsp_dist; } + /** + * \param[in] bc betweenness centrality measures for all vertices + */ + void Graph::set_betweenness(vector bc){ + this->betweenness = bc; + } + + /** + * return a const ref to the betweenness centrality vector + */ + const vector &Graph::get_betweenness_ref(){ + //FIXME: should this check to see if it's not-empty? + return this->betweenness; + } + /** * Checks if distance matrix has been computed (or needs to be recomputed) * if yes, returns the all pairs shortest paths distances * otherwise computes then returns **/ const vector< vector > &Graph::get_shortest_path_dist_ref(){ - if(this->apsp_dist.empty()){ - cout << "Empty -- calling function to compute shortest paths" << endl; + if(this->apsp_dist == NULL){ + this->apsp_dist = new vector< vector >; + } + if(this->apsp_dist->empty()){ + cout << "APSP matrix is empty -- calling function to compute shortest paths" << endl; GraphProperties properties; - properties.paths_dijkstra_all(this,this->apsp_dist); //sets this>apsp_dist with values - return this->apsp_dist; + properties.paths_dijkstra_all(this,*(this->apsp_dist)); //sets this>apsp_dist with values } - return this->apsp_dist; + return *(this->apsp_dist); } const vector &Graph::get_u_shortest_path_dist(int u){ + if(this->apsp_dist == NULL){ + this->apsp_dist = new vector< vector >; + } if(this->apsp_dist[u].empty()){ - cout << "u Empty -- calling function to compute shortest paths" << endl; + cout << "SSSP vector is empty -- calling function to compute shortest paths" << endl; GraphProperties properties; - properties.paths_dijkstra_single(this,this->apsp_dist[u], u); //sets this>apsp_dist[u] with values - - return this->apsp_dist[u]; + properties.paths_dijkstra_single(this,(*(this->apsp_dist))[u], u); //sets this>apsp_dist[u] with values } - return this->apsp_dist[u]; + return (*(this->apsp_dist))[u]; } } diff --git a/lib_graphd/src/GraphCreator.cpp b/lib_graphd/src/GraphCreator.cpp index 486f735..e77f852 100644 --- a/lib_graphd/src/GraphCreator.cpp +++ b/lib_graphd/src/GraphCreator.cpp @@ -25,6 +25,8 @@ #include "GraphUtil.h" #include "VertexWeightedGraph.h" +#include + namespace Graph { GraphCreator::GraphCreator(){ } @@ -112,13 +114,12 @@ namespace Graph { for(it = probs->begin(); it != probs->end(); it++){ //compute which actors have a given attribute vector connect; - for(int i = 0; i < n; i++){ + for(unsigned long i = 0; i < n; i++){ if(lcgrand(0) < *it){ connect.push_back(i); } } //attach these actors to the graph - // CSG - if you call size over and over here this will be sloooow! int conn_size = connect.size(); for(int i = 0; i < conn_size; i++){ for(int j = i + 1; j < conn_size; j++){ @@ -405,6 +406,133 @@ namespace Graph { return wmg; } + /** + * Creates a graph G with vertex set equal to the set in the members list. + * The entries in the members list are the positions in the nodes[] array. + * The edges in G are created by constructing the subgraph induced + * by the members list. If make_simple is true, then the resulting graph + * is guaranteed to be simple. + */ + Graph *GraphCreator::create_induced_subgraph(Graph *g, list *members, bool make_simple){ + Graph *wmg = new Graph(members->size()); + // The caller of g function is responsible for allocating a Graph + // of the appropriate size - make sure! + + if(wmg->capacity != (int) (((members->size())))){ + fatal_error( + "%s: Graph of members->size() must be allocated before calling\ncreate_component\n", + __FUNCTION__); + } + + // Sort the members - not necessary, but convenient? + members->sort(); + // Create a subgraph_labels[] array and a graph_indices[] + // array + + int *subgraph_labels = new int[members->size()]; + memset(subgraph_labels, GD_UNDEFINED, members->size() * sizeof(int)); + int *graph_indices = new int[g->capacity]; + memset(graph_indices, GD_UNDEFINED, g->capacity * sizeof(int)); + list::iterator i, j; + int k = 0; + for(i = members->begin(); i != members->end(); ++i){ + subgraph_labels[k] = g->nodes[*i].label; + graph_indices[*i] = k; + k++; + } + + k = 0; + int new_i, new_j; + // Use g for make_simple checking + char *neighbor_vec = new char[g->capacity]; + bool multiple_edges = false; + wmg->num_edges = 0; + for(i = members->begin(); i != members->end(); ++i){ + memset(neighbor_vec, 0, g->capacity * sizeof(char)); + new_i = graph_indices[*i]; + if(new_i == GD_UNDEFINED){ + fatal_error( + "%s: Encountered GD_UNDEFINED entry for new_i at position %d in graph_indices array\n", + __FUNCTION__, *i); + } + + wmg->nodes[new_i].label = subgraph_labels[k]; + for(j = g->nodes[*i].nbrs.begin(); j != g->nodes[*i].nbrs.end(); ++j){ + // We have an edge between *i and *j in the original graph + // g should be stored as an edge between + // graph_indices[*i] and graph_indices[*j] in the subgraph + + new_j = graph_indices[*j]; + print_message(1, "Translating old edge %d-%d to new edge %d-%d\n", + *i, *j, new_i, new_j); + + if(new_j == GD_UNDEFINED){ + print_message( + 1, + "%s: Encountered GD_UNDEFINED entry for new_j at position %d in graph_indices array\n", + __FUNCTION__, *j); + } + else { + if(new_i <= new_j){ + if(!make_simple || (neighbor_vec[*j] == 0) ){ + if(neighbor_vec[*j] == 1){ + // We are adding a duplicate edge to G - G will not be simple + multiple_edges = true; + } + // CSG added make_simple functionality - just check if we have seen g edge before by checking + // the neighbor_vec + wmg->num_edges++; + wmg->nodes[new_i].nbrs.push_back(new_j); + if(new_i != new_j){ // added check Dec 29 + wmg->nodes[new_j].nbrs.push_back(new_i); + } + } + } + } + neighbor_vec[*j] = 1; + } + // k is used for the subgraph labels + k++; + } + // If the original was simple, G will be. If make_simple, then it had better be simple! + // Otherwise, unknown. + if((g->simple == GD_TRUE) || make_simple){ + wmg->simple = GD_TRUE; + } + else { + wmg->simple = false; + wmg->canonical = false; + } + if(multiple_edges){ + wmg->simple = false; + wmg->canonical = false; + } + // We don't know number of components + wmg->num_connected_components = GD_UNDEFINED; + GraphUtil util; + util.recompute_degrees(wmg); + + delete[] subgraph_labels; + delete[] graph_indices; + delete[] neighbor_vec; + + return wmg; + } // create_induced_subgraph + + /** + * Creates the subgraph G induced by the members list where it is known + * that g subgraph is a connected component. Sets G->num_components=1 + * although g is not verified! If make_simple is true, then the component + * is guaranteed to be simple. + */ + Graph *GraphCreator::create_component(Graph *g, list *members, bool make_simple){ + Graph *comp; + comp = create_induced_subgraph(g, members, make_simple); + // Set num_connected_components to 1 since g is known - not verified - should it be?? + comp->num_connected_components = 1; + return comp; + } + /** * Fills the provided list with graphs that correspond to the connected * components of the graph. Sets num_connected_components to the correct value diff --git a/lib_graphd/src/GraphProperties.cpp b/lib_graphd/src/GraphProperties.cpp index 8c6e597..a5cc763 100644 --- a/lib_graphd/src/GraphProperties.cpp +++ b/lib_graphd/src/GraphProperties.cpp @@ -20,14 +20,20 @@ */ #include "GraphDecomposition.h" -//No longer used 7/22/13 -//#include +#include "Log.h" #include #if !WIN32 #include #endif +#include +#include +#include + #include +#ifdef HAS_SLEPC + #include +#endif namespace Graph { GraphProperties::GraphProperties(){ @@ -616,6 +622,83 @@ namespace Graph { global_cc = (double)num_triangles / (double)total_possible_triangles; } // clustering_coefficients + #ifdef HAS_BOOST + /** + * We assume that edge weights are all 1 + * + * \param[in] g input graph + * \param[in] source node id + * \param[out] p path distances from source to all other vertices + */ + void GraphProperties::paths_dijkstra_boost_single(Graph *g, vector &dists, vector &preds, int source){ + BoostUndirected *bg = g->boost_graph; + //std::vector p(boost::num_vertices(*bg)); + dists.resize(g->get_num_nodes()); + //std::vector d(boost::num_vertices(*bg)); + vertex_descriptor s = vertex(source, *bg); + boost::dijkstra_shortest_paths(*bg, s, boost::predecessor_map(&preds[0]).distance_map(&dists[0]).distance_inf(INDDGO_INFINITY)); + int i; + //for(i=0;i > &pAll){ + int inf = INDDGO_INFINITY; + int minD = inf; + + const int n = g->get_num_nodes(); + + std::vector betweenness_counts(n, 0); + std::vector betweenness(n, 0.0); + + pAll.resize(n); + + //#pragma omp parallel for default(none) shared(g, inf, pAll) private(nvisiting, nVisited, nv) firstprivate(dist, minD, visited) + #pragma omp parallel default(none) shared(g, inf, betweenness_counts, pAll) + { + std::vector p(boost::num_vertices(*(g->boost_graph))); + int i; + #pragma omp for schedule(dynamic, 8) + for(int v = 0; v < n; v++){ + //reset all distances to INF and mark all vertices as unvisited + fill(pAll[v].begin(),pAll[v].end(),inf); + paths_dijkstra_boost_single(g, pAll[v], p, v); //stores shortest paths from this vertex to all in pAll[v] + } + } + //store the results + g->set_shortest_path_dist(&pAll); + } // paths_dijkstra_boost_all + + /** + * Calculate the relative betweenness centrality for all nodes + * \param[in] g input graph + * \param[out] bc vector with one BC value for each vertex + */ + + void GraphProperties::betweenness_centrality(Graph *g, vector &bc){ + BoostUndirected *bg = g->boost_graph; + bc.resize(g->get_num_nodes()); + //boost::brandes_betweenness_centrality(*bg, get(boost::vertex_centrality, *bg)); + boost::brandes_betweenness_centrality(*bg, + boost::centrality_map( + boost::make_iterator_property_map(bc.begin(), get(boost::vertex_index, *bg), double())).vertex_index_map(get(boost::vertex_index, *bg) + ) + ); + + boost::relative_betweenness_centrality(*bg, + boost::make_iterator_property_map(bc.begin(), get(boost::vertex_index, *bg), double())); + g->set_betweenness(bc); + } + + #endif // ifdef HAS_BOOST + /** * \param[in] g input graph * \param[in] source node id @@ -623,8 +706,7 @@ namespace Graph { */ void GraphProperties::paths_dijkstra_single(Graph *g, vector &p, int source){ - //int inf = 100000; - int inf = INT_MAX; + int inf = INDDGO_INFINITY; int nVisited = 0; int minD; int nvisiting; @@ -686,7 +768,7 @@ namespace Graph { */ void GraphProperties::paths_dijkstra_all(Graph *g, vector< vector > &pAll){ - int inf = INT_MAX; + int inf = INDDGO_INFINITY; int minD = inf; const int n = g->get_num_nodes(); @@ -694,7 +776,7 @@ namespace Graph { pAll.resize(n); //#pragma omp parallel for default(none) shared(g, inf, pAll) private(nvisiting, nVisited, nv) firstprivate(dist, minD, visited) - #pragma omp parallel for default(none) shared(g, inf, pAll) + #pragma omp parallel for schedule(dynamic, 8) default(none) shared(g, inf, pAll) //loop over all vertices for(int v = 0; v < n; v++){ //0; v < n; v++){ //reset all distances to INF and mark all vertices as unvisited @@ -703,7 +785,7 @@ namespace Graph { } //end loop over vertices //store the results - g->set_shortest_path_dist(pAll); + g->set_shortest_path_dist(&pAll); //print out results //for(int i = 0; i < n; i++){ @@ -722,7 +804,7 @@ namespace Graph { */ void GraphProperties::eccentricity(Graph *g, vector &ecc){ const int n = g->get_num_nodes(); - vector< vector > short_paths = g->get_shortest_path_dist_ref(); //computes if not already + const vector< vector > &short_paths = g->get_shortest_path_dist_ref(); //computes if not already int bestMax = 0; ecc.resize(n); @@ -755,13 +837,11 @@ namespace Graph { eccentricity(g,ecc); } + freq_ecc.resize(*(std::max_element(ecc.begin(), ecc.end())) + 1); + //compute diameter of each vertex int eccsize = ecc.size(); - // This could be slow with resizing for(int i = 0; i < eccsize; i++){ - if(ecc[i] > freq_ecc.size() ){ - freq_ecc.resize(ecc[i] + 1); //because vector numbering starts at 0 - } freq_ecc[ecc[i]]++; //add to tally for this diameter size } //printf("Graph diameter is %d\n", freq_ecc.size()-1); @@ -782,14 +862,18 @@ namespace Graph { */ void GraphProperties::expansion(Graph *g, vector &norm_hops){ const int n = g->get_num_nodes(); - vector< vector > short_paths = g->get_shortest_path_dist_ref(); //computes if not already + const vector< vector > &short_paths = g->get_shortest_path_dist_ref(); //computes if not already vector hops(n,0); //largest possible dist is n-1 norm_hops.resize(n); + int k; //for each vertex, find the number of vertices reachable for all hops; add to tally for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ - hops[ short_paths[i][j] ]++; + k = short_paths[i][j]; + if(k != INDDGO_INFINITY){ + hops[k]++; + } } } @@ -798,7 +882,7 @@ namespace Graph { #pragma omp parallel for default(none) shared(norm_hops, hops) for(int h = 1; h < n; h++){ - norm_hops[h] = (double)hops[h] / (n * (n - 1)); + norm_hops[h] = (double)hops[h] / ((double)n * (n - 1)); //printf("h = %d and number is %d; norm value is %f\n",h,hops[h],norm_hops[h]); } } //expansion @@ -810,16 +894,15 @@ namespace Graph { */ void GraphProperties::diameter(Graph *g, int &diam){ int i, j, size, temp; - vector< vector > dist_mat; - - paths_dijkstra_all(g, dist_mat); + const vector< vector > &dist_mat = g->get_shortest_path_dist_ref(); //computes if not already size = dist_mat.size(); diam = dist_mat[0][0]; for(i = 0; i < size; i++){ for(j = 0; j < i; j++){ temp = dist_mat[i][j]; - if((temp > diam) && (temp < INT_MAX)){ + + if((temp > diam) && (temp < INDDGO_INFINITY)){ diam = temp; } } @@ -836,16 +919,14 @@ namespace Graph { int i, j, d, size, temp, diam = 0; int n0, numer, tot_con_pairs = 0; float gd; - vector< vector > dist_mat; + const vector< vector > &dist_mat = g->get_shortest_path_dist_ref(); //computes if not already vector bins (g->num_nodes, 0); - paths_dijkstra_all(g, dist_mat); - size = dist_mat.size(); for(i = 0; i < size; i++){ for(j = 0; j < i; j++){ temp = dist_mat[i][j]; - if(temp < INT_MAX){ + if(temp < INDDGO_INFINITY){ tot_con_pairs++; if(temp > diam){ diam = temp; @@ -893,6 +974,39 @@ namespace Graph { ad = (2.0 * E) / V; } + void GraphProperties::avg_path_length(Graph *g, double &pl){ + const uint64_t n = g->get_num_nodes(); + const vector< vector > &short_paths = g->get_shortest_path_dist_ref(); + double sum = 0; + uint64_t intermediate = 0; + int i, j; + int inf_path = 0; + + #pragma omp parallel for default(none) reduction(+:inf_path) private(j) shared(short_paths) + for(i = 0; i < n; i++){ + for(j = 0; j < n; j++){ + if(INDDGO_INFINITY == short_paths[i][j]){ + inf_path++; + } + } + } + + #pragma omp parallel for default(none) private(j, intermediate) reduction(+:sum) shared(short_paths, inf_path, std::cout) + for(i = 0; i < n; i++){ + intermediate = 0; + for(j = 0; j < n; j++){ + if(INDDGO_INFINITY != short_paths[i][j]){ + intermediate += short_paths[i][j]; + } + } + sum += (double)(intermediate / (double)((n * (n - 1)) - inf_path)); + //cout << "For node " << i << " got sum " << sum << endl; + //sum = sum / (double)((n * (n - 1)) - inf_path); + } + cout << "Got a SUM: " << sum << endl; + pl = sum; + } // avg_path_length + /** * Calculates the degree distribution of graph g * \param[in] g Pointer to a graph @@ -911,6 +1025,131 @@ namespace Graph { } } + #ifdef HAS_BOOST + /** + * Fits the degree distribution of g to a power law distribution + * \param[in] g Pointer to a graph + * \param[out] xmin Integer value holding the degree at which the data begins behaving like a power law + * \param[out] alpha Double holding the most likely value for the exponent + * \param[out] KS Double holding the Kolmogorov-Smirnov statistic + * \param[in] start Lower bound for exponent, defaults to 1.5 + * \param[in] inc Determines granularity of the exponent search range, defaults to 0.01 + * \param[in] end Upper bound for exponent, defaults to 3.5 + */ + void GraphProperties::powerlaw(Graph *g, int &xmin, double &alpha, double &KS, double start, double inc, double end){ + int xm, i, k, n, I; + int prev, pprev; + int size = 1 + (int)(end - start) / inc; + double slogz, L, MLE; + double znorm, denom; + double f, fn, D, tD; + double exp; + + vector x(g->degree); + + //Holds the possible \alpha values from start to end with a delta of inc + vector< double > vec( size ); + //Holds the zeta of the \alpha values, since it is used a lot, no need to keep calculating + vector< double > zvec( size ); + f = start; + for(i = 0; i < size; i++ ){ + vec[i] = f; + zvec[i] = boost::math::zeta(f); + f += inc; + } + + sort(x.begin(), x.end()); + + KS = -1; + prev = 0; + for( xm = 0; xm < x.size(); xm++ ){ + if(x[xm] == prev){ + continue; + } + + n = x.size() - xm; + + slogz = 0; + for(i = xm; i < x.size(); i++){ + slogz += log(x[i]); + } + + //MLE loop: for each possible \alpha value in the specified grid with the current test xmin + // calculate the log-likelihood, normalizing the Hurwitz zeta to the Riemann zeta + MLE = -1; + I = 0; + for( k = 0; k < vec.size(); k++ ){ + exp = vec[k]; + + znorm = 0; + for(i = 1; i < x[xm]; i++){ + znorm += pow(i, -exp); + } + + L = -exp * slogz - n * log( zvec[k] - znorm ); + + if(MLE != -1){ + if(L > MLE){ + MLE = L; + I = k; + } + } + else { + MLE = L; + I = k; + } + } + + //compute KS statistic + exp = vec[I]; + + znorm = 0; + for(i = 1; i < x[xm]; i++){ + znorm += pow(i, -exp); + } + denom = zvec[I] - znorm; + + pprev = 0; + fn = f = 0; + D = 0; + for(i = xm; i < x.size(); i++){ + if(x[i] == pprev){ + continue; + } + + //CDF (f) and EDF (fn) + for(k = i; k < x.size() && x[k] <= x[i]; k++){ + fn += (1.0) / n; + } + f += pow(x[i], -exp) / denom; + + tD = abs(fn - f); + if(tD > D){ + D = tD; + } + + pprev = x[i]; + } + + if(KS > -1){ + if(D < KS){ + KS = D; + xmin = x[xm]; + alpha = exp; + } + } + else { + KS = D; + xmin = x[xm]; + alpha = exp; + } + + prev = x[xm]; + } + } // powerlaw + + #endif // ifdef HAS_BOOST + /** * Calculates the degree assortativity of a graph g * \param[in] g input graph @@ -947,4 +1186,441 @@ namespace Graph { coeff = (n1 - n2) / (de - n2); } // deg_assortativity + + /** + * Calculates the delta hyperbolicity of a graph g and returns the hyperbolicity distribution + * \param[in] g Pointer to a graph + * \param[out] mex_delta Double value holding the maximum delta value encountered + * \param[out] delta Vector of vectors of doubles holding the delta hyperbolicity distribution + */ + void GraphProperties::delta_hyperbolicity(Graph *g, double &max_delta, vector > &delta){ + const vector< vector > &dist_mat = g->get_shortest_path_dist_ref(); + int size = dist_mat.size(); + int mat_size = dist_mat.size(); + int counter = 0; + int row = 0; + int diam; + + if(g->num_nodes < 4){ + cerr << "Graph is too small for hyperbolicity, returning zero\n"; + vector delta_vec(1, 0); + delta.push_back(delta_vec); + return; + } + + if(!is_connected(g)){ + cerr << "Graph passed to calc_gromov has multiple components\n"; + + //Find the largest connected component + int temp = 0; + size = 0; + for(int i = 0; i < mat_size; i++){ + temp = 0; + for(int j = 0; j < mat_size; j++){ + if(dist_mat[i][j] != INDDGO_INFINITY){ + temp++; + } + } + //temp++; //count the vertex currently being tested + if(temp > size){ + size = temp; + row = i; + } + } + } + + //build vertex set of largest connected component and find its diameter + int temp_diam = 0; + vector vert_vec(size); + for(int j = 0; j < mat_size; j++){ + if(dist_mat[row][j] != INDDGO_INFINITY){ + vert_vec[counter] = j; + counter++; + if(dist_mat[row][j] > temp_diam){ + temp_diam = dist_mat[row][j]; + } + } + else if(j == row){ + vert_vec[counter] = j; + counter++; + } + } + diam = temp_diam; + + max_delta = 0; + + for(int i = 0; i < diam; i++){ + vector zero_dist(2 * diam + 1,0); + delta.push_back(zero_dist); + } + + int num_threads = omp_get_max_threads(); + + //////////////////////////////////////////////////////////// + //These are the shared variables between threads. Each thread has access to a certain pointer. + //The pointer should then point to a copy of the variable for the thread's private (local) use. + //Shared max_delta and shared_delta are updated by each thread, must be careful to avoid contention. + //////////////////////////////////////////////////////////// + + int size_of_array = 64 / sizeof(double *); //64 is cacheline size, needs to be updated on different machines for performance + int type_size = sizeof(double *); + if(type_size < sizeof(vector< vector > *)){ + type_size = sizeof(vector< vector > *); + } + + counter = 1; + while(num_threads * type_size > size_of_array){ + ++counter; + size_of_array = counter * 64 / sizeof(double *); + } + + //////////////////////////////////////////////////////////// + //Pointers to shared data arrays that have copy of the delta information for each thread, + //ie, if there are 8 threads, there will be an 8 (pointers to) arrays each accessed by only one thread, + //At the end of the parallel section of code, the 8 arrays will be combined into a single array + /////////////////////////////////////////////////////////// + + double **shared_max_delta; + shared_max_delta = new double * [size_of_array]; + + vector< vector > **shared_delta; + shared_delta = new vector< vector > * [size_of_array]; + + #if defined (TASK_PROFILE) || defined(TASK_PROFILE_OVERHEAD) + int num_tasks1[1024][1024]; + int num_tasks2[1024][1024]; + int num_tasks1_switch[1024][1024]; + int num_tasks2_switch[1024][1024]; + int total_threads = 0; + double task_time[1024][512]; + double time_starts = 0.0; + double time_stops = 0.0; + #endif + + //OMP parallel region, this current implementation generates tasks at two of the four levels of the nested for loop, + // these tasks are then passed to threads which execute them and update their private copy of the results array + //After the tasks have all been generated and executed the results are collated + #pragma omp parallel shared(delta, max_delta, shared_max_delta, diam, shared_delta, dist_mat, vert_vec, size) + { + double max_delta_loc = 0; + + vector zero_dist(2 * diam + 1,0); + zero_dist.reserve(256 / sizeof(double)); + + vector< vector > delta_loc(diam,zero_dist); + + int thread_id = omp_get_thread_num(); + + #ifdef TASK_PROFILE + num_tasks1[thread_id][0] = 0; + num_tasks2[thread_id][0] = 0; + num_tasks1_switch[thread_id][0] = 0; + num_tasks2_switch[thread_id][0] = 0; + int total_threads = 0; + #endif + #ifdef TASK_PROFILE_OVERHEAD + task_time[thread_id][0] = 0.0; + #endif + + shared_max_delta[thread_id] = &max_delta_loc; + + shared_delta[thread_id] = &delta_loc; + + //size_t size = vert_vec.size(); + + #pragma omp single + { + #ifdef TASK_PROFILE_OVERHEAD + time_starts = omp_get_wtime(); + #endif + + for(int i = 0; i < size; ++i){ + #if defined (TASK_PROFILE) || defined (TASK_PROFILE_OVERHEAD) + #pragma omp task shared(shared_delta, shared_max_delta, dist_mat, vert_vec, size, num_tasks1, num_tasks2, task_time) + #else + #pragma omp task shared(shared_delta, shared_max_delta, dist_mat, vert_vec, size) + #endif + { + #ifdef TASK_PROFILE + int thread_id = omp_get_thread_num(); + num_tasks1[thread_id][0]++; + #endif + #ifdef TASK_PROFILE_OVERHEAD + double tt1 = omp_get_wtime(); + #endif + + for(int j = i + 1; j < size; ++j){ + #if defined (TASK_PROFILE) || defined (TASK_PROFILE_OVERHEAD) + #pragma omp task shared(shared_delta, shared_max_delta, dist_mat, vert_vec, size, num_tasks1, num_tasks2, task_time) + #else + #pragma omp task shared(shared_delta, shared_max_delta, dist_mat, vert_vec, size) + #endif + { + int thread_num = omp_get_thread_num(); + + #ifdef TASK_PROFILE + num_tasks2[thread_num][0]++; + #endif + #ifdef TASK_PROFILE_OVERHEAD + double ttt1 = omp_get_wtime(); + #endif + + vector > &loc_delta = *shared_delta[thread_num]; + + double &max_delta_loc = *shared_max_delta[thread_num]; + + for(int k = j + 1; k < size; ++k){ + for(int l = k + 1; l < size; ++l){ + const int ui = vert_vec[i]; + + const int vi = vert_vec[j]; + const int uv = (dist_mat)[ui][vi]; + + const int xi = vert_vec[k]; + const int ux = (dist_mat)[ui][xi]; + const int vx = (dist_mat)[vi][xi]; + + const int yi = vert_vec[l]; + const int uy = (dist_mat)[ui][yi]; + const int vy = (dist_mat)[vi][yi]; + const int xy = (dist_mat)[xi][yi]; + + const int s1 = uv + xy; + const int s2 = ux + vy; + const int s3 = uy + vx; + + double currDelta = 0; + unsigned long maxPair = 1; + + //find max pair distance + maxPair = uv; + + if(xy > maxPair){ + maxPair = xy; + } + + if(ux > maxPair){ + maxPair = ux; + } + + if(vy > maxPair){ + maxPair = vy; + } + + if(uy > maxPair){ + maxPair = uy; + } + + if(vx > maxPair){ + maxPair = vx; + } + + //Delta calculations + + if((s1 >= s2) && (s3 >= s2) ){ + currDelta = abs(s1 - s3) / 2.0; //works since s1 and s2 are positive + } + else if((s2 >= s1) && (s3 >= s1) ){ + currDelta = abs(s2 - s3) / 2.0; + } + else { + currDelta = abs(s1 - s2) / 2.0; + } + + ++(loc_delta)[maxPair - 1][2 * currDelta + 1]; + + if(currDelta > max_delta_loc){ + max_delta_loc = currDelta; + } + + ++(loc_delta)[maxPair - 1][0]; + } + } + + #ifdef TASK_PROFILE_OVERHEAD + double ttt2 = omp_get_wtime(); + task_time[thread_num][0] += (ttt2 - ttt1); + #endif + #ifdef TASK_PROFILE + int thread_id_end = omp_get_thread_num(); + if(thread_id != thread_id_end){ + num_tasks2_switch[thread_id_end][0]++; + } + #endif + } // end task + } + + #ifdef TASK_PROFILE_OVERHEAD + //double tt2 = omp_get_wtime(); + //task_time[thread_id][0]+= (tt2 - tt1); + #endif + #ifdef TASK_PROFILE + int thread_id_end = omp_get_thread_num(); + if(thread_id != thread_id_end){ + num_tasks1_switch[thread_id_end][0]++; + } + #endif + } // end task + } + } // end single + + #ifdef TASK_PROFILE_OVERHEAD + #pragma omp single nowait + { + time_stops = omp_get_wtime(); + } + #endif + + double t1 = time(NULL); + + #pragma omp critical (collate_delta) + { + int thread_num = omp_get_thread_num(); + vector > *delta_point = shared_delta[thread_num]; + vector > &loc_delta = *delta_point; + + int i_size = loc_delta.size(); + for(int i = 0; i < i_size; ++i){ + int j_size = loc_delta[i].size(); + for(int j = 0; j < j_size; ++j){ + delta[i][j] += loc_delta[i][j]; + } + } + + if(max_delta_loc > max_delta){ + max_delta = max_delta_loc; + } + } + + double t2 = time(NULL); + + #pragma omp single + { + cout << "Critical Region time: " << t2 - t1 << "\n"; + } + } //END OF FIRST PRAGMA + + //take care of pointer! + delete [] shared_delta; + delete [] shared_max_delta; + + //Needs removed before parallel code is implemented + for(int i = 0; i < diam; ++i){ + delta[i].erase(delta[i].begin() + 2 * max_delta + 2, delta[i].end()); + } + + #if defined (TASK_PROFILE) || defined (TASK_PROFILE_OVERHEAD) + + #pragma omp parallel shared(total_threads) + { + #pragma omp master + { + total_threads = omp_get_num_threads(); + } + } + + cout << endl << endl << "******Tasks Statistics: (num_task, num_tasks, migrated_tasks, switched_task, task_time)" << endl; + + for(int i = 0; i < total_threads; i++){ + cout << i + #endif + #ifdef TASK_PROFILE + << "," << num_tasks1[i][0] << "," << num_tasks2[i][0] << "," << num_tasks1_switch[i][0] << "," << num_tasks2_switch[i][0] + #endif + #ifdef TASK_PROFILE_OVERHEAD + << "," << task_time[i][0] + #endif + #if defined (TASK_PROFILE) || defined (TASK_PROFILE_OVERHEAD) + << endl; + } // delta_hyperbolicity + + cout << endl; + + #endif + #ifdef TASK_PROFILE_OVERHEAD + cout << "Time in task region = " << time_stops - time_starts << endl; + #endif + } // delta_hyperbolicity + + #ifdef HAS_PETSC + /** + * Built in self tester for the eigen solver. Looks at Ax - yx and looks for the + * largest magnitude of error. + */ + void check_eigen_values(Mat A, Vec eigen_vec, PetscScalar eigen_val){ + Vec xr, xi, xr2, result1, result2; + MatGetVecs(A, PETSC_NULL, &xr2); + MatGetVecs(A, PETSC_NULL, &result1); + MatGetVecs(A, PETSC_NULL, &result2); + + cout << "Eigen vector is:\n"; + VecView(eigen_vec,PETSC_VIEWER_STDOUT_SELF); + cout << "Eigen value is: " << eigen_val << endl; + + MatMult(A,eigen_vec,result1); + VecSet(xr2,eigen_val); + VecPointwiseMult(result2,xr2,eigen_vec); + cout << "Ax = " << endl; + VecView(result1,PETSC_VIEWER_STDOUT_SELF); + cout << "yx = " << endl; + VecView(result1,PETSC_VIEWER_STDOUT_SELF); + PetscScalar *a; + PetscScalar *b; + VecGetArray(result1, &a); + VecGetArray(result2, &b); + PetscInt size; + VecGetLocalSize(result1, &size); + double max = 0.0,current; + for(int idx = 0; idx < size; idx++){ + current = fabs(a[idx] - b[idx]); + max = current > max ? current : max; + } + cout << "Magnitude of greatest error is: " << max << endl; + VecRestoreArray(result1, &a); + VecRestoreArray(result2, &b); + } // check_eigen_values + + /** + * looks for eigen values in the adjacency matrix + * \param[in] g input graph + * \param[out] eigen_values vector of eigen values found + * \param[in] spread the number of values wanted, spread high values and spred low values, so eigen_values can be upto 2*spread in size + */ + void GraphProperties::eigen_spectrum(Graph *g, vector &eigen_values, int spread){ + #ifndef HAS_SLEPC + fatal_error("Called SLEPC eigen solvers without HAS_SLEPC.\n"); + #else + GraphUtil graph_util; + graph_util.populate_PetscMat(g); + EPS eps; + PetscInt nconv; + PetscScalar kr,ki; + EPSCreate(PETSC_COMM_WORLD, &eps); + EPSSetType(eps, EPSPOWER); + EPSSetOperators(eps,g->PetscMat,PETSC_NULL); + EPSSetLeftVectorsWanted(eps,PETSC_TRUE); + EPSSetFromOptions(eps); + EPSSetDimensions(eps,spread * 2,spread * 8,spread * 8); + EPSSolve(eps); + EPSGetConverged(eps,&nconv); + EPSGetConverged(eps,&nconv); + eigen_values.resize(nconv); + for(int idx = 0; idx < nconv; idx++){ + EPSGetEigenvalue(eps,idx,&kr,&ki); + eigen_values[idx] = kr; + #ifdef EIGENSOLVER_SELFTEST + //built in self tester. Don't use in production runs. + Vec xr, xi; + MatGetVecs(g->PetscMat, PETSC_NULL, &xr); + MatGetVecs(g->PetscMat, PETSC_NULL, &xi); + EPSGetEigenpair(eps,idx,&kr,&ki, xr, xi); + check_eigen_values(g->PetscMat, xr, kr); + #endif + } + EPSDestroy(&eps); + + #endif // ifndef HAS_SLEPC + } // eigen_spectrum + + #endif // ifdef HAS_PETSC } diff --git a/lib_graphd/src/GraphReader.cpp b/lib_graphd/src/GraphReader.cpp index 34be2b3..66267ad 100644 --- a/lib_graphd/src/GraphReader.cpp +++ b/lib_graphd/src/GraphReader.cpp @@ -136,8 +136,7 @@ namespace Graph { } } } - // CSG - what should this return? - return 1; + return 0; } // read_adjlist /** diff --git a/lib_graphd/src/GraphUtil.cpp b/lib_graphd/src/GraphUtil.cpp index 729f5bf..6b2d56f 100644 --- a/lib_graphd/src/GraphUtil.cpp +++ b/lib_graphd/src/GraphUtil.cpp @@ -19,8 +19,18 @@ */ +#include "GraphUtil.h" #include "GraphDecomposition.h" +#ifdef HAS_BOOST + #include + #include + #include + + #include "boost/graph/adjacency_list.hpp" + #include "boost/graph/topological_sort.hpp" +#endif + namespace Graph { GraphUtil::GraphUtil(){ } @@ -498,6 +508,89 @@ namespace Graph { g->adjncy.clear(); } + #ifdef HAS_BOOST + /** + * Populates the boost_graph member of g + * \param[in] g the input graph + */ + void GraphUtil::populate_boost(Graph *g){ + const int n = g->get_num_nodes(); + int v; + boost::graph_traits < BoostUndirected >::vertex_descriptor a, b; + list::const_iterator it; + g->boost_graph = new BoostUndirected(n); + BoostUndirected *bg = g->boost_graph; + for(v = 0; v < n; v++){ + const list &nbrs = g->get_node(v)->get_nbrs_ref(); + for(it = nbrs.begin(); it != nbrs.end(); ++it){ + if(v < *it){ + a = boost::vertex(v, *bg); + b = boost::vertex(*it, *bg); + boost::add_edge(a, b, 1, *bg); + } + } + } + } // populate_boost + + #endif //HAS_BOOST + + #ifdef HAS_PETSC + /** + * Populates the PetscMat member of graph g. This function will also call populate_CRS() if it hasn't been already. + * Durring cleanup a free_CRS() also needs to be done. + * \param[in] g the input graph + */ + void GraphUtil::populate_PetscMat(Graph *g){ + if(g->adjncy.size() == 0){ + populate_CRS(g); + } + int start, end; + + //Matrix is g->PetscMat + PetscErrorCode ierror; + ierror = MatCreate(PETSC_COMM_WORLD,&(g->PetscMat)); + CHKERRABORT(PETSC_COMM_WORLD,ierror); + ierror = MatSetSizes(g->PetscMat,PETSC_DECIDE,PETSC_DECIDE,g->num_nodes,g->num_nodes); + CHKERRABORT(PETSC_COMM_WORLD,ierror); + ierror = MatSetFromOptions(g->PetscMat); + CHKERRABORT(PETSC_COMM_WORLD,ierror); + ierror = MatSetUp(g->PetscMat); + CHKERRABORT(PETSC_COMM_WORLD,ierror); + int row, col, size; + const PetscScalar one_val = 1; + for(int node = 0; node < g->num_nodes; node++){ + start = g->xadj[node]; + end = g->xadj[node + 1]; + size = 1 + end - start; + row = node; + PetscScalar ones[size]; + PetscInt columns[size]; + for(int idx = 0; idx < size; idx++){ + ones[idx] = 1.0; + columns[idx] = g->adjncy[start + idx]; + } + ierror = MatSetValues(g->PetscMat, 1, &row, size, columns, ones, INSERT_VALUES); + CHKERRABORT(PETSC_COMM_WORLD,ierror); + } + + ierror = MatAssemblyBegin(g->PetscMat,MAT_FINAL_ASSEMBLY); + CHKERRABORT(PETSC_COMM_WORLD,ierror); + ierror = MatAssemblyEnd(g->PetscMat,MAT_FINAL_ASSEMBLY); + CHKERRABORT(PETSC_COMM_WORLD,ierror); + } // populate_PetscMat + + /** + * Frees the PetscMat member of g. This function will not cleanup CRS, even if populate_PetscMat() filled it. + * You will have to also call free_CRS(); + * \param[in] g the input graph + */ + void GraphUtil::free_PetscMat(Graph *g){ + PetscErrorCode ierror = MatDestroy(&(g->PetscMat)); + CHKERRABORT(PETSC_COMM_WORLD,ierror); + } + + #endif // ifdef HAS_PETSC + /** * Non-recursive function that fills the members vector with the * lists of nodes belonging to the components. The members vector @@ -1033,7 +1126,6 @@ namespace Graph { break; } } - (*kcore)[v] = k = max(k,deg_lookup[v]); last_deg = max(0, deg_lookup[v] - 1); deg_lookup[v] = -1; @@ -1055,6 +1147,44 @@ namespace Graph { delete [] depth; return k; } // find_degen + + /** + * \input g input graph + * \output new graph consisting of largest component, or NULL if the input graph is connected + * NOTE: this function *will* canonicalize your graph!!! + **/ + Graph *GraphUtil::get_largest_component_graph(Graph *g){ + GraphProperties properties; + GraphCreatorFile creator; + Graph *largecomp; + list *maxlist = NULL; + size_t maxlen = 0; + + if(!properties.is_connected(g)){ + properties.make_canonical(g); + vector *> members; + vector *>::iterator vlit; + find_all_components(g, &members); + // traverse the list and find the one with the most members + for(vlit = members.begin(); vlit != members.end(); ++vlit){ + //cout << "Got list with size: " << ((*vlit)->size()) << endl; + if(((*vlit)->size()) >= maxlen){ + maxlen = (*vlit)->size(); + //cout << "New list with maxlen > " << maxlen << endl; + maxlist = *vlit; + //cout << maxlist << endl; + } + } + + // found the max component, let's create the graph + largecomp = creator.create_component((Graph *)g, maxlist, true); + return largecomp; + } + else { + return NULL; + } + } // get_largest_component_graph + } using namespace std; /** diff --git a/lib_graphd/src/Makefile b/lib_graphd/src/Makefile index 1339dd6..db2e9af 100644 --- a/lib_graphd/src/Makefile +++ b/lib_graphd/src/Makefile @@ -10,9 +10,9 @@ LIBNAME = libgraphd.a GVIZ=../bin/gviz # include directories -INCLUDES = -I../inc/ -I/usr/local/include $(METIS_INCLUDES) $(SSPARSE_INCDIR) $(PARMETIS_INCDIR) +INCLUDES = -I../inc/ -I/usr/local/include $(METIS_INCLUDES) $(SSPARSE_INCDIR) $(PARMETIS_INCDIR) $(PETSC_INCDIR) $(SLEPC_INCDIR) # libraries -LIBS = -L/usr/local/lib $(INDDGO_LIB) $(SSPARSE_LIB) -lm $(METIS_LIB) $(PARMETIS_LIB) +LIBS = -L/usr/local/lib $(INDDGO_LIB) $(SSPARSE_LIB) -lm $(METIS_LIB) $(PARMETIS_LIB) $(SLEPC_LIB) $(PETSC_LIB) # source SRC := Log.cpp GraphReader.cpp Node.cpp \ GraphCreator.cpp GraphCreatorFile.cpp Graph.cpp VertexWeightedGraph.cpp GraphProperties.cpp \ diff --git a/lib_graphd/src/Util.cpp b/lib_graphd/src/Util.cpp index f280f05..c3a0e12 100644 --- a/lib_graphd/src/Util.cpp +++ b/lib_graphd/src/Util.cpp @@ -24,6 +24,7 @@ #include #include #include +#include /*BDS - added to get memory highwater mark*/ int parseLine(char *line){ @@ -845,6 +846,11 @@ void split(const std::string& s, char sep, vector& v){ } } // split +/** + * Write a degree distribution out to file. + * \param[in] filename filename to write output to + * \param[in] dist a vector, indexed on degree + */ void write_degree_distribution(string filename, const vector &dist){ ofstream outfile; @@ -856,10 +862,217 @@ void write_degree_distribution(string filename, const vector &dist){ else { int i; for(i = 0; i < dist.size(); i++){ - outfile << dist[i] << "\n"; + outfile << i << " " << dist[i] << "\n"; } } outfile.close(); } // write_degree_distribution +/** + * Write an eccentricity distribution out to file. + * \param[in] filename filename to write output to + * \param[in] dist a vector, indexed on degree + */ +void write_eccentricity_distribution(string filename, const vector &dist){ + ofstream outfile; + + outfile.open(filename.c_str()); + + if(!outfile.is_open()){ + cerr << "Error opening " << filename << "for writing\n"; + } + else { + int i; + for(i = 0; i < dist.size(); i++){ + outfile << i << " " << dist[i] << "\n"; + } + } + + outfile.close(); +} // write_eccentricity_distribution + +/** + * Write a expansion out to file. + * \param[in] filename filename to write output to + * \param[in] dist a vector, indexed on degree + */ +void write_expansion(string filename, const vector &expansion){ + ofstream outfile; + + outfile.open(filename.c_str()); + + if(!outfile.is_open()){ + cerr << "Error opening " << filename << "for writing\n"; + } + else { + int i; + for(i = 0; i < expansion.size(); i++){ + outfile << i << " " << expansion[i] << "\n"; + } + } + + outfile.close(); +} // write_expansion + +/** + * Write a kcore list out to file. + * \param[in] filename filename to write output to + * \param[in] kcores a vector, indexed on vertex number + */ +void write_kcores(string filename, const vector &kcores){ + ofstream outfile; + + outfile.open(filename.c_str()); + + if(!outfile.is_open()){ + cerr << "Error opening " << filename << "for writing\n"; + } + else { + int i; + for(i = 0; i < kcores.size(); i++){ + outfile << i << " " << kcores[i] << "\n"; + } + } + + outfile.close(); +} // write_k_cores + +/** + * Write an eccentricity list out to file. + * \param[in] filename filename to write output to + * \param[in] ecc a vector, indexed on vertex number + */ +void write_eccentricity(string filename, const vector &ecc){ + ofstream outfile; + + outfile.open(filename.c_str()); + + if(!outfile.is_open()){ + cerr << "Error opening " << filename << "for writing\n"; + } + else { + int i; + for(i = 0; i < ecc.size(); i++){ + outfile << i << " " << ecc[i] << "\n"; + } + } + + outfile.close(); +} // write_k_cores + +/** + * Write a betweenness centrality vecotr out to file. + * + * \param[in] filename filename to write output to + * \param[in] bc a vector, indexed on vertex number + */ +void write_betweenness(string filename, const vector &bc){ + ofstream outfile; + + outfile.open(filename.c_str()); + + if(!outfile.is_open()){ + cerr << "Error opening " << filename << "for writing\n"; + } + else { + outfile.precision(10); + int i; + for(i = 0; i < bc.size(); i++){ + outfile << fixed << i << " " << bc[i] << "\n"; + } + } + + outfile.close(); +} // write_betweenness + +/** + * Write a delta hyperbolicity vector out to file. + * + * \param[in] filename filename to write output to + * \param[in] bc a vector, indexed on vertex number + */ +void write_delta_hyperbolicity(string filename, const vector< vector > &delta){ + ofstream outfile; + + outfile.open(filename.c_str()); + + if(!outfile.is_open()){ + cerr << "Error opening " << filename << "for writing\n"; + } + else { + outfile.precision(10); + for(int idx = 0; idx < delta.size(); idx++){ + for(int jdx = 0; jdx < delta[idx].size(); jdx++){ + outfile << delta[idx][jdx] << " "; + } + outfile << endl; + } + } + + outfile.close(); +} // write_betweenness + +/** + * Write an all pairs shortest path matrix out to file. + * + * \param[in] filename filename to write output to + * \param[in] apsp a vector< vector >, indexed on vertex number, assumed to be |V|x|V| + */ +void write_apsp_matrix(string filename, vector< vector > &apsp){ + int i; + int n = apsp.size(); //assuming it's sized correctly + cerr << "Writing apsp matrix of size: " << n << endl; + + FILE *outfile; + outfile = fopen(filename.c_str(), "w+"); + + if(!outfile){ + cerr << "Error opening " << filename << "for writing\n"; + } + + fwrite((void *) &n, 1, sizeof(int), outfile); + + //#pragma omp parallel for default(none) share(n, apsp) + int ret; + for(i = 0; i < n; i++){ + int *arr = &apsp[i].front(); + fwrite(arr, n, sizeof(int), outfile); + } + + fclose(outfile); +} // write_apsp_matrix + +/** + * Read an all pairs shortest path matrixfrom file. + * + * \param[in] filename filename to read + * \param[out] apsp a vector< vector >, indexed on vertex number, assumed to be |V|x|V| + */ +void read_apsp_matrix(string filename, vector< vector > &apsp){ + int i; + int n; + + FILE *infile; + infile = fopen(filename.c_str(), "r"); + + if(!infile){ + cerr << "Error opening " << filename << "for writing\n"; + } + + fread((void *) &n, 1, sizeof(int), infile); + cerr << "Reading apsp matrix of size: " << n << endl; + + apsp.resize(n); + + //#pragma omp parallel for default(none) share(n, apsp) + int ret; + for(i = 0; i < n; i++){ + apsp[i].resize(n); + int *arr = &apsp[i].front(); + fread(arr, n, sizeof(int), infile); + } + + fclose(infile); +} // write_apsp_matrix + diff --git a/lib_graphd/test/GraphPropertyTest.cpp b/lib_graphd/test/GraphPropertyTest.cpp index 369e43b..4156f34 100644 --- a/lib_graphd/test/GraphPropertyTest.cpp +++ b/lib_graphd/test/GraphPropertyTest.cpp @@ -19,6 +19,10 @@ */ +#define GTEST_HAS_TR1_TUPLE 0 + +#include + #include "Log.h" #include "GraphCreatorFile.h" #include "Graph.h" @@ -31,6 +35,7 @@ class GraphPropertyTest : public testing::Test public: Graph::GraphCreatorFile creator; Graph::Graph *mg; +Graph::Graph *mg_dis; Graph::GraphProperties properties; virtual void SetUp(){ @@ -39,6 +44,11 @@ virtual void SetUp(){ creator.set_file_name("data/1dc.128.txt"); creator.set_graph_type("DIMACS"); mg = creator.create_mutable_graph(); + + //disconnected graph for testing + creator.set_file_name("data/1et.64.txt"); + creator.set_graph_type("DIMACS"); + mg_dis = creator.create_mutable_graph(); } virtual void TearDown(){ @@ -93,11 +103,7 @@ TEST_F(GraphPropertyTest, testClique) TEST_F(GraphPropertyTest, testIsConnected) { - creator.set_file_name("data/1et.64.txt"); - creator.set_graph_type("DIMACS"); - mg = creator.create_mutable_graph(); - - EXPECT_FALSE(properties.is_connected(mg)); + EXPECT_FALSE(properties.is_connected(mg_dis)); } TEST_F(GraphPropertyTest, testIsIndependentSet) @@ -171,6 +177,43 @@ TEST_F(GraphPropertyTest, testAvgDegree){ TEST_F(GraphPropertyTest, testDegDist){ vector dist; + properties.deg_dist(mg, dist); EXPECT_EQ(4, dist[33]); } + +#ifdef HAS_BOOST +TEST_F(GraphPropertyTest, testPowerLaw){ + int xmin; + double alpha, KS; + properties.powerlaw(mg, xmin, alpha, KS); + EXPECT_EQ(18, xmin); + EXPECT_NEAR(3.5, alpha, 0.1); + EXPECT_NEAR(0.470626, KS, 0.000001); +} +#endif // ifdef HAS_BOOST + +TEST_F(GraphPropertyTest, testDeltaHyperbolicity){ + double max_delta; + vector > delta; + + properties.delta_hyperbolicity(mg, max_delta, delta); + EXPECT_NEAR(2.0, max_delta, 0.1); + EXPECT_NEAR(204.0, delta[3][5], 0.1); + + delta.clear(); + properties.delta_hyperbolicity(mg_dis, max_delta, delta); + EXPECT_NEAR(1.0, max_delta, 0.1); + EXPECT_NEAR(126.0, delta[1][3], 0.1); +} + +TEST_F(GraphPropertyTest, testClustering){ + double global_cc; + double avg_cc; + vector local_ccs; + + properties.clustering_coefficients(mg, global_cc, avg_cc, local_ccs); + EXPECT_NEAR(0.56209150326797386, local_ccs[32], 0.0000001); + EXPECT_NEAR(0.491997272348, avg_cc, 0.00000001); + EXPECT_NEAR(0.460570029725, global_cc, 0.0000001); +} diff --git a/lib_graphd/test/GraphReaderTest.cpp b/lib_graphd/test/GraphReaderTest.cpp index 1bb6122..a630334 100644 --- a/lib_graphd/test/GraphReaderTest.cpp +++ b/lib_graphd/test/GraphReaderTest.cpp @@ -30,11 +30,12 @@ using namespace std; class GraphReaderTest : public testing::Test { public: Graph::GraphReader gr; -Graph::Graph g; +Graph::Graph *g; virtual void SetUp(){ + g = new Graph::Graph(); LOG_INIT("test.log", NULL, 0); - gr.read_graph(&g, string("data/1dc.128.txt"), string("DIMACS"), false ); + gr.read_graph(g, string("data/1dc.128.txt"), string("DIMACS"), false ); } virtual void TearDown(){ @@ -44,19 +45,20 @@ virtual void TearDown(){ TEST_F(GraphReaderTest, testCapacity) { - EXPECT_EQ(128, g.get_capacity()); + int capacity = g->get_capacity(); + EXPECT_EQ(128, capacity); } TEST_F(GraphReaderTest, testNumEdges) { - EXPECT_EQ(1471, g.get_num_edges()); + EXPECT_EQ(1471, g->get_num_edges()); } TEST_F(GraphReaderTest, testNodeNbrs) { vector n; int i; - n = g.get_nodes(); + n = g->get_nodes(); EXPECT_EQ(128, n.size()); diff --git a/lib_graphd/test/Makefile b/lib_graphd/test/Makefile index 2b404b6..7230a82 100644 --- a/lib_graphd/test/Makefile +++ b/lib_graphd/test/Makefile @@ -26,12 +26,12 @@ include ../../make.inc #----------------------------------------------------------------------------- # To build the test library -CXXFLAGS = $(INCLUDES) -g +CXXFLAGS := $(CFLAGS) -DHAS_GTEST -g INCLUDES = -I../inc -I. -I.. $(METIS_INCLUDES) $(SSPARSE_INCDIR) $(PARMETIS_INCDIR) -LIBDIR= -L. -L.. $(METIS_LIB_DIR) $(SSPARSE_LIB) -L../lib $(INDDGO_LIB) $(MPILIB_DIR) +LIBDIR= -L. -L.. -L$(METIS_LIB_DIR) $(SSPARSE_LIB) -L../lib $(INDDGO_LIB) $(MPILIB_DIR) LIB= $(MPILIBS) -lpthread -lgraphd -lgtest -lgtest_main $(METIS_LIB) -LFLAGS = $(CFLAGS) +LFLAGS = $(CXXFLAGS) #----changes are below this line---------------------------------------------- @@ -67,51 +67,51 @@ bin: mkdir -p bin .cpp.o: - $(CXX) $(INCLUDES) $(CFLAGS) -O0 -c $< + $(CXX) $(INCLUDES) $(CXXFLAGS) -O0 -c $< -bin/testDimacsReader: DIMACSReaderTest.o +bin/testDimacsReader: DIMACSReaderTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testGraphReader: GraphReaderTest.o +bin/testGraphReader: GraphReaderTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testGraphCreatorFile: GraphCreatorFileTest.o +bin/testGraphCreatorFile: GraphCreatorFileTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testGraph: GraphTest.o +bin/testGraph: GraphTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testWeightedGraph: WeightedGraphTest.o +bin/testWeightedGraph: WeightedGraphTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testMutableGraph: MutableGraphTest.o +bin/testMutableGraph: MutableGraphTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testVertexWeightedGraph: VertexWeightedGraphTest.o +bin/testVertexWeightedGraph: VertexWeightedGraphTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testAdjMatrixGraphWriter: AdjMatrixGraphWriterTest.o +bin/testAdjMatrixGraphWriter: AdjMatrixGraphWriterTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testAdjMatrixGraphReader: AdjMatrixGraphReaderTest.o +bin/testAdjMatrixGraphReader: AdjMatrixGraphReaderTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testDIMACSGraphWriter: DIMACSGraphWriterTest.o +bin/testDIMACSGraphWriter: DIMACSGraphWriterTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testGraphVizGraphWriter: GraphVizGraphWriterTest.o +bin/testGraphVizGraphWriter: GraphVizGraphWriterTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testGraphProperty: GraphPropertyTest.o +bin/testGraphProperty: GraphPropertyTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testGraphUtil: GraphUtilTest.o +bin/testGraphUtil: GraphUtilTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testMetisGraphWriter: MetisGraphWriterTest.o +bin/testMetisGraphWriter: MetisGraphWriterTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) -bin/testMetisGraphReader: MetisGraphReaderTest.o +bin/testMetisGraphReader: MetisGraphReaderTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $< ${INCLUDES} $(LIBDIR) $(LIB) bin/testGraphEOUtil: GraphEOUtilTest.o @@ -119,7 +119,7 @@ bin/testGraphEOUtil: GraphEOUtilTest.o ifeq ($(HAS_PARMETIS), 1) -bin/testParMetis: ParmetisTest.o +bin/testParMetis: ParmetisTest.o $(INDDGO_LIB_DIR)/libgraphd.a ${CXX} ${LFLAGS} -o $@ $^ $(PARMETISOBJ) ${INCLUDES} $(LIBDIR) $(LIB) endif diff --git a/lib_ptreed/Makefile b/lib_ptreed/Makefile index 6c4afc0..fdc9156 100644 --- a/lib_ptreed/Makefile +++ b/lib_ptreed/Makefile @@ -3,9 +3,9 @@ include ../make.inc DOX_DIR = ./doc/ DOXYFILE = ./Doxyfile -INC_DIR= -I./inc -I$(GRAPH)/inc -I$(TREE)/inc $(METIS_INCLUDES) $(SSPARSE_INCDIR) $(UTHASH_INCDIR) $(MADNESS_INCDIR) $(GMP_INCDIR) $(PARMETIS_INCDIR) +INC_DIR= -I./inc -I$(GRAPH)/inc -I$(TREE)/inc $(METIS_INCLUDES) $(SSPARSE_INCDIR) $(UTHASH_INCDIR) $(MADNESS_INCDIR) $(GMP_INCDIR) $(PARMETIS_INCDIR) $(SLEPC_INCDIR) $(PETSC_INCDIR) -LIBS = -lm $(INDDGO_LIB) -ltreed -lgraphd $(METIS_LIB) $(SSPARSE_LIB) $(ARPACK_LIB) $(MPILIBS) $(MADNESS_LIB) $(GMP_LIB) $(PARMETIS_LIB) +LIBS = -lm $(INDDGO_LIB) -ltreed -lgraphd $(METIS_LIB) $(SSPARSE_LIB) $(ARPACK_LIB) $(MPILIBS) $(MADNESS_LIB) $(GMP_LIB) $(PARMETIS_LIB) $(SLEPC_LIB) $(PETSC_LIB) PTD_LIB_NAME = libptreed.a diff --git a/lib_treed/Makefile b/lib_treed/Makefile index cabb11e..9867a07 100644 --- a/lib_treed/Makefile +++ b/lib_treed/Makefile @@ -4,9 +4,9 @@ include ../make.inc DOX_DIR = ./doc/ DOXYFILE = ./Doxyfile -INC_DIR= -I./inc -I$(GRAPH)/inc $(METIS_INCLUDES) $(SSPARSE_INCDIR) $(UTHASH_INCDIR) $(MADNESS_INCDIR) $(GMP_INCDIR) $(PARMETIS_INCDIR) +INC_DIR= -I./inc -I$(GRAPH)/inc $(METIS_INCLUDES) $(SSPARSE_INCDIR) $(UTHASH_INCDIR) $(MADNESS_INCDIR) $(GMP_INCDIR) $(PARMETIS_INCDIR) $(SLEPC_INCDIR) $(PETSC_INCDIR) -LIBS = -L./lib -lm -L$(GRAPH)/lib -lgraphd $(INDDGO_LIB) $(METIS_LIB) $(SSPARSE_LIB) $(ARPACK_LIB) $(MPILIBS) $(MADNESS_LIB) $(GMP_LIB) $(PARMETIS_LIB) +LIBS = -L./lib -lm -L$(GRAPH)/lib -lgraphd $(INDDGO_LIB) $(METIS_LIB) $(SSPARSE_LIB) $(ARPACK_LIB) $(MPILIBS) $(MADNESS_LIB) $(GMP_LIB) $(PARMETIS_LIB) $(SLEPC_LIB) $(PETSC_LIB) TD_LIB_NAME = libtreed.a diff --git a/make.inc.parallel b/make.inc.parallel index 9905e64..e47fa92 100644 --- a/make.inc.parallel +++ b/make.inc.parallel @@ -26,13 +26,21 @@ HAS_METIS = 1 HAS_IGRAPH = 0 HAS_GMP = 0 HAS_GTEST = 0 +# Set to 1 if you have boost installed on your system +# Many linux systems have it installed by default +HAS_BOOST = 0 +#Slepc is needed if you want eigen values +HAS_PETSC = 1 +HAS_SLEPC = 1 # Set whether serial or parallel version is desired for WIS. IS_PARALLEL = 1 HAS_MADNESS = 1 # madness is included in the INDDGO distribution, and is required to be compiled for successful parallel execution of WIS. +MAC_OSX = 0 +#some compiler flags cause problems on MacOSX. Set this to 1 if you're having problems compiling on OSX. #use this to turn logging on/off -LOG_ENABLED = 1 +LOG_ENABLED = 0 #---------------------------------------------------------------- # OPTIONAL USER-SUPPLIED DIRECTORY VARIABLES @@ -42,13 +50,13 @@ LOG_ENABLED = 1 ARPACK = #directory containing SuiteSparse installation. This includes AMD and SuiteSparse_config/UFconfig. -SUITESPARSE = #FILL IN +SUITESPARSE = #NOTE: the build directory is usually platform dependent. -PARMETIS_SRC_DIR = #FILL IN -PARMETIS_LIB_DIR = #FILL IN +PARMETIS_SRC_DIR = +PARMETIS_LIB_DIR = METIS_SRC_DIR = $(PARMETIS_SRC_DIR)/metis -METIS_LIB_DIR = #FILL IN +METIS_LIB_DIR = $(PARMETIS_SRC_DIR)/metis/build/Linux-x86_64/libmetis/ IGRAPH = IGRAPH_INSTALL_DIR = $(IGRAPH)/deploy @@ -57,6 +65,9 @@ GMP = GTEST_INCLUDE_DIR = +PETSC_DIR = +SLEPC_DIR = + #---------------------------------------------------------------- # # Compilers, Flags and System Tools @@ -71,6 +82,10 @@ CFLAGS = -O3 CPPFLAGS = LDFLAGS = +ifeq ($(HAS_BOOST),1) +CFLAGS := $(CFLAGS) -DHAS_BOOST +endif + ifeq ($(LOG_ENABLED), 1) CFLAGS := $(CFLAGS) -D__LOG_ENABLE__ endif @@ -78,12 +93,16 @@ endif ifeq ($(HAS_MADNESS),1) CXX = mpicxx ifeq ($(OLDGCC), 1) -CFLAGS := $(CFLAGS) -D__MADNESS__ -D_OLDGCC -Wno-strict-aliasing -Wno-deprecated -ffast-math +CFLAGS := $(CFLAGS) -D__MADNESS__ -D_OLDGCC -Wno-strict-aliasing -Wno-deprecated -ffast-math endif ifeq ($(OLDGCC), 0) CPPFLAGS := $(CPPFLAGS) -std=c++0x -CFLAGS := $(CFLAGS) -D__MADNESS__ -std=c++0x -Wno-strict-aliasing -Wno-deprecated -ffast-math -march=native +CFLAGS := $(CFLAGS) -D__MADNESS__ -std=c++0x -Wno-strict-aliasing -Wno-deprecated -ffast-math +endif endif + +ifneq ($(MAC_OSX),1) +CFLAGS := $(CFLAGS) -march=native endif ifeq ($(IS_PARALLEL),1) @@ -182,6 +201,21 @@ $(error When HAS_METIS = 1, you must define the METIS_SRC_DIR directory variable endif endif +ifeq ($(HAS_SLEPC),1) +ifeq ($(HAS_PETSC),0) +$(error When HAS_SLEPC = 1, HAS_PETSC must also be 1) +endif +ifeq ($(SLEPC_DIR), ) +$(error When HAS_SLEPC = 1, you must define the SLEPC_DIR directory variable) +endif +endif + +ifeq ($(HAS_METIS),1) +ifeq ($(PETSC_DIR), ) +$(error When HAS_PETSC = 1, you must define the PETSC_DIR directory variable) +endif +endif + ifeq ($(HAS_IGRAPH),1) ifeq ($(IGRAPH), ) $(error When HAS_IGRAPH = 1, you must define the IGRAPH directory variable) @@ -329,3 +363,18 @@ IGRAPH_LIB= -L $(IGRAPH_INSTALL_DIR)/lib -ligraph IGRAPH_INCDIR = -I $(IGRAPH_INSTALL_DIR)/include/igraph endif +PETSC_INCDIR= +PETSC_LIB= +ifeq ($(HAS_PETSC),1) +CFLAGS := $(CFLAGS) -DHAS_PETSC +PETSC_INCDIR = -I $(PETSC_DIR)/include +PETSC_LIB = -L $(PETSC_DIR)/lib -lpetsc -llapack -lblas -lX11 +endif + +SLEPC_INCDIR= +SLEPC_LIB= +ifeq ($(HAS_SLEPC),1) +CFLAGS := $(CFLAGS) -DHAS_SLEPC +SLEPC_INCDIR = -I $(SLEPC_DIR)/include +SLEPC_LIB = -L $(SLEPC_DIR)/lib -lslepc +endif diff --git a/make.inc.serial b/make.inc.serial index d9e37be..9b2bc0a 100644 --- a/make.inc.serial +++ b/make.inc.serial @@ -32,6 +32,9 @@ HAS_METIS = 0 HAS_IGRAPH = 0 HAS_GMP = 0 HAS_GTEST = 0 +# Set to 1 if you have boost installed on your system +# Many linux systems have it installed by default +HAS_BOOST = 0 # Set whether serial or parallel version is desired for WIS. IS_PARALLEL = 0 HAS_MADNESS = 0 @@ -91,6 +94,10 @@ ifeq ($(LOG_ENABLED), 1) CFLAGS := $(CFLAGS) -D__LOG_ENABLE__ endif +ifeq ($(HAS_BOOST),1) +CFLAGS := $(CFLAGS) -DHAS_BOOST +endif + ifeq ($(HAS_MADNESS),1) CXX = mpicxx ifeq ($(OLDGCC), 1) diff --git a/max_wis/Makefile b/max_wis/Makefile index ef87cb5..1b8e918 100644 --- a/max_wis/Makefile +++ b/max_wis/Makefile @@ -3,9 +3,9 @@ include ../make.inc # Optimal WIS for this one is 79 TEST_GRAPH = $(SRC_DIR)/sample_graphs/pkt.200.70.75_0.dimacs -INC_DIR= -I./inc -I$(GRAPH)/inc -I$(TREE)/inc/ $(METIS_INCLUDES) $(SSPARSE_INCDIR) $(UTHASH_INCDIR) $(MADNESS_INCDIR) $(GMP_INCDIR) $(PARMETIS_INCDIR) -I$(PTREE)/inc/ +INC_DIR= -I./inc -I$(GRAPH)/inc -I$(TREE)/inc/ $(METIS_INCLUDES) $(SSPARSE_INCDIR) $(UTHASH_INCDIR) $(MADNESS_INCDIR) $(GMP_INCDIR) $(PARMETIS_INCDIR) -I$(PTREE)/inc/ $(SLEPC_INCDIR) $(PETSC_INCDIR) -LIBS = -lm $(INDDGO_LIB) -ltreed -lgraphd $(SSPARSE_LIB) $(ARPACK_LIB) $(MPILIBS) $(MADNESS_LIB) $(GMP_LIB) $(METIS_LIB) +LIBS = -lm $(INDDGO_LIB) -ltreed -lgraphd $(SSPARSE_LIB) $(ARPACK_LIB) $(MPILIBS) $(MADNESS_LIB) $(GMP_LIB) $(METIS_LIB) $(SLEPC_LIB) $(PETSC_LIB) WEIGHTED_IND_SET_SRC = ./src/weighted_ind_set.cpp ./src/main.cpp WEIGHTED_IND_SET_EXE = $(INDDGO_BIN)/serial_wis diff --git a/util/Makefile b/util/Makefile index b8e3522..896b149 100755 --- a/util/Makefile +++ b/util/Makefile @@ -1,84 +1,77 @@ -include ../make.inc -DOX_DIR = ./doc/ -DOXYFILE = ./Doxyfile - -INC_DIR = -I./inc -I$(GRAPH)/inc -I$(TREE)/inc $(METIS_INCLUDES) $(SSPARSE_INCDIR) $(UTHASH_INCDIR) $(MADNESS_INCDIR) $(GMP_INCDIR) $(PARMETIS_INCDIR) - -LIBS = -lm $(INDDGO_LIB) -ltreed -lgraphd $(SSPARSE_LIB) $(ARPACK_LIB) $(GMP_LIB) $(PARMETIS_LIB) $(METIS_LIB) - -PKT_SRCS = ./src/gen_pkt.cpp -PKT_OBJ = src/orbtimer.o $(PKT_SRCS:.cpp=.o) -PKT_EXE = $(INDDGO_BIN)/gen_pkt - -CMP_SRCS = ./src/complement.cpp -CMP_OBJ = $(CMP_SRCS:.cpp=.o) -CMP_EXE = $(INDDGO_BIN)/complement - -TD_STATS_SRCS = ./src/td_stats.cpp -TD_STATS_OBJ = $(TD_STATS_SRCS:.cpp=.o) -TD_STATS_EXE = $(INDDGO_BIN)/td_stats - -G_STATS_SRCS = ./src/graph_stats.cpp -G_STATS_OBJ = src/orbtimer.o $(G_STATS_SRCS:.cpp=.o) -G_STATS_EXE = $(INDDGO_BIN)/graph_stats - -GCONVERT_SRCS = ./src/gconvert.cpp -GCONVERT_OBJ = src/orbtimer.o $(GCONVERT_SRCS:.cpp=.o) -GCONVERT_EXE = $(INDDGO_BIN)/gconvert - -TRI_SRCS = ./src/count-tri.cpp -TRI_OBJ = src/orbtimer.o $(TRI_SRCS:.cpp=.o) -TRI_EXE = $(INDDGO_BIN)/count-tri - -SRT_SRCS = ./src/shortest-paths.cpp -SRT_OBJ = $(SRT_SRCS:.cpp=.o) -SRT_EXE = $(INDDGO_BIN)/shortest-paths - -ECC_SRCS = ./src/v_eccentricity.cpp -ECC_OBJ = $(ECC_SRCS:.cpp=.o) -ECC_EXE = $(INDDGO_BIN)/v_eccentricity - -EXP_SRCS = ./src/expansion.cpp -EXP_OBJ = $(EXP_SRCS:.cpp=.o) -EXP_EXE = $(INDDGO_BIN)/expansion - -all: $(PKT_EXE) $(TD_STATS_EXE) $(GCONVERT_EXE) $(E2A_EXE) $(M2D_EXE) $(G_STATS_EXE) $(TRI_EXE) $(SRT_EXE) $(ECC_EXE) $(EXP_EXE) $(CMP_EXE) - -.cpp.o: - $(CXX) $(CPPFLAGS) $(CFLAGS) -c $(INC_DIR) $< -o $@ - -$(PKT_EXE): $(PKT_OBJ) ../lib/libgraphd.a - $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ - -$(CMP_EXE): $(CMP_OBJ) ../lib/libgraphd.a - $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ - -$(TD_STATS_EXE): $(TD_STATS_OBJ) ../lib/libgraphd.a - $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ - -$(G_STATS_EXE): $(G_STATS_OBJ) ../lib/libgraphd.a - $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ - -$(GCONVERT_EXE): $(GCONVERT_OBJ) ../lib/libgraphd.a - $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ - -$(TRI_EXE): $(TRI_OBJ) ../lib/libgraphd.a - $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ - -$(SRT_EXE): $(SRT_OBJ) ../lib/libgraphd.a - $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ - -$(ECC_EXE): $(ECC_OBJ) ../lib/libgraphd.a - $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ - -$(EXP_EXE): $(EXP_OBJ) ../lib/libgraphd.a - $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ - -clean: - -rm -rf $(PKT_OBJ) $(PKT_EXE) $(TD_STATS_OBJ) $(TD_STATS_EXE) $(GCONVERT_OBJ) $(GCONVERT_EXE) $(M2D_EXE) $(M2D_OBJ) $(G_STATS_EXE) $(G_STATS_OBJ) $(TRI_OBJ) $(TRI_EXE) $(SRT_OBJ) $(SRT_EXE) $(ECC_OBJ) $(ECC_EXE) $(EXP_OBJ) $(EXP_EXE) $(E2A_EXE) $(E2A_OBJ) $(CMP_EXE) $(CMP_OBJ) - -doc: $(DOXYFILE) - doxygen $(DOXYFILE) - -clean_doc: - rm -rf $(DOX_DIR) +include ../make.inc +DOX_DIR = ./doc/ +DOXYFILE = ./Doxyfile + +INC_DIR = -I./inc -I$(GRAPH)/inc -I$(TREE)/inc $(METIS_INCLUDES) $(SSPARSE_INCDIR) $(UTHASH_INCDIR) $(MADNESS_INCDIR) $(GMP_INCDIR) $(PARMETIS_INCDIR) $(SLEPC_INCDIR) $(PETSC_INCDIR) + +LIBS = -lm $(INDDGO_LIB) -ltreed -lgraphd $(SSPARSE_LIB) $(ARPACK_LIB) $(GMP_LIB) $(PARMETIS_LIB) $(METIS_LIB) $(SLEPC_LIB) $(PETSC_LIB) + +PKT_SRCS = ./src/gen_pkt.cpp +PKT_OBJ = src/orbtimer.o $(PKT_SRCS:.cpp=.o) +PKT_EXE = $(INDDGO_BIN)/gen_pkt + +TD_STATS_SRCS = ./src/td_stats.cpp +TD_STATS_OBJ = $(TD_STATS_SRCS:.cpp=.o) +TD_STATS_EXE = $(INDDGO_BIN)/td_stats + +G_STATS_SRCS = ./src/graph_stats.cpp +G_STATS_OBJ = src/orbtimer.o $(G_STATS_SRCS:.cpp=.o) +G_STATS_EXE = $(INDDGO_BIN)/graph_stats + +GCONVERT_SRCS = ./src/gconvert.cpp +GCONVERT_OBJ = src/orbtimer.o $(GCONVERT_SRCS:.cpp=.o) +GCONVERT_EXE = $(INDDGO_BIN)/gconvert + +TRI_SRCS = ./src/count-tri.cpp +TRI_OBJ = src/orbtimer.o $(TRI_SRCS:.cpp=.o) +TRI_EXE = $(INDDGO_BIN)/count-tri + +SRT_SRCS = ./src/shortest-paths.cpp +SRT_OBJ = $(SRT_SRCS:.cpp=.o) +SRT_EXE = $(INDDGO_BIN)/shortest-paths + +ECC_SRCS = ./src/v_eccentricity.cpp +ECC_OBJ = $(ECC_SRCS:.cpp=.o) +ECC_EXE = $(INDDGO_BIN)/v_eccentricity + +EXP_SRCS = ./src/expansion.cpp +EXP_OBJ = $(EXP_SRCS:.cpp=.o) +EXP_EXE = $(INDDGO_BIN)/expansion + +all: $(PKT_EXE) $(TD_STATS_EXE) $(GCONVERT_EXE) $(E2A_EXE) $(M2D_EXE) $(G_STATS_EXE) $(TRI_EXE) $(SRT_EXE) $(ECC_EXE) $(EXP_EXE) + +.cpp.o: + $(CXX) $(CPPFLAGS) $(CFLAGS) -c $(INC_DIR) $< -o $@ + +$(PKT_EXE): $(PKT_OBJ) ../lib/libgraphd.a + $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ + +$(TD_STATS_EXE): $(TD_STATS_OBJ) ../lib/libgraphd.a + $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ + +$(G_STATS_EXE): $(G_STATS_OBJ) ../lib/libgraphd.a + $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ + +$(GCONVERT_EXE): $(GCONVERT_OBJ) ../lib/libgraphd.a + $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ + +$(TRI_EXE): $(TRI_OBJ) ../lib/libgraphd.a + $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ + +$(SRT_EXE): $(SRT_OBJ) ../lib/libgraphd.a + $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ + +$(ECC_EXE): $(ECC_OBJ) ../lib/libgraphd.a + $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ + +$(EXP_EXE): $(EXP_OBJ) ../lib/libgraphd.a + $(CXX) $(CPPFLAGS) $(CFLAGS) $^ $(INC_DIR) $(LIBS) $(LDFLAGS) -o $@ + +clean: + -rm -rf $(PKT_OBJ) $(PKT_EXE) $(TD_STATS_OBJ) $(TD_STATS_EXE) $(GCONVERT_OBJ) $(GCONVERT_EXE) $(M2D_EXE) $(M2D_OBJ) $(G_STATS_EXE) $(G_STATS_OBJ) $(TRI_OBJ) $(TRI_EXE) $(SRT_OBJ) $(SRT_EXE) $(ECC_OBJ) $(ECC_EXE) $(EXP_OBJ) $(EXP_EXE) $(E2A_EXE) $(E2A_OBJ) + +doc: $(DOXYFILE) + doxygen $(DOXYFILE) + +clean_doc: + rm -rf $(DOX_DIR) diff --git a/util/src/CPX_solve_wis.cpp b/util/src/CPX_solve_wis.cpp old mode 100755 new mode 100644 index 89e88ec..802d63b --- a/util/src/CPX_solve_wis.cpp +++ b/util/src/CPX_solve_wis.cpp @@ -8,231 +8,220 @@ #include "GraphDecomposition.h" -void check_CPX_status(char *func, int status) -{ - if (status) - { - fprintf (stderr, "CPX nonzero status after %s: %d\n",func,status); - exit(-1); - } +void check_CPX_status(char *func, int status){ + if(status){ + fprintf (stderr, "CPX nonzero status after %s: %d\n",func,status); + exit(-1); + } }; void write_ind_set_model(const char *DIMACS_file, const char *model_file, - Graph::VertexWeightedGraph *G) -{ - int i, j; - - FILE *out = fopen(model_file, "w"); - if (!out) - fatal_error("Can't open %s for writing\n", model_file); - - // Write out the model - fprintf(out, - "# Automatically generated model file for max independent set\n" - "# Assumes 1-based node names with no holes!!\n" - "# Original graph file is %s\n" - "# Model section\n\n" - "param num_nodes ;\n" - "set Nodes := 1..num_nodes ;\n" - "set E within Nodes cross Nodes ;\n" - "param w{Nodes};\n" - "var x{i in Nodes} binary;\n\n" - // Change to minimization for archaic MPS reasons - "minimize Cost: sum{i in Nodes} -x[i]*w[i];\n\n" - "subject to Independent{i in Nodes, j in Nodes: (i,j) in E}:\n" - "x[i]+x[j]<=1;\n\n" - "solve;\n\n", DIMACS_file); - /* - fprintf( - out, - "printf \" \\nMaximum Independent Set: %%d\\n\", sum{i in Nodes} x[i]*w[i] > \"%s\";\n", - sol_file); - fprintf(out, "for { i in Nodes }\n" - "{\n" - " printf{0..0: x[i]!=0} \"%%d (%%3.1f)\\n\", i, w[i] >> \"%s\";\n", - sol_file); - fprintf(out, "}\n\n");*/ - fflush(out); - fprintf(stderr,"Writing data section\n"); - - fprintf(out, "# Data Section\n\ndata;\n\n"); - fflush(out); - // Write out the problem data - fprintf(out, "param num_nodes:=%d;\n", G->get_num_nodes()); - fflush(out); - fprintf(out, "param w:=\n"); - fflush(out); - vector nodes = G->get_nodes(); - vector weight = G->get_weight(); - - for (i = 0; i < G->get_num_nodes(); i++) - { - fprintf(out, "%d %d\n",nodes[i].get_label(), weight[i]); - } - fprintf(out, ";\n"); - fprintf(out, "set E:=\n"); - Graph::GraphProperties properties; - - vector adj_vec; - for (i = 0; i < G->get_num_nodes(); i++) - { - // This assumes 1-based labeling! - int current_key = properties.fill_adj_vec(G, i); - //int current_key=G->fill_adj_vec(i); - adj_vec = G->get_adj_vec(); - for (j = i + 1; j < G->get_num_nodes(); j++) - { - if (adj_vec[j] == current_key) - fprintf(out, "(%d,%d)\n", i + 1, j + 1); - } - fprintf(out, "\n"); - } - fprintf(out, ";\nend;\n"); - fclose(out); + Graph::VertexWeightedGraph *G){ + int i, j; + + FILE *out = fopen(model_file, "w"); + if(!out){ + fatal_error("Can't open %s for writing\n", model_file); + } + + // Write out the model + fprintf(out, + "# Automatically generated model file for max independent set\n" + "# Assumes 1-based node names with no holes!!\n" + "# Original graph file is %s\n" + "# Model section\n\n" + "param num_nodes ;\n" + "set Nodes := 1..num_nodes ;\n" + "set E within Nodes cross Nodes ;\n" + "param w{Nodes};\n" + "var x{i in Nodes} binary;\n\n" + // Change to minimization for archaic MPS reasons + "minimize Cost: sum{i in Nodes} -x[i]*w[i];\n\n" + "subject to Independent{i in Nodes, j in Nodes: (i,j) in E}:\n" + "x[i]+x[j]<=1;\n\n" + "solve;\n\n", DIMACS_file); + /* + fprintf( + out, + "printf \" \\nMaximum Independent Set: %%d\\n\", sum{i in Nodes} x[i]*w[i] > \"%s\";\n", + sol_file); + fprintf(out, "for { i in Nodes }\n" + "{\n" + " printf{0..0: x[i]!=0} \"%%d (%%3.1f)\\n\", i, w[i] >> \"%s\";\n", + sol_file); + fprintf(out, "}\n\n");*/ + fflush(out); + fprintf(stderr,"Writing data section\n"); + + fprintf(out, "# Data Section\n\ndata;\n\n"); + fflush(out); + // Write out the problem data + fprintf(out, "param num_nodes:=%d;\n", G->get_num_nodes()); + fflush(out); + fprintf(out, "param w:=\n"); + fflush(out); + vector nodes = G->get_nodes(); + vector weight = G->get_weight(); + + for(i = 0; i < G->get_num_nodes(); i++){ + fprintf(out, "%d %d\n",nodes[i].get_label(), weight[i]); + } + fprintf(out, ";\n"); + fprintf(out, "set E:=\n"); + Graph::GraphProperties properties; + + vector adj_vec; + for(i = 0; i < G->get_num_nodes(); i++){ + // This assumes 1-based labeling! + int current_key = properties.fill_adj_vec(G, i); + //int current_key=G->fill_adj_vec(i); + adj_vec = G->get_adj_vec(); + for(j = i + 1; j < G->get_num_nodes(); j++){ + if(adj_vec[j] == current_key){ + fprintf(out, "(%d,%d)\n", i + 1, j + 1); + } + } + fprintf(out, "\n"); + } + fprintf(out, ";\nend;\n"); + fclose(out); }; -void read_DIMACS(const char *DIMACS_file, Graph::VertexWeightedGraph *G) -{ - int i; - Graph::GraphCreatorFile creator; - creator.set_file_name(DIMACS_file); - creator.set_graph_type("DIMACS"); - - G = creator.create_weighted_mutable_graph(); - if (!G) - { - fprintf(stderr,"Could not create graph for DIMACS file %s\n",DIMACS_file); - exit(-1); - } - - // Add weights of 1 to all vertices if we didn't load any from the file - bool has_weights = false; - vector weight = (G)->get_weight(); - for (i = 0; i < (G)->get_capacity(); i++) - { - if (weight[i] != 0) - { - has_weights = true; - break; - } - } - - if (!has_weights) - for (i = 0; i < (G)->get_capacity(); i++) - weight[i] = 1; - - fprintf(stderr,"Graph loaded with %d nodes, %d edges\n",G->get_num_nodes(), - G->get_num_edges()); +void read_DIMACS(const char *DIMACS_file, Graph::VertexWeightedGraph *G){ + int i; + Graph::GraphCreatorFile creator; + creator.set_file_name(DIMACS_file); + creator.set_graph_type("DIMACS"); + + G = creator.create_weighted_mutable_graph(); + if(!G){ + fprintf(stderr,"Could not create graph for DIMACS file %s\n",DIMACS_file); + exit(-1); + } + + // Add weights of 1 to all vertices if we didn't load any from the file + bool has_weights = false; + vector weight = (G)->get_weight(); + for(i = 0; i < (G)->get_capacity(); i++){ + if(weight[i] != 0){ + has_weights = true; + break; + } + } + + if(!has_weights){ + for(i = 0; i < (G)->get_capacity(); i++){ + weight[i] = 1; + } + } + + fprintf(stderr,"Graph loaded with %d nodes, %d edges\n",G->get_num_nodes(), + G->get_num_edges()); }; -void create_mps_file(char *gmpl_file, char *mps_file, bool verbose) -{ - // Read in the model - glp_prob *lp; - glp_tran *tran; - if(!verbose) - glp_term_out(GLP_OFF); - lp = glp_create_prob(); - tran = glp_mpl_alloc_wksp(); - fprintf(stderr,"reading model\n"); - int ret = glp_mpl_read_model(tran, gmpl_file , 0); - if (ret) - { - fprintf(stderr, "Error translating model\n"); - exit(-1); - } - ret = glp_mpl_generate(tran, NULL); - if (ret) - { - fprintf(stderr, "Error generating model\n"); - exit(-1); - } - - glp_mpl_build_prob(tran, lp); - ret = glp_write_mps(lp, GLP_MPS_FILE, NULL, mps_file); - if (ret) - { - fprintf(stderr, "Error on writing MPS file\n"); - exit(-1); - } - glp_mpl_free_wksp(tran); - glp_delete_prob(lp); - fprintf(stderr,"GLPK created MPS file %s\n",mps_file); +void create_mps_file(char *gmpl_file, char *mps_file, bool verbose){ + // Read in the model + glp_prob *lp; + glp_tran *tran; + if(!verbose){ + glp_term_out(GLP_OFF); + } + lp = glp_create_prob(); + tran = glp_mpl_alloc_wksp(); + fprintf(stderr,"reading model\n"); + int ret = glp_mpl_read_model(tran, gmpl_file, 0); + if(ret){ + fprintf(stderr, "Error translating model\n"); + exit(-1); + } + ret = glp_mpl_generate(tran, NULL); + if(ret){ + fprintf(stderr, "Error generating model\n"); + exit(-1); + } + + glp_mpl_build_prob(tran, lp); + ret = glp_write_mps(lp, GLP_MPS_FILE, NULL, mps_file); + if(ret){ + fprintf(stderr, "Error on writing MPS file\n"); + exit(-1); + } + glp_mpl_free_wksp(tran); + glp_delete_prob(lp); + fprintf(stderr,"GLPK created MPS file %s\n",mps_file); +} // create_mps_file + +void usage(char *str){ + fprintf(stderr,"%s [-n num_threads]\n" + "\t Uses CPLEX with num_threads to solve WIS with max_seconds time limit\n",str); + exit(-1); } -void usage(char *str) -{ - fprintf(stderr,"%s [-n num_threads]\n" - "\t Uses CPLEX with num_threads to solve WIS with max_seconds time limit\n",str); - exit(-1); -} - -int main(int argc,char *argv[]) -{ - if(argc<3) - usage(argv[0]); - char *DIMACS_file=argv[1]; - // set time limit - int max_secs=atoi(argv[2]); - int num_threads=-1; - if(argc>=4) - { - for(int i=3;iget_num_nodes(), - G->get_num_edges()); - - // Write a GMPL model - sprintf(mod_file,"%s.mod",DIMACS_file); - write_ind_set_model(DIMACS_file, mod_file, G); - // Write mps file - sprintf(mps_file,"%s.mps",DIMACS_file); - create_mps_file(mod_file,mps_file,false); - - CPXENVptr env = NULL; - env = CPXopenCPLEX (&status); - check_CPX_status("CPXopenCPLEX",status); - - CPXsetintparam (env, CPX_PARAM_SCRIND, CPX_OFF); - - clock_t start=clock(),stop; - CPXLPptr mip; - mip=CPXcreateprob(env,&status,mps_file); - status = CPXreadcopyprob (env, mip, mps_file, NULL); - check_CPX_status("CPXreadcopyprob",status); - CPXsetdblparam(env, CPX_PARAM_TILIM, max_secs); - - if(num_threads!=-1) - // Set # of threads - CPXsetintparam(env,CPX_PARAM_THREADS,num_threads); - - int num_cols=CPXgetnumcols(env,mip); - int num_rows=CPXgetnumrows(env,mip); - - int mip_status=CPXmipopt(env,mip); - double obj; - CPXgetobjval(env,mip,&obj); - int objval=(int)obj; - stop=clock(); - fprintf(stdout,"%s %d %d %d %d %d %3.3f\n",DIMACS_file,num_cols, num_rows,mip_status, - -objval,getHWmem(),(double)(stop-start)/CLOCKS_PER_SEC); - fflush(stdout); - exit(-1); -} - - - +int main(int argc,char *argv[]){ + if(argc < 3){ + usage(argv[0]); + } + char *DIMACS_file = argv[1]; + // set time limit + int max_secs = atoi(argv[2]); + int num_threads = -1; + if(argc >= 4){ + for(int i = 3; i < argc; i++){ + if(strcmp(argv[i],"-n") == 0){ + num_threads = atoi(argv[i + 1]); + } + } + } + + // Load the graph from DIMACS_file + Graph::VertexWeightedGraph *G; + Graph::GraphCreatorFile creator; + creator.set_file_name(DIMACS_file); + creator.set_graph_type("DIMACS"); + G = creator.create_weighted_mutable_graph(); + + char mps_file[100], mod_file[100]; + + int status; + fprintf(stderr,"G has %d nodes, %d edges\n",G->get_num_nodes(), + G->get_num_edges()); + + // Write a GMPL model + sprintf(mod_file,"%s.mod",DIMACS_file); + write_ind_set_model(DIMACS_file, mod_file, G); + // Write mps file + sprintf(mps_file,"%s.mps",DIMACS_file); + create_mps_file(mod_file,mps_file,false); + + CPXENVptr env = NULL; + env = CPXopenCPLEX (&status); + check_CPX_status("CPXopenCPLEX",status); + + CPXsetintparam (env, CPX_PARAM_SCRIND, CPX_OFF); + + clock_t start = clock(),stop; + CPXLPptr mip; + mip = CPXcreateprob(env,&status,mps_file); + status = CPXreadcopyprob (env, mip, mps_file, NULL); + check_CPX_status("CPXreadcopyprob",status); + CPXsetdblparam(env, CPX_PARAM_TILIM, max_secs); + + if(num_threads != -1){ + // Set # of threads + CPXsetintparam(env,CPX_PARAM_THREADS,num_threads); + } + + int num_cols = CPXgetnumcols(env,mip); + int num_rows = CPXgetnumrows(env,mip); + + int mip_status = CPXmipopt(env,mip); + double obj; + CPXgetobjval(env,mip,&obj); + int objval = (int)obj; + stop = clock(); + fprintf(stdout,"%s %d %d %d %d %d %3.3f\n",DIMACS_file,num_cols, num_rows,mip_status, + -objval,getHWmem(),(double)(stop - start) / CLOCKS_PER_SEC); + fflush(stdout); + exit(-1); +} // main diff --git a/util/src/complement.cpp b/util/src/complement.cpp old mode 100755 new mode 100644 index d63b6b5..843f731 --- a/util/src/complement.cpp +++ b/util/src/complement.cpp @@ -1,23 +1,23 @@ /* -This file is part of INDDGO. + This file is part of INDDGO. -Copyright (C) 2012, Oak Ridge National Laboratory + Copyright (C) 2012, Oak Ridge National Laboratory -This product includes software produced by UT-Battelle, LLC under Contract No. -DE-AC05-00OR22725 with the Department of Energy. + This product includes software produced by UT-Battelle, LLC under Contract No. + DE-AC05-00OR22725 with the Department of Energy. -This program is free software; you can redistribute it and/or modify -it under the terms of the New BSD 3-clause software license (LICENSE). + This program is free software; you can redistribute it and/or modify + it under the terms of the New BSD 3-clause software license (LICENSE). -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -LICENSE for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + LICENSE for more details. -For more information please contact the INDDGO developers at: -inddgo-info@googlegroups.com + For more information please contact the INDDGO developers at: + inddgo-info@googlegroups.com -*/ + */ #include "GraphDecomposition.h" #include "TreeDecomposition.h" @@ -28,39 +28,38 @@ inddgo-info@googlegroups.com #include "VertexWeightedGraph.h" -void usage(char *str) -{ - fprintf(stderr,"%s \n\tWrites the complement graph of the provided\n" - "\tDIMACS file to .comp.norm\n" - "\tin normalized DIMACS form\n", str); - exit(-1); +void usage(char *str){ + fprintf(stderr,"%s \n\tWrites the complement graph of the provided\n" + "\tDIMACS file to .comp.norm\n" + "\tin normalized DIMACS form\n", str); + exit(-1); }; -int main(int argc, char **argv) -{ - if(argc!=2 || strcmp(argv[1],"-h")==0 || strcmp(argv[1],"--help")==0) - usage(argv[0]); +int main(int argc, char **argv){ + if((argc != 2) || (strcmp(argv[1],"-h") == 0) || (strcmp(argv[1],"--help") == 0) ){ + usage(argv[0]); + } - Graph::VertexWeightedGraph *G; - - Graph::GraphCreatorFile creator; - creator.set_file_name(argv[1]); - creator.set_graph_type("DIMACS"); - G = creator.create_weighted_mutable_graph(); - G->complement(); - Graph::GraphWriter writer; - - char comp_DIMACS_file[200]; - char normalized_comp_DIMACS_file[200]; - sprintf(comp_DIMACS_file,"%s.comp",argv[1]); - writer.write_graph(G,comp_DIMACS_file,"DIMACS",true,false); - // Now normalize it - sprintf(normalized_comp_DIMACS_file,"%s.norm",comp_DIMACS_file); - normalize_DIMACS_file(comp_DIMACS_file,normalized_comp_DIMACS_file); - fprintf(stderr,"Complement graph of %s written to %s in normalized DIMACS form\n", - argv[1],normalized_comp_DIMACS_file); + Graph::VertexWeightedGraph *G; - delete G; - return 1; -} + Graph::GraphCreatorFile creator; + creator.set_file_name(argv[1]); + creator.set_graph_type("DIMACS"); + G = creator.create_weighted_mutable_graph(); + G->complement(); + Graph::GraphWriter writer; + + char comp_DIMACS_file[200]; + char normalized_comp_DIMACS_file[200]; + sprintf(comp_DIMACS_file,"%s.comp",argv[1]); + writer.write_graph(G,comp_DIMACS_file,"DIMACS",true,false); + // Now normalize it + sprintf(normalized_comp_DIMACS_file,"%s.norm",comp_DIMACS_file); + normalize_DIMACS_file(comp_DIMACS_file,normalized_comp_DIMACS_file); + fprintf(stderr,"Complement graph of %s written to %s in normalized DIMACS form\n", + argv[1],normalized_comp_DIMACS_file); + + delete G; + return 1; +} // main diff --git a/util/src/count-tri.cpp b/util/src/count-tri.cpp index e0bb0bf..20419a6 100644 --- a/util/src/count-tri.cpp +++ b/util/src/count-tri.cpp @@ -21,21 +21,21 @@ #if !WIN32 && !CYGWIN -#include "GraphDecomposition.h" -#include "GraphProperties.h" -#include "Log.h" -#include "VertexWeightedGraph.h" -#include "GraphException.h" -#include "GraphReader.h" -#include "GraphWriter.h" -#include -#include -#include -#include -#include -#include -#include "orbconfig.h" -#include "orbtimer.h" + #include "GraphDecomposition.h" + #include "GraphProperties.h" + #include "Log.h" + #include "VertexWeightedGraph.h" + #include "GraphException.h" + #include "GraphReader.h" + #include "GraphWriter.h" + #include + #include + #include + #include + #include + #include + #include "orbconfig.h" + #include "orbtimer.h" using namespace std; @@ -136,13 +136,12 @@ int main(int argc, char **argv){ return 0; } // main - -#else -#include -int main() -{ - fprintf(stderr,"Can't build under windows or cygwin\n"); - return 0; +#else // if !WIN32 && !CYGWIN + #include +int main(){ + fprintf(stderr,"Can't build under windows or cygwin\n"); + return 0; } -#endif + +#endif // if !WIN32 && !CYGWIN diff --git a/util/src/gconvert.cpp b/util/src/gconvert.cpp index dc5b14a..65a1ef7 100644 --- a/util/src/gconvert.cpp +++ b/util/src/gconvert.cpp @@ -28,13 +28,14 @@ #include "GraphWriter.h" #if !WIN32 && !CYGWIN -#include "orbconfig.h" -#include "orbtimer.h" + #include "orbconfig.h" + #include "orbtimer.h" using namespace std; void print_time(string prefix, ORB_t start, ORB_t end){ cout << prefix + ": " << ORB_seconds(end, start) << "\n"; } + #endif void usage(const char *s){ @@ -42,7 +43,7 @@ void usage(const char *s){ } int main(int argc, char **argv){ -#if !WIN32 & !CYGWIN + #if !WIN32 & !CYGWIN ORB_t t1, t2; char *intype, *outtype, *infile, *outfile; @@ -108,9 +109,9 @@ int main(int argc, char **argv){ print_time("Time(write_graph)", t1, t2); return 0; -#else - fprintf(stderr,"Can't build under Cygwin or Windows\n"); - return 1; -#endif + #else // if !WIN32 & !CYGWIN + fprintf(stderr,"Can't build under Cygwin or Windows\n"); + return 1; + #endif // if !WIN32 & !CYGWIN } // main diff --git a/util/src/gen_pkt.cpp b/util/src/gen_pkt.cpp index 1e1bd71..7b0b3f6 100644 --- a/util/src/gen_pkt.cpp +++ b/util/src/gen_pkt.cpp @@ -26,16 +26,15 @@ #include "GraphWriter.h" #if !WIN32 && !CYGWIN -#include "orbconfig.h" -#include "orbtimer.h" + #include "orbconfig.h" + #include "orbtimer.h" #else -#define ORB_t clock_t -#define ORB_seconds(x,y) "lame" -#define ORB_calibrate() -#define ORB_read(x) + #define ORB_t clock_t + #define ORB_seconds(x,y) "lame" + #define ORB_calibrate() + #define ORB_read(x) #endif - using namespace std; void usage(const char *s){ @@ -69,7 +68,7 @@ int main(int argc, char **argv){ exit(-1); } - ORB_t t1=0, t2=0, t3=0; + ORB_t t1 = 0, t2 = 0, t3 = 0; int i; int t = 1; int ktree_n = -1, ktree_k = -1, ktree_p = -1; diff --git a/util/src/graph_stats.cpp b/util/src/graph_stats.cpp index 7dbb3ea..b39e474 100644 --- a/util/src/graph_stats.cpp +++ b/util/src/graph_stats.cpp @@ -33,17 +33,23 @@ #include "GraphException.h" #if !WIN32 && !CYGWIN -#include "orbconfig.h" -#include "orbtimer.h" + #include "orbconfig.h" + #include "orbtimer.h" + + #ifdef HAS_SLEPC + #include + #endif using namespace std; -void print_time(string prefix, ORB_t start, ORB_t end){ - cout << prefix + ": " << ORB_seconds(end, start) << "\n"; +void print_time(ofstream &of, string prefix, ORB_t start, ORB_t end){ + cout << prefix + ": " << ORB_seconds(end, start) << endl; + if(of.is_open()){ + of << prefix + ": " << ORB_seconds(end, start) << endl; + } } - -const string allowed_methods ("edge_density,avg_degree,degree_dist,global_cc,avg_cc,local_ccs,shortest_paths,assortativity,eccentricity,eccentricity_dist,expansion"); +const string allowed_methods ("edge_density,avg_degree,degree_dist,global_cc,avg_cc,local_ccs,shortest_paths,assortativity,eccentricity,eccentricity_dist,expansion,apsp_output,avg_shortest_path,shortest_paths_boost,eigen_spectrum,k_cores,degeneracy,betweenness,powerlaw,delta_hyperbolicity"); /** * Creates a map from a comma-separated string @@ -59,9 +65,9 @@ void create_map(string list, map &outmap){ } void print_usage(char **argv){ - cerr << "Usage: " << argv[0] << " [-h] -i infile [-t input-type] [-o outfile] [-p output-prefix] [-m methods]\n"; - cerr << "Allowed methods: " << allowed_methods << "\n"; - cerr << "Input type should be one of: edge, adjlist, adjmatrix, dimacs\n"; + cerr << "Usage: " << argv[0] << " [-h] -i infile [-t input-type] [-o outfile] [-p output-prefix] [-m methods] [-s eigen spectrum size] [-r] [-x APSP matrix input]" << endl; + cerr << "Allowed methods: " << allowed_methods << endl; + cerr << "Input type should be one of: edge, adjlist, adjmatrix, dimacs" << endl; } /** @@ -73,9 +79,10 @@ void print_usage(char **argv){ * \param[out] outfilename file to write output to * \param[out] methods list of methods we want to run. Valid values currently: edge_density,avg_degree,degree_dist,global_cc, avg_cc, local_ccs */ -int parse_options(int argc, char **argv, string& infile, string& intype, string& outfilename, string &outprefix, std::map& methods){ + +int parse_options(int argc, char **argv, string& infile, string& intype, string& outfilename, string &outprefix, std::map& methods, bool& record_timings, bool &file_append, int *spectrum_spread, string &apsp_input){ int flags, opt; - while((opt = getopt(argc, argv, "hi:t:o:m:p:")) != -1){ + while((opt = getopt(argc, argv, "hi:t:o:m:p:s:rax:")) != -1){ switch(opt){ case 'h': print_usage(argv); @@ -95,170 +102,460 @@ int parse_options(int argc, char **argv, string& infile, string& intype, string& case 'm': create_map(optarg, methods); break; + case 'r': + record_timings = true; + break; + case 's': + *spectrum_spread = atoi(optarg); + break; + case 'a': + file_append = true; + break; + case 'x': + apsp_input = optarg; + break; } } return 0; } // parse_options -int main(int argc, char **argv){ - string infile; - string outfilename ("graph-stats.txt"); - string outprefix; - ofstream outfile; - string intype ("edge"); - std::map req_methods; - std::map val_methods; - ORB_t t1, t2; - - create_map(allowed_methods, val_methods); - parse_options(argc, argv, infile, intype, outfilename, outprefix, req_methods); - if(outprefix.length() == 0){ - outprefix = infile; - } - - // we'd like higher precision when printing values - std::cout.precision(10); - - cout << "done parsing options\n"; - cout << "Input file: " << infile << "\n"; - cout << "Input type: " << intype << "\n"; - cout << "Output file: " << outfilename << "\n"; - cout << "Methods :"; - for(map::iterator it = req_methods.begin(); it != req_methods.end(); ++it){ - cout << " " << it->first; - if(val_methods[it->first] != true){ - cerr << "Error: " << it->first << " is not a valid method! " << endl; - } - } - cout << "\n"; - cout << "Calibrating timers\n"; - ORB_calibrate(); - - // let's do some calculations - - Graph::Graph g; +void run_all_methods(Graph::Graph *g, ofstream &outfile, ofstream &timing_file, string outprefix, std::map req_methods, bool &file_append, int spectrum_spread){ Graph::GraphReader gr; Graph::GraphProperties gp; - - cout << "Reading graph\n"; - ORB_read(t1); - if(gr.read_graph(&g, infile, intype, false) == -1){ - exit(1); - } - ORB_read(t2); - print_time("Time(read_graph)", t1, t2); + Graph::GraphUtil gu; + ORB_t t1, t2; double global_cc, avg_cc, assortativity; - vector local_cc, freq_ecc, norm_hops; + + vector local_cc, freq_ecc, norm_hops, eigen_spectrum; float edge_density, avg_degree; vector deg_dist, ecc; - vector< vector > shortest_path_distances; + int degeneracy; + vector k_cores; + double avg_path_length; + int xmin; + double alpha, KS, max_delta; + vector > delta; + vector betweenness; - outfile.open(outfilename.c_str()); - if(!outfile.is_open()){ - cerr << "Error opening " << outfilename << " for writing, exiting\n"; - exit(1); - } + Graph::Graph *largest_component; - outfile.precision(16); + vector< vector > shortest_path_distances; - cout << "Simplifying graph\n"; + cout << "Simplifying graph" << endl; ORB_read(t1); - gp.make_simple(&g); + gp.make_simple(g); ORB_read(t2); - print_time("Time(make_simple)", t1, t2); - - outfile << "num_nodes " << g.get_num_nodes() << "\n"; - outfile << "num_edges " << g.get_num_edges() << "\n"; + print_time(timing_file, "Time(make_simple)", t1, t2); + int num_components = g->get_num_connected_components(); + outfile << "connected_components " << num_components << endl; if(req_methods["edge_density"] == true){ - cout << "Calculating edge density\n"; + cout << "Calculating edge density" << endl; ORB_read(t1); - gp.edge_density(&g, edge_density); + gp.edge_density(g, edge_density); ORB_read(t2); - print_time("Time(edge_density)", t1, t2); - outfile << "edge_density " << edge_density << "\n"; + print_time(timing_file, "Time(edge_density)", t1, t2); + outfile << "edge_density " << edge_density << endl; } if(req_methods["avg_degree"] == true){ - cout << "Calculating average degree\n"; + cout << "Calculating average degree" << endl; ORB_read(t1); - gp.avg_degree(&g, avg_degree); + gp.avg_degree(g, avg_degree); ORB_read(t2); - print_time("Time(average_degree)", t1, t2); - outfile << "avg_degree " << avg_degree << "\n"; + print_time(timing_file, "Time(average_degree)", t1, t2); + outfile << "avg_degree " << avg_degree << endl; } if(req_methods["degree_dist"] == true){ - cout << "Calculating degree distribution\n"; + cout << "Calculating degree distribution" << endl; ORB_read(t1); - gp.deg_dist(&g, deg_dist); + gp.deg_dist(g, deg_dist); ORB_read(t2); - print_time("Time(degree_distribution)", t1, t2); + print_time(timing_file, "Time(degree_distribution)", t1, t2); string of = outprefix + ".deg_dist"; write_degree_distribution(of, deg_dist); - outfile << "degree_distribution " << of << "\n"; + outfile << "degree_distribution " << of << endl; } if(req_methods["assortativity"] == true){ - cout << "Calculating degree assortativity\n"; + cout << "Calculating degree assortativity" << endl; + ORB_read(t1); + gp.deg_assortativity(g, assortativity); + ORB_read(t2); + print_time(timing_file, "Time(assortativity)", t1, t2); + outfile << "assortativity " << assortativity << endl; + } + if((req_methods["degeneracy"] == true) || (req_methods["k_cores"] == true)){ + cout << "Calculating k_cores and degeneracy" << endl; ORB_read(t1); - gp.deg_assortativity(&g, assortativity); + degeneracy = gu.find_kcore(g, &k_cores); ORB_read(t2); - print_time("Time(assortativity)", t1, t2); - outfile << "assortativity " << assortativity << "\n"; + print_time(timing_file, "Time(find_kcore)", t1, t2); + outfile << "degeneracy " << degeneracy << endl; + if(req_methods["k_cores"] == true){ + string of = outprefix + ".kcores"; + outfile << "kcore file " << of << endl; + write_kcores(of, k_cores); + } } + if((req_methods["global_cc"] == true) || (req_methods["local_ccs"] == true) || (req_methods["avg_cc"] == true)){ - cout << "Calculating clustering coefficients\n"; + cout << "Calculating clustering coefficients" << endl; ORB_read(t1); - gp.clustering_coefficients(&g, global_cc, avg_cc, local_cc); + gp.clustering_coefficients(g, global_cc, avg_cc, local_cc); ORB_read(t2); - print_time("Time(clustering_coeffecients)", t1, t2); + print_time(timing_file, "Time(clustering_coeffecients)", t1, t2); if(req_methods["global_cc"] == true){ - outfile << "global_clustering_coefficient " << global_cc << "\n"; + outfile << "global_clustering_coefficient " << global_cc << endl; } if(req_methods["avg_cc"] == true){ - outfile << "average_clustering_coefficient " << avg_cc << "\n"; + outfile << "average_clustering_coefficient " << avg_cc << endl; } if(req_methods["local_ccs"] == true){ } } - if(req_methods["shortest_paths"] == true){ - cout << "Calculating shortest paths\n"; + cout << "Calculating shortest paths" << endl; ORB_read(t1); - gp.paths_dijkstra_all(&g, shortest_path_distances); + gp.paths_dijkstra_all(g, shortest_path_distances); ORB_read(t2); - print_time("Time(shortest_paths_dijkstra)", t1, t2); + print_time(timing_file, "Time(shortest_paths_dijkstra)", t1, t2); } - if(req_methods["eccentricity"] == true){ - cout << "Calculating eccentricities\n"; + + #ifdef HAS_BOOST + if((req_methods["shortest_paths_boost"] == true)){ + cout << "Creating BOOST representation of g" << endl; + ORB_read(t1); + gu.populate_boost(g); + ORB_read(t2); + print_time(timing_file, "Time(populate_boost)", t1, t2); + cout << "Calculating shortest paths (boost)" << endl; ORB_read(t1); - gp.eccentricity(&g, ecc); + gp.paths_dijkstra_boost_all(g, shortest_path_distances); ORB_read(t2); - print_time("Time(eccentricity)",t1,t2); + print_time(timing_file, "Time(shortest_paths_dijkstra_boost)", t1, t2); } - if(req_methods["eccentricity_dist"] == true){ - cout << "Calculating distribution of eccentricities\n"; + if(req_methods["betweenness"]){ + /* cout << "Creating BOOST representation of g" << endl; + ORB_read(t1); + gu.populate_boost(g); + ORB_read(t2); + print_time(timing_file, "Time(populate_boost)", t1, t2); + */cout << "Calculating betweeneess centrality" << endl; ORB_read(t1); - gp.eccentricity_dist(&g, ecc, freq_ecc); + gp.betweenness_centrality(g, betweenness); ORB_read(t2); - print_time("Time(eccentricity distribution)",t1,t2); + print_time(timing_file, "Time(betweenness_centrality",t1,t2); + string of = outprefix + ".betweenness"; + outfile << "betweenness_file " << of << endl; + write_betweenness(of, g->get_betweenness_ref()); + } + #else // ifdef HAS_BOOST + cerr << "Error: BOOST support was not compiled, cannot run shortest_paths_boost or betweenness" << endl; + #endif // ifdef HAS_BOOST + + if(num_components == 1){ + if(req_methods["eccentricity"] == true){ + cout << "Calculating eccentricities" << endl; + ORB_read(t1); + gp.eccentricity(g, ecc); + ORB_read(t2); + print_time(timing_file, "Time(eccentricity)",t1,t2); + string of = outprefix + ".eccentricity"; + outfile << "eccentricity_file " << of << endl; + write_eccentricity(of, ecc); + } + if(req_methods["eccentricity_dist"] == true){ + cout << "Calculating distribution of eccentricities" << endl; + ORB_read(t1); + gp.eccentricity_dist(g, ecc, freq_ecc); + ORB_read(t2); + print_time(timing_file, "Time(eccentricity distribution)",t1,t2); + string of = outprefix + ".eccentricity_dist"; + outfile << "eccentricity_dist_file " << of << endl; + write_eccentricity_distribution(of, freq_ecc); + } + } + else { + cout << "Graph is disconnected - not calculating eccentricities" << endl; } + if(req_methods["expansion"] == true){ - cout << "Calculating normalized expansion (distance distribution) - no self loops allowed\n"; + cout << "Calculating normalized expansion (distance distribution) - no self loops allowed" << endl; + ORB_read(t1); + gp.expansion(g, norm_hops); + ORB_read(t2); + print_time(timing_file, "Time(expansion)",t1,t2); + string of = outprefix + ".expansion"; + outfile << "expansion_file " << of << endl; + write_expansion(of, norm_hops); + } + if(req_methods["avg_shortest_path"] == true){ + cout << "Calculating average shortest path length" << endl; + ORB_read(t1); + gp.avg_path_length(g, avg_path_length); + ORB_read(t2); + print_time(timing_file, "Time(avg_path_length)", t1, t2); + outfile << "avg_path_length " << avg_path_length << endl; + } + if((req_methods["apsp_output"] == true)){ + string of = outprefix + ".apsp"; + ORB_read(t1); + write_apsp_matrix(of, shortest_path_distances); + ORB_read(t2); + print_time(timing_file, "Time(write_apsp_matrix)", t1, t2); + } + + #ifdef HAS_PETSC + if(req_methods["eigen_spectrum"] == true){ + //If petsc/slepc are present, initalize those. + //If MPI support is added in the future, init MPI before Petsc. Petsc will do it's own MPI + //init if MPI isn't already inited. + #ifdef HAS_SLEPC + SlepcInitializeNoArguments(); + #elif HAVE_PETSC + PetscInitializeNoArguments(); + #endif + if(spectrum_spread == 0){ + spectrum_spread = 3; + } + + cout << "Calculating adjacency matrix eigen spectrum\n"; ORB_read(t1); - gp.expansion(&g, norm_hops); + gp.eigen_spectrum(g, eigen_spectrum, spectrum_spread); ORB_read(t2); - print_time("Time(expansion)",t1,t2); + print_time(timing_file, "Time(eigen spectrum)",t1,t2); + outfile << "eigen_spectrum "; + for(int idx = 0; idx < eigen_spectrum.size(); idx++){ + outfile << eigen_spectrum[idx]; + } + outfile << "\n"; } + #endif // ifdef HAS_PETSC + #ifdef HAS_BOOST + if(req_methods["powerlaw"] == true){ + cout << "Calculating power law parameters" << endl; + ORB_read(t1); + gp.powerlaw(g, xmin, alpha, KS); + ORB_read(t2); + + print_time(timing_file, "Time(powerlaw)", t1, t2); + outfile << "powerlaw " << xmin << " " << alpha << " " << KS << endl; + } + #else + cerr << "Error: BOOST support was not compiled, cannot run shortest_paths_boost or betweenness" << endl; + #endif //HAS_BOOST + if(num_components == 1){ + if(req_methods["delta_hyperbolicity"] == true){ + cout << "Calculating delta hyperbolicity" << endl; + ORB_read(t1); + gp.delta_hyperbolicity(g, max_delta, delta); + ORB_read(t2); + + print_time(timing_file, "Time(delta_hyperbolicity)", t1, t2); + //outfile << "delta_hyperbolicity " << max_delta << endl; + //for(int idx = 0; idx < delta.size(); idx++){ + // for(int jdx = 0; jdx < delta[idx].size(); jdx++){ + // outfile << delta[idx][jdx] << " "; + // } + // outfile << endl; + //} + string of = outprefix + ".delta_hyp"; + write_delta_hyperbolicity(of, delta); + outfile << "max_delta_hyperbolicity " << max_delta; + } + } + else { + cout << "Graph is disconnected - not calculating delta hyperbolicity" << endl; + } + + outfile.close(); + + #ifdef HAS_SLEPC + SlepcFinalize(); + #elif HAVE_PETSC + PetscFinalize(); + #endif +} // run_all_methods + +int main(int argc, char **argv){ + string infile; + string outfilename; + string outprefix; + string apspinputfilename; + ofstream outfile; + ofstream timing_file; + bool record_timings = false; + bool file_append = false; + string intype ("edge"); + std::map req_methods; + std::map val_methods; + ORB_t t1, t2; + int spectrum_spread = 0; + create_map(allowed_methods, val_methods); + parse_options(argc, argv, infile, intype, outfilename, outprefix, req_methods, record_timings, file_append, &spectrum_spread, apspinputfilename); + if(outfilename.length() == 0){ + if(outprefix.length() != 0){ + outfilename = outprefix + ".stats"; + } + else { + outfilename = "graph-stats.txt"; + } + } + if(outprefix.length() == 0){ + outprefix = infile; + } + + // we'd like higher precision when printing values + std::cout.precision(10); + + cout << "done parsing options" << endl; + cout << "Input file: " << infile << endl; + cout << "Input type: " << intype << endl; + cout << "Output file: " << outfilename << endl; + cout << "Appending : "; + cout << std::boolalpha << file_append << endl; + cout << "Methods :"; + for(map::iterator it = req_methods.begin(); it != req_methods.end(); ++it){ + cout << " " << it->first; + if(val_methods[it->first] != true){ + cerr << "Error: " << it->first << " is not a valid method! " << endl; + } + } + cout << endl; + cout << "Calibrating timers" << endl; + ORB_calibrate(); + + // let's do some calculations + + Graph::Graph *g = new(Graph::Graph); + Graph::GraphReader gr; + Graph::GraphProperties gp; + Graph::GraphUtil gu; + + // Set up output streams + if(file_append == false){ + outfile.open(outfilename.c_str()); + } + else { + outfile.open(outfilename.c_str(), ios_base::out | ios_base::app); + } + if(!outfile.is_open()){ + cerr << "Error opening " << outfilename << " for writing, exiting" << endl; + exit(1); + } + + // Read in the graph and start recording things to output streams + cout << "Reading graph" << endl; + ORB_read(t1); + if(gr.read_graph(g, infile, intype, false) == -1){ + exit(1); + } + ORB_read(t2); + + if(outfile.tellp() == 0){ + outfile << "filename " << infile << endl; + outfile << "num_nodes " << g->get_num_nodes() << endl; + outfile << "num_edges " << g->get_num_edges() << endl; + } + + if(record_timings){ + string of = outfilename + ".timings"; + if(file_append == false){ + timing_file.open(of.c_str()); + } + else { + timing_file.open(of.c_str(), ios_base::out | ios_base::app); + } + if(!timing_file.is_open()){ + cerr << "Error opening " << timing_file << " for writing, exiting" << endl; + exit(1); + } + outfile << "timing_file " << of << endl; + } + + print_time(timing_file, "Time(read_graph)", t1, t2); + + if(apspinputfilename.length() != 0){ + cout << "Reading APSP matrix from " << apspinputfilename << endl; + vector< vector > *apsp_dists = new vector< vector >; + ORB_read(t1); + read_apsp_matrix(apspinputfilename, *apsp_dists); + ORB_read(t2); + print_time(timing_file, "Time(read_apsp_matrix)", t1, t2); + g->set_shortest_path_dist(apsp_dists); + } + + outfile.precision(16); + vector components; + ORB_read(t1); + cout << "GU.label_all_components says: " << gu.label_all_components(g, &components) << endl; + ORB_read(t2); + print_time(timing_file, "Time(label_all_components)", t1, t2); + bool is_connected = gp.is_connected(g); + cout << "Connected components: " << g->get_num_connected_components() << endl; + cout << "Graph is connected: " << std::boolalpha << is_connected << endl; + + run_all_methods(g, outfile, timing_file, outprefix, req_methods, file_append, spectrum_spread); outfile.close(); + timing_file.close(); + + // some algorithms only make sense to run on a connected graph/component + if(not is_connected){ // run everything against the other algorithms + cout << "Graph is not connected, re-running stats on largest connected component" << endl; + outfilename = outprefix + ".largest_component.stats"; + if(file_append == false){ + outfile.open(outfilename.c_str()); + } + else { + outfile.open(outfilename.c_str(), ios_base::out | ios_base::app); + } + if(!outfile.is_open()){ + cerr << "Error opening " << outfilename << " for writing, exiting" << endl; + exit(1); + } + + // get the largest component + Graph::Graph *largest_component = gu.get_largest_component_graph(g); + delete(g); // delete g here to save on memory + + if(outfile.tellp() == 0){ + outfile << "filename " << infile << endl; + outfile << "num_nodes " << largest_component->get_num_nodes() << endl; + outfile << "num_edges " << largest_component->get_num_edges() << endl; + } + if(record_timings){ + string of = outfilename + ".timings"; + if(file_append == false){ + timing_file.open(of.c_str()); + } + else { + timing_file.open(of.c_str(), ios_base::out | ios_base::app); + } + + if(!timing_file.is_open()){ + cerr << "Error opening " << timing_file << " for writing, exiting" << endl; + exit(1); + } + outfile << "timing_file " << of << endl; + } + + outprefix = outprefix + ".largest_component"; + + outfile.precision(16); + run_all_methods(largest_component, outfile, timing_file, outprefix, req_methods, file_append, spectrum_spread); + outfile.close(); + timing_file.close(); + } + exit(0); } // main -#else -int main() -{ - fprintf(stderr,"Can't run under windows or cygwin\n"); - return 0; +#else // if !WIN32 && !CYGWIN +int main(){ + fprintf(stderr,"Can't run under windows or cygwin\n"); + return 0; } -#endif + +#endif // if !WIN32 && !CYGWIN diff --git a/util/src/orbtimer.cpp b/util/src/orbtimer.cpp index d53302a..0f6e1a8 100644 --- a/util/src/orbtimer.cpp +++ b/util/src/orbtimer.cpp @@ -28,26 +28,26 @@ * **************************************************************************/ #if !WIN32 -#if !CYGWIN + #if !CYGWIN -#include -#include -#include "orbconfig.h" + #include + #include + #include "orbconfig.h" -#define ORBTIMER_LIBRARY -#include "orbtimer.h" + #define ORBTIMER_LIBRARY + #include "orbtimer.h" static ORB_tick_t Csum = 0; static ORB_tick_t Gsum = 0; static ORB_tick_t nsamples = 0; static ORB_tick_t ndummy = 0; -#endif + #endif #endif void ORB_calibrate(){ -#if WIN32 || CYGWIN || _CYGWIN - return; -#else + #if WIN32 || CYGWIN || _CYGWIN + return; + #else int i, j; double seconds; struct timeval tv1, tv2; @@ -111,8 +111,6 @@ void ORB_calibrate(){ ORB_min_lat_sec = ORB_min_lat_cyc / ORB_ref_freq; GTD_avg_lat_sec = GTD_avg_lat_cyc / ORB_ref_freq; GTD_min_lat_sec = GTD_min_lat_cyc / ORB_ref_freq; -#endif + #endif // if WIN32 || CYGWIN || _CYGWIN } // ORB_calibrate - - diff --git a/util/src/shortest-paths.cpp b/util/src/shortest-paths.cpp index 8f3daca..1af6eaa 100644 --- a/util/src/shortest-paths.cpp +++ b/util/src/shortest-paths.cpp @@ -65,21 +65,26 @@ int main(int argc, char **argv){ //compute shortest paths from source node begin = clock(); //for each node run it - int source = 0; + int source = 8; vector onePaths; printf("\nRunning Dijsktra for source %d\n",source); prop.paths_dijkstra_single(g, onePaths, source); end = clock(); + + int i; + for(i = 0; i < onePaths.size(); i++){ + printf("%d: %d\n", i, onePaths[i]); + } printf("Alg Time (single): %f\n", double(end - begin) / CLOCKS_PER_SEC); //compute all pairs shortest paths begin = clock(); - vector< vector > allPaths; +// vector< vector > allPaths; - printf("\nRunning Dijsktra for all pairs \n"); - prop.paths_dijkstra_all(g,allPaths); //alternate: vector< vector > pt2 = g->get_shortest_path_dist_ref(); - end = clock(); - printf("Alg Time (all): %f\n", double(end - begin) / CLOCKS_PER_SEC); + // printf("\nRunning Dijsktra for all pairs \n"); + // prop.paths_dijkstra_all(g,allPaths); //alternate: vector< vector > pt2 = g->get_shortest_path_dist_ref(); + // end = clock(); + //printf("Alg Time (all): %f\n", double(end - begin) / CLOCKS_PER_SEC); } // main diff --git a/viz/Makefile b/viz/Makefile index ea3fc83..37fe59e 100644 --- a/viz/Makefile +++ b/viz/Makefile @@ -3,9 +3,9 @@ include ../make.inc VIZ_SRC = ./src/viz_main.cpp ./src/viz.cpp VIZ_EXE = $(INDDGO_BIN)/td_viz -INC_DIR= -I./inc -I$(GRAPH)/inc -I$(TREE)/inc $(METIS_INCLUDES) $(SSPARSE_INCDIR) $(UTHASH_INCDIR) $(GMP_INCDIR) $(MADNESS_INCDIR) $(PARMETIS_INCDIR) +INC_DIR= -I./inc -I$(GRAPH)/inc -I$(TREE)/inc $(METIS_INCLUDES) $(SSPARSE_INCDIR) $(UTHASH_INCDIR) $(GMP_INCDIR) $(MADNESS_INCDIR) $(PARMETIS_INCDIR) $(SLEPC_INCDIR) $(PETSC_INCDIR) -LIBS = -lm $(INDDGO_LIB) -ltreed -lgraphd $(SSPARSE_LIB) $(ARPACK_LIB) $(GMP_LIB) $(PARMETIS_LIB) $(METIS_LIB) +LIBS = -lm $(INDDGO_LIB) -ltreed -lgraphd $(SSPARSE_LIB) $(ARPACK_LIB) $(GMP_LIB) $(PARMETIS_LIB) $(METIS_LIB) $(SLEPC_LIB) $(PETSC_LIB) VIZ_OBJ=$(VIZ_SRC:.cpp=.o)