-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #57 from Bears-R-Us/four-cycles
Four cycles (squares)
- Loading branch information
Showing
8 changed files
with
341 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -133,3 +133,6 @@ dmypy.json | |
|
||
# Old Arkouda-NJIT stuff | ||
GraphServerModules.cfg.* | ||
|
||
# Random server things | ||
(nil) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
"""Square Counts Benchmark | ||
This script provides a benchmark on a graph that is randomly generated or specified by a matrix | ||
market file. The random graphs are generated by using the ak.randint function with the range of the | ||
vertex names being picked from [0,n-1] and the number of edges m. No special distribution is used to | ||
generate the graph. Select seed value to ensure repeatability of experiments. | ||
Assumes Arkouda server is running. It will shutdown the Arkouda server upon completion. | ||
""" | ||
import argparse | ||
import os | ||
import time | ||
import statistics as st | ||
import arachne as ar | ||
import arkouda as ak | ||
|
||
def create_parser(): | ||
"""Creates the command line parser for this script""" | ||
parser = argparse.ArgumentParser( | ||
description="Simple benchmark for breadth-first search on randomly generated sample graphs." | ||
) | ||
parser.add_argument("hostname", help = "Hostname of the arkouda server") | ||
parser.add_argument("port", type = int, default = 5555, | ||
help = "Port used by the arkouda server") | ||
|
||
parser.add_argument("--rand", action="store_true", help = "Run random benchmark?") | ||
parser.add_argument("-n", type = int, default = 1000, help = "Number of vertices for graph") | ||
parser.add_argument("-m", type = int, default = 2000, help = "Number of edges for graph") | ||
|
||
parser.add_argument("--mtx", action="store_true", help = "Run mtx benchmark?") | ||
parser.add_argument("--filepath", type = str, default = "../data/karate.mtx", | ||
help = ".mtx file to benchmark") | ||
parser.add_argument("--is_directed", action="store_true", help = "Is graph directed?") | ||
|
||
parser.add_argument("-t", "--trials", type = int, default = 5, | ||
help = "Number of trials for BFS" | ||
) | ||
parser.add_argument("-s", "--seed", type = int, default = 2, help = "Set seed for randomness.") | ||
|
||
return parser | ||
|
||
def run_rand_benchmark(args): | ||
"""Runs rand benchmark and prints out results to terminal.""" | ||
### Build graph from randomly generated source and destination arrays. | ||
# 1. Use Arkouda's randint to generate the random edge arrays. | ||
src = ak.randint(0, args.n, args.m, seed=args.seed*2) | ||
dst = ak.randint(0, args.n, args.m, seed=args.seed*4) | ||
|
||
# 2. Build undirected graph. | ||
print("### Arachne Graph Building") | ||
start = time.time() | ||
graph = ar.Graph() | ||
graph.add_edges_from(src, dst) | ||
end = time.time() | ||
print(f"Building undirected graph with {len(graph)} vertices and {graph.size()} edges " | ||
f"took {round(end-start,2)} seconds") | ||
|
||
edges = graph.edges() | ||
print(edges[0]) | ||
print(edges[1]) | ||
|
||
print() | ||
print("### Arachne Square Count") | ||
### Run Arachne square count on the input graph. | ||
# 1. Square count on undirected graph. | ||
square_count_trials = [] | ||
for _ in range(args.trials): | ||
start = time.time() | ||
square_count = ar.squares(graph) | ||
end = time.time() | ||
square_count_trials.append(end-start) | ||
avg_runtime = round(st.mean(square_count_trials),2) | ||
print(f"Running square count on undirected graph took on average {avg_runtime} seconds and " | ||
f"counted {square_count} squares with max degree {ak.max(graph.degree())}") | ||
|
||
# 3. Print out times in comma-delimited manner. | ||
print("### Full Timings") | ||
square_count_trials = [round(x,2) for x in square_count_trials] | ||
print(f"square_count_trials = {square_count_trials}") | ||
|
||
def run_mtx_benchmark(args): | ||
"""Runs mtx benchmark and prints out results to terminal.""" | ||
### Build graph from matrix market file. | ||
# 1. Use Arachne's matrix_market reading method. | ||
print("### Arachne Graph Building") | ||
start = time.time() | ||
graph = ar.read_matrix_market_file(os.path.abspath(args.filepath), args.is_directed) | ||
end = time.time() | ||
graph_type = "directed" if args.is_directed else "undirected" | ||
print(f"Building {graph_type} graph with {len(graph)} vertices and {graph.size()} edges took " | ||
f"{round(end-start,2)} seconds") | ||
|
||
print() | ||
print("### Arachne Square Count") | ||
### Run Arachne square count on the input graph. | ||
# 1a. Sequential square count on undirected graph. | ||
square_count_trials = [] | ||
for _ in range(args.trials): | ||
start = time.time() | ||
square_count = ar.squares(graph) | ||
end = time.time() | ||
square_count_trials.append(end-start) | ||
avg_runtime = round(st.mean(square_count_trials),2) | ||
print(f"Running sequential square count on undirected graph took on average {avg_runtime} " | ||
f"seconds and counted {square_count} squares with max degree {ak.max(graph.degree())}") | ||
|
||
# 1b. Print out times in comma-delimited manner. | ||
print("### Full Timings") | ||
square_count_trials = [round(x,2) for x in square_count_trials] | ||
print(f"square_count_trials = {square_count_trials}") | ||
|
||
if __name__ == "__main__": | ||
# Command line parser and extraction. | ||
benchmark_parser = create_parser() | ||
in_args = benchmark_parser.parse_args() | ||
|
||
# Connect to the Arkouda server. | ||
ak.verbose = False | ||
ak.connect(in_args.hostname, in_args.port) | ||
|
||
if in_args.rand: | ||
print("\n##### RAND BENCHMARK") | ||
run_rand_benchmark(in_args) | ||
|
||
if in_args.mtx: | ||
filename = in_args.filepath.split("/")[-1] | ||
print(f"\n##### MTX BENCHMARK FOR GRAPH {filename}") | ||
run_mtx_benchmark(in_args) | ||
|
||
if not in_args.rand and not in_args.mtx: | ||
print("Unrecognized benchmark type. Terminating.") | ||
|
||
ak.shutdown() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,5 +4,6 @@ BreadthFirstSearchMsg | |
PropertyGraphMsg | ||
TriCtrMsg | ||
TriangleCountMsg | ||
SquareCountMsg | ||
TrussMsg | ||
CCMsg |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
module SquareCount { | ||
// Arachne modules. | ||
use GraphArray; | ||
|
||
// Arkouda modules. | ||
use MultiTypeSymbolTable; | ||
use MultiTypeSymEntry; | ||
use ServerConfig; | ||
use AryUtil; | ||
|
||
/** | ||
* Total degree order operator u << v compares the degrees of the two nodes and returns | ||
* true if the degree of u is less than the degree of v, or if equal, if the integer specifier | ||
* of u is less than that of v. | ||
* | ||
* :arg u: vertex u | ||
* :type u: int | ||
* :arg v: vertex v | ||
* :type v: int | ||
* :arg degree: array containing degrees | ||
* :type degree: [?D] int | ||
* | ||
* :returns: bool */ | ||
inline proc nodeCompare(u: int, v: int, ref degree): bool { | ||
if degree[u] < degree[v] then return true; | ||
else if degree[u] == degree[v] && u < v then return true; | ||
else return false; | ||
} | ||
|
||
/** | ||
* Sequential square counting for an undirected graph. | ||
* | ||
* :arg graph: SegGraph to run square counting on. | ||
* :type graph: SegGraph | ||
* | ||
* :returns: int */ | ||
proc squareCountSequential(graph:SegGraph, degree:[?D1] int):int throws { | ||
var src = toSymEntry(graph.getComp("SRC"),int).a; | ||
var dst = toSymEntry(graph.getComp("DST"),int).a; | ||
var seg = toSymEntry(graph.getComp("SEGMENTS"),int).a; | ||
|
||
var square_count:int = 0; | ||
var L : [0..<graph.n_vertices] int; | ||
L = 0; | ||
|
||
for v in L.domain { | ||
var v_adj_list_start = seg[v]; | ||
var v_adj_list_end = seg[v+1] - 1; | ||
ref v_neighborhood = dst.localSlice(v_adj_list_start..v_adj_list_end); | ||
for u in v_neighborhood { | ||
if nodeCompare(u,v,degree) { | ||
var u_adj_list_start = seg[u]; | ||
var u_adj_list_end = seg[u+1] - 1; | ||
ref u_neighborhood = dst.localSlice(u_adj_list_start..u_adj_list_end); | ||
for y in u_neighborhood { | ||
if nodeCompare(y,v,degree) { | ||
square_count += L[y]; | ||
L[y] += 1; | ||
} | ||
} | ||
} | ||
} | ||
for u in v_neighborhood { | ||
if (nodeCompare(u,v,degree)) { | ||
var u_adj_list_start = seg[u]; | ||
var u_adj_list_end = seg[u+1] - 1; | ||
ref u_neighborhood = dst.localSlice(u_adj_list_start..u_adj_list_end); | ||
for y in u_neighborhood { | ||
L[y] = 0; | ||
} | ||
} | ||
} | ||
} | ||
return square_count; | ||
} | ||
} |
Oops, something went wrong.