diff --git a/.gitignore b/.gitignore index e643a5f..b62b64b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ # IDEA configurations /.idea + +# Doc files +/docs* \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 58ea840..89954b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${GraphMLIR_BINARY_DIR}) set(GraphMLIR_EXAMPLES OFF CACHE BOOL "Build examples") +set(GraphMLIR_BENCHMARK OFF CACHE BOOL "Benchmark the Graph Algorithms") + # Add MLIR and LLVM headers to the include path include_directories(${LLVM_INCLUDE_DIRS}) include_directories(${MLIR_INCLUDE_DIRS}) @@ -68,8 +70,11 @@ include_directories(${MLIR_INCLUDE_DIRS}) # Add GraphMLIR files to the include path include_directories(${GraphMLIR_MAIN_INCLUDE_DIR}) include_directories(${GraphMLIR_INCLUDE_DIR}) +include_directories(${GraphMLIR_INCLUDE_DIR}/Interface) include_directories(${GraphMLIR_INCLUDE_DIR}/Dialect) +include_directories(${GraphMLIR_INCLUDE_DIR}/Utility) include_directories(${CMAKE_CURRENT_BINARY_DIR}/include/Dialect) +include_directories(${GraphMLIR_SOURCE_DIR}/lib) #------------------------------------------------------------------------------- # Directory setup @@ -82,3 +87,44 @@ add_subdirectory(tools) if(GraphMLIR_EXAMPLES) add_subdirectory(examples) endif() + +if(GraphMLIR_BENCHMARK) +#------------------------------------------------------------------------------- +# Deploy google/benchmark +#------------------------------------------------------------------------------- + + message(STATUS "Configuring benchmarks: google") + + include(ExternalProject) + + ExternalProject_Add(project_googlebenchmark + GIT_REPOSITORY https://github.com/google/benchmark.git + GIT_TAG "v1.6.0" + GIT_SHALLOW 1 + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/vendor/benchmark + TIMEOUT 10 + BUILD_BYPRODUCTS /lib/${CMAKE_STATIC_LIBRARY_PREFIX}benchmark${CMAKE_STATIC_LIBRARY_SUFFIX} + CMAKE_ARGS + -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/vendor/benchmark + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DBENCHMARK_ENABLE_TESTING=OFF + UPDATE_COMMAND "" + TEST_COMMAND "") + + ExternalProject_Get_Property(project_googlebenchmark INSTALL_DIR) + + file(MAKE_DIRECTORY ${INSTALL_DIR}/include) + add_library(GoogleBenchmark STATIC IMPORTED) + target_include_directories(GoogleBenchmark INTERFACE ${INSTALL_DIR}/include) + set_property(TARGET GoogleBenchmark PROPERTY IMPORTED_LOCATION + "${INSTALL_DIR}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}benchmark${CMAKE_STATIC_LIBRARY_SUFFIX}") + + add_dependencies(GoogleBenchmark project_googlebenchmark) + + find_package(Threads) + target_link_libraries(GoogleBenchmark INTERFACE Threads::Threads) +endif() + +if(GraphMLIR_BENCHMARK) + add_subdirectory(benchmarks) +endif() \ No newline at end of file diff --git a/README.md b/README.md index 6f584f5..ed8cf60 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # GraphMLIR + An IR based solution for optimising graph algorithms. ## Clone repository and its dependencies + ``` git clone https://github.com/meshtag/GraphMLIR.git cd GraphMLIR @@ -9,6 +11,7 @@ git submodule update --init ``` ## Build LLVM + ``` cd llvm && mkdir build && cd build cmake -G Ninja ../llvm \ @@ -21,6 +24,7 @@ ninja check-mlir ``` ## Build project + ``` cd ../../ && mkdir build && cd build cmake -G Ninja .. \ @@ -32,3 +36,27 @@ cmake -G Ninja .. \ ninja bfsExample cd bin && ./bfsExample ``` + +## Benchmark project + +``` +cmake -G Ninja .. \ + -DMLIR_DIR=$PWD/../llvm/build/lib/cmake/mlir \ + -DLLVM_DIR=$PWD/../llvm/build/lib/cmake/llvm \ + -DLLVM_ENABLE_ASSERTIONS=ON \ + -DCMAKE_BUILD_TYPE=RELEASE \ + -DGraphMLIR_BENCHMARK=ON \ + -DLEMON_DIR=/PATH/TO/LEMON/SOURCE/CODE +ninja graph-processing-benchmark +cd bin && ./graph-processing-benchmark +``` + +_Note_ : Rename the `lemon.1.x.x` folder to `lemon`. For benchmarking install `BOOST` library in system. + +## Instructions for generating docs + +``` +Use doxywizard for generating docs automatically from relevant source directories. +``` + +#### After this go to docs and open index.html in the html subdirectory with your prefered browser. diff --git a/benchmarks/Bfs.cpp b/benchmarks/Bfs.cpp new file mode 100644 index 0000000..b3f59e4 --- /dev/null +++ b/benchmarks/Bfs.cpp @@ -0,0 +1,80 @@ +#include +#include + +using namespace std; + +#define V 1000 + +namespace { +int graph[V][V]; +int parent[V]; +int dist[V]; +} // namespace + +void bfs(int graph[V][V], int *parent, int *dist) { + bool visited[V]; + + for (int i = 0; i < V; i++) + visited[i] = false; + + queue q; + + visited[0] = true; + q.push(0); + + while (!q.empty()) { + int u = q.front(); + q.pop(); + + for (int v = 0; v < V; v++) { + if (visited[v] == false && graph[u][v] != 0) { + visited[v] = true; + + dist[v] = dist[u] + graph[u][v]; + parent[v] = u; + + q.push(v); + } + } + } +} + +void initializeBfs() { + int MAX_EDGES = V * (V - 1) / 2; + + for (int i = 0; i < MAX_EDGES; i++) { + int u = rand() % V; + int v = rand() % V; + int d = rand() % 100; + + graph[u][v] = d; + } +} + +static void Bfs(benchmark::State &state) { + for (auto _ : state) { + for (int i = 0; i < state.range(0); i++) { + bfs(graph, parent, dist); + } + } +} + +BENCHMARK(Bfs)->Arg(1); + +void generateResultBfs() { + initializeBfs(); + cout << "-------------------------------------------------------\n"; + cout << "BFS Result Information ]\n"; + + bfs(graph, parent, dist); + + for (int i = 0; i < V; i++) + cout << parent[i] << " "; + cout << endl; + + for (int i = 0; i < V; i++) + cout << dist[i] << " "; + cout << endl; + + cout << "BFS operation finished!\n"; +} \ No newline at end of file diff --git a/benchmarks/BoostBellmanFordBenchmarking.cpp b/benchmarks/BoostBellmanFordBenchmarking.cpp new file mode 100644 index 0000000..4615b87 --- /dev/null +++ b/benchmarks/BoostBellmanFordBenchmarking.cpp @@ -0,0 +1,112 @@ +//===- BoostBellmanforBenchmarking.cpp -----------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the benchmark for Boost Bellmanford example benchmark. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#define SIZE 100 + +namespace { +typedef int t_weight; + +// define the graph type +typedef boost::property EdgeWeightProperty; +typedef boost::adjacency_list + Graph; + +typedef boost::property_map::type WeightMap; + + +Graph g; + +std::vector distnce(SIZE, (std::numeric_limits::max)()); +int source_node_index = 0; +std::vector parent(SIZE); + +} // namespace + +void initializeBoostBellmanFord() { + + const int vertices = SIZE; + int num_edges = vertices * (vertices -1) / 2; + + // define edges + // int edges[] = {1, 2, 2, 3, 3, 4, 4, 1, 1, 3, 2, 4}; + + // t_weight weight[] = {4, 3, 3, 6, 2, 2}; + + std::vector edges; + std::vector weight; + + graph::generateRandomGraph(edges, weight, vertices); + + for (std::size_t k = 0; k < num_edges; ++k) + boost::add_edge(edges[k * 2] - 1, edges[k * 2 + 1] - 1, weight[k], g); + WeightMap weight_pmap = boost::get(boost::edge_weight, g); + + + for (int i = 0; i < num_vertices(g); ++i) + parent[i] = i; + distnce[source_node_index] = 0; + + +} + +// Benchmarking function. +static void Boost_BellmanFord(benchmark::State &state) { + + for (auto _ : state) { + WeightMap weight_pmap = boost::get(boost::edge_weight, g); + + for (int i = 0; i < state.range(0); ++i) { + bool r = bellman_ford_shortest_paths(g, num_vertices(g), weight_pmap, &parent[0], + &distnce[0], boost::closed_plus< int >(), std::less< int >(), + boost::default_bellman_visitor()); + } + } +} + +// Register benchmarking function. +BENCHMARK(Boost_BellmanFord)->Arg(1); + +void generateResultBoostBellmanFord() { + initializeBoostBellmanFord(); + WeightMap weight_pmap = boost::get(boost::edge_weight, g); + for (int i = 0; i < num_vertices(g); ++i) + parent[i] = i; + distnce[source_node_index] = 0; + + cout << "-------------------------------------------------------\n"; + cout << "[ BOOST FloydWarshall Result Information ]\n"; + bool r = bellman_ford_shortest_paths(g, num_vertices(g), weight_pmap, &parent[0], + &distnce[0], boost::closed_plus< int >(), std::less< int >(), + boost::default_bellman_visitor()); + cout << "Boost FloydWarshall operation finished!\n"; +} \ No newline at end of file diff --git a/benchmarks/BoostFloydWarshall.cpp b/benchmarks/BoostFloydWarshall.cpp new file mode 100644 index 0000000..9562b2b --- /dev/null +++ b/benchmarks/BoostFloydWarshall.cpp @@ -0,0 +1,107 @@ +//===- BoostFloyWarshall.cpp +//-------------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the benchmark for Boost FloydWarshall example benchmark. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +namespace { +typedef int t_weight; + +// define the graph type +typedef boost::property EdgeWeightProperty; +typedef boost::adjacency_list + Graph; + +typedef boost::property_map::type WeightMap; + +// Declare a matrix type and its corresponding property map that +// will contain the distances between each pair of vertices. +typedef boost::exterior_vertex_property DistanceProperty; +typedef DistanceProperty::matrix_type DistanceMatrix; +typedef DistanceProperty::matrix_map_type DistanceMatrixMap; +Graph g; +} // namespace + +void initializeBoostFLoydWarshall() { + + const int vertices = 100; + int num_edges = vertices * (vertices -1) / 2; + + // define edges + // int edges[] = {1, 2, 2, 3, 3, 4, 4, 1, 1, 3, 2, 4}; + + // t_weight weight[] = {4, 3, 3, 6, 2, 2}; + + std::vector edges; + std::vector weight; + + graph::generateRandomGraph(edges, weight, vertices); + + for (std::size_t k = 0; k < num_edges; ++k) + boost::add_edge(edges[k * 2] - 1, edges[k * 2 + 1] - 1, weight[k], g); + WeightMap weight_pmap = boost::get(boost::edge_weight, g); + // set the distance matrix to receive the floyd warshall output + DistanceMatrix distances(num_vertices(g)); + DistanceMatrixMap dm(distances, g); + + +} + +// Benchmarking function. +static void Boost_FloydWarshall(benchmark::State &state) { + + for (auto _ : state) { + WeightMap weight_pmap = boost::get(boost::edge_weight, g); + + // set the distance matrix to receive the floyd warshall output + DistanceMatrix distances(num_vertices(g)); + DistanceMatrixMap dm(distances, g); + for (int i = 0; i < state.range(0); ++i) { + bool valid = floyd_warshall_all_pairs_shortest_paths( + g, dm, boost::weight_map(weight_pmap)); + } + } +} + +// Register benchmarking function. +BENCHMARK(Boost_FloydWarshall)->Arg(1); + +void generateResultBoostFLoydWarshall() { + initializeBoostFLoydWarshall(); + WeightMap weight_pmap = boost::get(boost::edge_weight, g); + + // set the distance matrix to receive the floyd warshall output + DistanceMatrix distances(num_vertices(g)); + DistanceMatrixMap dm(distances, g); + cout << "-------------------------------------------------------\n"; + cout << "[ BOOST FloydWarshall Result Information ]\n"; + bool valid = floyd_warshall_all_pairs_shortest_paths( + g, dm, boost::weight_map(weight_pmap)); + cout << "Boost FloydWarshall operation finished!\n"; +} diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt new file mode 100644 index 0000000..565a057 --- /dev/null +++ b/benchmarks/CMakeLists.txt @@ -0,0 +1,59 @@ +ADD_SUBDIRECTORY(${LEMON_DIR} ./lemon) +SET(LEMON_INCLUDE_DIRS + ${LEMON_DIR} + ${CMAKE_BINARY_DIR}/benchmarks/lemon +) +SET(LEMON_LIBRARIES lemon) +UNSET(LEMON_ROOT_DIR CACHE) +UNSET(LEMON_DIR CACHE) +UNSET(LEMON_INCLUDE_DIR CACHE) +UNSET(LEMON_LIBRARY CACHE) + +INCLUDE_DIRECTORIES( + ${LEMON_INCLUDE_DIRS} +) + +add_custom_command(OUTPUT graph.o +COMMAND ${GraphMLIR_BINARY_DIR}/graph-opt ${GraphMLIR_EXAMPLES_DIR}/graph.mlir + -lower-graph -lower-affine -convert-scf-to-cf + -test-vector-multi-reduction-lowering-patterns + -convert-vector-to-llvm + -convert-memref-to-llvm + -llvm-request-c-wrappers + -convert-func-to-llvm + -reconcile-unrealized-casts | + ${LLVM_MLIR_BINARY_DIR}/mlir-translate --mlir-to-llvmir | + ${LLVM_MLIR_BINARY_DIR}/llc -mtriple=${GraphMLIR_OPT_TRIPLE} -mattr=${GraphMLIR_OPT_ATTR} + --filetype=obj -o ${GraphMLIR_BINARY_DIR}/../benchmarks/graph.o +DEPENDS graph-opt) + +add_library(graph STATIC graph.o) + +SET_TARGET_PROPERTIES( +graph +PROPERTIES +LINKER_LANGUAGE C) + +add_executable(graph-processing-benchmark + FloydWarshall.cpp + BoostFloydWarshall.cpp + BoostBellmanFordBenchmarking.cpp + GraphMlirFloydWarshallBenchmark.cpp + GraphMlirBellmanFordBenchmark.cpp + LemonBFS.cpp + LemonBellmanFord.cpp + Main.cpp + GraphMlirBfs.cpp + Bfs.cpp +) + + +find_package(Boost 1.40 COMPONENTS program_options REQUIRED) + +target_link_libraries(graph-processing-benchmark + PRIVATE + ${LEMON_LIBRARIES} + Boost::program_options + graph + GoogleBenchmark +) diff --git a/benchmarks/FloydWarshall.cpp b/benchmarks/FloydWarshall.cpp new file mode 100644 index 0000000..582c57c --- /dev/null +++ b/benchmarks/FloydWarshall.cpp @@ -0,0 +1,90 @@ +//===- FloydWarshall.cpp --------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the benchmark for Floyd Warshall Benchmark. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +// #include + +using namespace std; + +#define V 100 + +namespace { +int input[V][V]; +int output[V][V]; +} // namespace + +void floydWarshall(int graph[][V], int dist[][V]) { + + int i, j, k; + + for (i = 0; i < V; i++) + for (j = 0; j < V; j++) + dist[i][j] = graph[i][j]; + + for (k = 0; k < V; k++) { + for (i = 0; i < V; i++) { + for (j = 0; j < V; j++) { + if (dist[i][j] > (dist[i][k] + dist[k][j])) + dist[i][j] = dist[i][k] + dist[k][j]; + } + } + } +} + +void initializeFloydWarshall() { + int data[4][4] = {{0, 4, 2, 6}, {4, 0, 3, 2}, {2, 3, 0, 3}, {5, 2, 3, 0}}; + + for (int i = 0; i < V; i++) { + for (int j = 0; j < V; j++) { + input[i][j] = 100; + } + } + memset(output, 0, sizeof(output)); +} + +// Benchmarking function. +static void FloydWarshall(benchmark::State &state) { + for (auto _ : state) { + for (int i = 0; i < state.range(0); ++i) { + floydWarshall(input, output); + } + } +} + +// Register benchmarking function. +BENCHMARK(FloydWarshall)->Arg(1); + +void generateResultFloydWarshall() { + initializeFloydWarshall(); + cout << "-------------------------------------------------------\n"; + cout << "[Floyd Warshall Result Information ]\n"; + + floydWarshall(input, output); + + for (int i = 0; i < V; i++) { + for (int j = 0; j < V; j++) { + cout << output[i][j] << " "; + } + cout << "\n"; + } + cout << "FLoyd Warshall operation finished!\n"; +} diff --git a/benchmarks/GraphMlirBellmanFordBenchmark.cpp b/benchmarks/GraphMlirBellmanFordBenchmark.cpp new file mode 100644 index 0000000..33c6f02 --- /dev/null +++ b/benchmarks/GraphMlirBellmanFordBenchmark.cpp @@ -0,0 +1,101 @@ +//===- GraphMlirBellmanFordBenchmark.cpp +//----------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the benchmark for GraphMLIR Bellman Ford Benchmark. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +#define V 100 +#define NUM_EDGE V *(V - 1) / 2 + +using namespace std; + +namespace { +// Graph +// sample_graph(graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED, +// 100); +intptr_t size[1]; +// // MemRef *input; +MemRef *start; +MemRef *e; +MemRef *dist; +} // namespace + +void initializeGraphMLIRBellmanFord() { + + // graph::generateRandomGraph(&sample_graph, V); + + // input = &sample_graph.get_Memref(); + + // size = 100; + + // MemRef output = MemRef(size); + + std::vector st, ed, distance(V, INT32_MAX); + + srand(time(0)); + + for (int i = 0; i < NUM_EDGE; i++) { + int u = rand() % V; + int v = rand() % V; + int d = (rand() % 100); + + st.push_back(u); + ed.push_back(v); + distance.push_back(d); + } + size[0] = V; + + MemRef temp1 = MemRef(st); + start = &temp1; + MemRef temp2 = MemRef(ed); + e = &temp2; + MemRef temp3 = MemRef(distance); + dist = &temp3; + // start = MemRef(st); + // e = MemRef(ed); + // dist = MemRef(distance); +} + +// Benchmarking function. +static void GraphMLIR_BellmanFord(benchmark::State &state) { + for (auto _ : state) { + std::vector op(V, INT32_MAX); + MemRef output = MemRef(op); + for (int i = 0; i < state.range(0); ++i) { + graph::bellman_ford(start, e, dist, &output); + } + } +} + +// Register benchmarking function. +BENCHMARK(GraphMLIR_BellmanFord)->Arg(1); + +void generateResultGraphMLIRBellmanFord() { + initializeGraphMLIRBellmanFord(); + cout << "-------------------------------------------------------\n"; + cout << "[ GraphMLIR Bellman Ford Result Information ]\n"; + MemRef output(size); + // graph::bellman_ford(&start, &end, &dist, &output); + + cout << "Bellman Ford operation finished!\n"; +} diff --git a/benchmarks/GraphMlirBfs.cpp b/benchmarks/GraphMlirBfs.cpp new file mode 100644 index 0000000..739784e --- /dev/null +++ b/benchmarks/GraphMlirBfs.cpp @@ -0,0 +1,108 @@ +//===- GraphMlirBfs.cpp +//----------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the benchmark for GraphMLIR Floyd Warshall Benchmark. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +using namespace std; + +#define V 1000 + +namespace { +int g[V][V]; +intptr_t opsize[1]; +std::vector a, ia, ca; +MemRef *weights, *cnz, *cidx; +} // namespace + +// Generate compressed sparse matrix +void generateCSR(int graph[V][V], std::vector &a, std::vector &ia, + std::vector &ca) { + int count = 0; + ia.push_back(0); + + for (int r = 0; r < V; r++) { + for (int c = 0; c < V; c++) { + if (graph[r][c] != 0) { + a.push_back(graph[r][c]); + ca.push_back(c); + + count++; + } + } + + ia.push_back(count); + } +} + +void initializeGraphMLIRBfs() { + int MAX_EDGES = V * (V - 1) / 2; + int NUMEDGES = MAX_EDGES; + + for (int i = 0; i < NUMEDGES; i++) { + int u = rand() % V; + int v = rand() % V; + int d = rand() % 100 + 1; + + if (g[u][v] == 0) + g[u][v] = d; + } + + std::vector a, ia, ca; + + generateCSR(g, a, ia, ca); + + opsize[0] = V + 1; + + weights = new MemRef(a); + cnz = new MemRef(ia); + cidx = new MemRef(ca); + MemRef parent = MemRef(opsize); + MemRef distance = MemRef(opsize); +} + +static void GraphMLIR_Bfs(benchmark::State &state) { + for (auto _ : state) { + MemRef parent = MemRef(opsize); + MemRef distance = MemRef(opsize); + for (int i = 0; i < state.range(0); ++i) { + graph::graph_bfs(weights, cnz, cidx, &parent, &distance); + } + } +} + +BENCHMARK(GraphMLIR_Bfs)->Arg(1); + +void generateResultGraphMLIRBfs() { + initializeGraphMLIRBfs(); + + cout << "-------------------------------------------------------\n"; + cout << "[ GraphMLIR BFS Result Information ]\n"; + + MemRef parent(opsize); + MemRef distance(opsize); + + graph::graph_bfs(weights, cnz, cidx, &parent, &distance); + + cout << "BFS operation finished!\n"; +} \ No newline at end of file diff --git a/benchmarks/GraphMlirFloydWarshallBenchmark.cpp b/benchmarks/GraphMlirFloydWarshallBenchmark.cpp new file mode 100644 index 0000000..a4165d3 --- /dev/null +++ b/benchmarks/GraphMlirFloydWarshallBenchmark.cpp @@ -0,0 +1,83 @@ +//===- GraphMlirFloydWarshallBenchmark.cpp +//----------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the benchmark for GraphMLIR Floyd Warshall Benchmark. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +using namespace std; + +namespace { +Graph sample_graph(graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED, + 100); +intptr_t size[2]; +MemRef *input; +} // namespace + +void initializeGraphMLIRFloydWarshall() { + // sample_graph.addEdge(0, 1, 4); + // sample_graph.addEdge(1, 2, 3); + // sample_graph.addEdge(2, 3, 3); + // sample_graph.addEdge(3, 0, 6); + // sample_graph.addEdge(0, 2, 2); + // sample_graph.addEdge(1, 3, 2); + + graph::generateRandomGraph(&sample_graph, 100); + + input = &sample_graph.get_Memref(); + + size[0] = 100; + size[1] = 100; + + MemRef output = MemRef(size); +} + +// Benchmarking function. +static void GraphMLIR_FloydWarshall(benchmark::State &state) { + for (auto _ : state) { + MemRef output = MemRef(size); + for (int i = 0; i < state.range(0); ++i) { + graph::floyd_warshall(input, &output); + } + } +} + +// Register benchmarking function. +BENCHMARK(GraphMLIR_FloydWarshall)->Arg(1); + +void generateResultGraphMLIRFloydWarshall() { + initializeGraphMLIRFloydWarshall(); + cout << "-------------------------------------------------------\n"; + cout << "[ GraphMLIR Floyd Warshall Result Information ]\n"; + MemRef generateResult(size); + graph::floyd_warshall(input, &generateResult); + + // auto y = generateResult.getData(); + + // for(int i=0; i +#include +#include +#include + +using namespace std; +using namespace lemon; + +#define V 1000 + +namespace { +ListDigraph g; +ListDigraph::Node source; +} // namespace + +void initializeLemonBFS() { + ListDigraph::Node nodes[V]; + + for (int i = 0; i < V; i++) + nodes[i] = g.addNode(); + + source = nodes[0]; + + int vertices = V; + int NUM = vertices; + int MAX_EDGES = vertices * (vertices - 1) / 2; + int NUMEDGE = MAX_EDGES; + + for (int i = 1; i <= NUMEDGE; i++) { + ListDigraph::Node a = nodes[rand() % V]; + ListDigraph::Node b = nodes[rand() % V]; + + g.addArc(a, b); + } + + Bfs bfs(g); +} + +// Benchmarking function. +static void Lemon_BFS(benchmark::State &state) { + for (auto _ : state) { + Bfs bfs(g); + for (int i = 0; i < state.range(0); ++i) { + bfs.run(source); + } + } +} + +// Register benchmarking function. +BENCHMARK(Lemon_BFS)->Arg(1); + +void generateResultLemonBFS() { + initializeLemonBFS(); + cout << "-------------------------------------------------------\n"; + cout << "[ LEMON BFS Result Information ]\n"; + Bfs output(g); + output.run(source); + cout << "Lemon bfs operation finished!\n"; +} diff --git a/benchmarks/LemonBellmanFord.cpp b/benchmarks/LemonBellmanFord.cpp new file mode 100644 index 0000000..4b56712 --- /dev/null +++ b/benchmarks/LemonBellmanFord.cpp @@ -0,0 +1,91 @@ +#include +#include +#include +#include + +using namespace std; +using namespace lemon; + +#define V 100 +#define MaxWeight 900 +#define UpperLimit 100 +#define LowerLimit 2 + +typedef ListDigraph::ArcMap LengthMap; + +namespace { +ListDigraph g; +ListDigraph::Node source; +LengthMap length(g); +ListDigraph::Node nodes[V]; +} // namespace + +void initializeLemonBellmanFord() { + + // LengthMap length(g); + + for (int i = 0; i < V; i++) { + nodes[i] = g.addNode(); + } + + source = nodes[0]; + + // length[g.addArc(nodes[0], nodes[1])] = 4; + // length[g.addArc(nodes[1], nodes[2])] = 3; + // length[g.addArc(nodes[2], nodes[3])] = 3; + // length[g.addArc(nodes[3], nodes[0])] = 6; + // length[g.addArc(nodes[0], nodes[2])] = 2; + // length[g.addArc(nodes[1], nodes[3])] = 2; + + std::set> container; + std::set>::iterator it; + srand(time(NULL)); + + int NUM = V; // Number of Vertices + int MAX_EDGES = V * (V - 1) / 2; + int NUMEDGE = MAX_EDGES; // Number of Edges + for (int j = 1; j <= NUMEDGE; j++) { + int a = rand() % NUM; + int b = rand() % NUM; + std::pair p = std::make_pair(a, b); + std::pair reverse_p = std::make_pair(b, a); + + while (container.find(p) != container.end() || + container.find(reverse_p) != container.end()) { + a = rand() % NUM; + b = rand() % NUM; + p = std::make_pair(a, b); + reverse_p = std::make_pair(b, a); + } + + container.insert(p); + length[g.addArc(nodes[a], nodes[b])] = 1 + rand() % MaxWeight; + } + BellmanFord bf(g, length); +} + +// Benchmarking function. +static void Lemon_BellmanFord(benchmark::State &state) { + for (auto _ : state) { + BellmanFord bf(g, length); + for (int i = 0; i < state.range(0); ++i) { + bf.run(source); + } + } +} + +BENCHMARK(Lemon_BellmanFord)->Arg(1); + +void generateResultLemonBellmanFord() { + initializeLemonBellmanFord(); + cout << "-------------------------------------------------------\n"; + cout << "[ LEMON Bellman Ford Result Information ]\n"; + BellmanFord output(g, length); + output.run(source); + + LengthMap::Value value = output.dist(nodes[2]); + std::cout << "The distance of node t from node s: " + << output.dist(nodes[3]) << std::endl; + + cout << "Lemon Bellman Ford Operation Completed!\n"; +} \ No newline at end of file diff --git a/benchmarks/Main.cpp b/benchmarks/Main.cpp new file mode 100644 index 0000000..6f504ae --- /dev/null +++ b/benchmarks/Main.cpp @@ -0,0 +1,65 @@ +//===- Main.cpp -----------------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This is the main file of the Graph processing Algorithm benchmark. +// +//===----------------------------------------------------------------------===// + +#include + +void initializeGraphMLIRFloydWarshall(); +void initializeFloydWarshall(); +void initializeLemonBFS(); +void initializeBoostFLoydWarshall(); +void initializeGraphMLIRBfs(); +void initializeGraphMLIRBellmanFord(); +void initializeLemonBellmanFord(); +void initializeBoostBellmanFord(); + +void generateResultGraphMLIRFloydWarshall(); +void generateResultFloydWarshall(); +void generateResultLemonBFS(); +void generateResultBoostFLoydWarshall(); +void generateResultGraphMLIRBfs(); +void generateResultGraphMLIRBellmanFord(); +void generateResultLemonBellmanFord(); +void generateResultBoostBellmanFord(); + +int main(int argc, char **argv) { + + initializeGraphMLIRFloydWarshall(); + initializeFloydWarshall(); + initializeLemonBFS(); + initializeBoostFLoydWarshall(); + initializeGraphMLIRBfs(); + initializeGraphMLIRBellmanFord(); + initializeLemonBellmanFord(); + initializeBoostBellmanFord(); + + ::benchmark::Initialize(&argc, argv); + ::benchmark::RunSpecifiedBenchmarks(); + + generateResultGraphMLIRFloydWarshall(); + generateResultFloydWarshall(); + generateResultLemonBFS(); + generateResultBoostFLoydWarshall(); + generateResultGraphMLIRBfs(); + generateResultGraphMLIRBellmanFord(); + generateResultLemonBellmanFord(); + generateResultBoostBellmanFord(); + + return 0; +} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ec97a1d..a1c6de5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,18 +1,34 @@ -add_custom_command(OUTPUT bfs.o -COMMAND ${GraphMLIR_BINARY_DIR}/graph-opt ${GraphMLIR_EXAMPLES_DIR}/bfs.mlir -lower-graph -lower-affine -convert-scf-to-cf -convert-vector-to-llvm -convert-memref-to-llvm -convert-func-to-llvm='emit-c-wrappers=1' -reconcile-unrealized-casts | - ${LLVM_MLIR_BINARY_DIR}/mlir-translate --mlir-to-llvmir | - ${LLVM_MLIR_BINARY_DIR}/llc -mtriple=${GraphMLIR_OPT_TRIPLE} -mattr=${GraphMLIR_OPT_ATTR} --filetype=obj -o ${GraphMLIR_BINARY_DIR}/../examples/bfs.o +add_custom_command(OUTPUT graph.o +COMMAND ${GraphMLIR_BINARY_DIR}/graph-opt ${GraphMLIR_EXAMPLES_DIR}/graph.mlir + -lower-graph -lower-affine -convert-scf-to-cf + -test-vector-multi-reduction-lowering-patterns + -convert-vector-to-llvm + -convert-memref-to-llvm + -llvm-request-c-wrappers + -convert-func-to-llvm + -reconcile-unrealized-casts + | + ${LLVM_MLIR_BINARY_DIR}/mlir-translate --mlir-to-llvmir + | + ${LLVM_MLIR_BINARY_DIR}/llc -mtriple=${GraphMLIR_OPT_TRIPLE} -mattr=${GraphMLIR_OPT_ATTR} + --filetype=obj -o ${GraphMLIR_BINARY_DIR}/../examples/graph.o DEPENDS graph-opt) -add_library(BFS STATIC bfs.o) +add_library(GRAPH STATIC graph.o) SET_TARGET_PROPERTIES( -BFS +GRAPH PROPERTIES LINKER_LANGUAGE C) - - add_executable(bfsExample bfsExample.cpp) add_dependencies(bfsExample graph-opt) -target_link_libraries(bfsExample BFS) +target_link_libraries(bfsExample GRAPH) + +add_executable(bellmanFordExample bellmanFordExample.cpp) +add_dependencies(bellmanFordExample graph-opt) +target_link_libraries(bellmanFordExample GRAPH) + +add_executable(floydWarshallExample floydWarshallExample.cpp) +add_dependencies(floydWarshallExample graph-opt) +target_link_libraries(floydWarshallExample GRAPH) diff --git a/examples/bellmanFordExample.cpp b/examples/bellmanFordExample.cpp new file mode 100644 index 0000000..b24d8a6 --- /dev/null +++ b/examples/bellmanFordExample.cpp @@ -0,0 +1,74 @@ +#include +#include +#include +#include +#include + +#define V 100 + +// Bellman Ford basic implementation +void bellman_ford(std::vector &st, std::vector &ed, + std::vector &dist, std::vector &output1) { + int E = st.size(); + output1[0] = 0; + + for (int i = 1; i < V; i++) { + for (int j = 0; j < E; j++) { + int u = st[j]; + int v = ed[j]; + int d = dist[j]; + + if (output1[u] != INT32_MAX && output1[u] + d < output1[v]) + output1[v] = output1[u] + d; + } + } + + for (int j = 0; j < E; j++) { + int u = st[j]; + int v = ed[j]; + int d = dist[j]; + + if (output1[u] != INT32_MAX && output1[u] + d < output1[v]) + return; + } +} + +int main() { + int MAX_EDGES = V * (V - 1) / 2; + int NUMEDGES = MAX_EDGES; + + std::vector st, ed, dist, op(V, INT32_MAX); + + srand(time(0)); + + for (int i = 0; i < NUMEDGES; i++) { + int u = rand() % V; + int v = rand() % V; + int d = (rand() % 100); + + st.push_back(u); + ed.push_back(v); + dist.push_back(d); + } + + std::vector output1(V, INT32_MAX); + bellman_ford(st, ed, dist, output1); + + std::cout << st[0] << " " << ed[0] << " " << dist[0] << std::endl; + + intptr_t size[1] = {V}; + + MemRef start = MemRef(st); + MemRef end = MemRef(ed); + MemRef distance = MemRef(dist); + MemRef output = MemRef(op); + + graph::bellman_ford(&start, &end, &distance, &output); + + auto y = output.getData(); + + for (int i = 0; i < V; i++) { + std::cout << (y[i]) << " " << (output1[i]) << "\n"; + } + std::cout << std::endl; +} \ No newline at end of file diff --git a/examples/bfs.mlir b/examples/bfs.mlir deleted file mode 100644 index 294a969..0000000 --- a/examples/bfs.mlir +++ /dev/null @@ -1,6 +0,0 @@ -func @bfs(%m1 : memref, %m2 : memref, %m3 : memref) -{ - graph.bfs %m1, %m2, %m3 : memref, memref, memref - %c0 = arith.constant 0 : index - return -} diff --git a/examples/bfsExample.cpp b/examples/bfsExample.cpp index ff9d068..5c9473f 100644 --- a/examples/bfsExample.cpp +++ b/examples/bfsExample.cpp @@ -7,23 +7,74 @@ // //===----------------------------------------------------------------------===// +#include +#include #include -#include #include +#include -int main() { - std::cout << "Reached here !!!\n"; +#define V 5 + +// Generate compressed sparse matrix +void generateCSR(std::vector> &graph, std::vector &a, + std::vector &ia, std::vector &ca) { + int count = 0; + ia.push_back(0); - float sample_graph1_array[9] = {1, 1, 1, 1, -8, 1, 1, 1, 1}; - intptr_t sample_graph_length = 3; - intptr_t sample_graph_width = 3; - float *allocation_pointer = (float *)malloc(sizeof(float)); - intptr_t sample_graph_sizes[2] = {sample_graph_width, sample_graph_length}; - intptr_t sample_graph_strides[2] = {sample_graph_width, sample_graph_length}; + for (int r = 0; r < V; r++) { + for (int c = 0; c < V; c++) { + if (graph[r][c] != 0) { + a.push_back(graph[r][c]); + ca.push_back(c); - MemRef_descriptor sample_graph = - MemRef_Descriptor(allocation_pointer, sample_graph1_array, 0, - sample_graph_sizes, sample_graph_strides); + count++; + } + } - graph::graph_bfs(sample_graph, sample_graph, sample_graph); + ia.push_back(count); + } } + +int main() { + std::vector> graph(V, std::vector(V, 0)); + + int MAX_EDGES = V * (V - 1) / 2; + int NUMEDGES = MAX_EDGES; + + for (int i = 0; i < NUMEDGES; i++) { + int u = rand() % V; + int v = rand() % V; + int d = rand() % 100 + 1; + + if (graph[u][v] == 0) + graph[u][v] = d; + } + + std::vector a, ia, ca; + + generateCSR(graph, a, ia, ca); + + MemRef weights = MemRef(a); + MemRef cnz = MemRef(ia); + MemRef cidx = MemRef(ca); + MemRef parent = MemRef(std::vector(V, -1)); + MemRef distance = MemRef(std::vector(V, INT32_MAX)); + + graph::graph_bfs(&weights, &cnz, &cidx, &parent, &distance); + + auto y = parent.getData(); + + // Print parents + for (size_t i = 0; i < V; i++) { + std::cout << "parent(" << i << ")" + << " = " << parent[i] << std::endl; + } + + y = distance.getData(); + + // Print distance + for (size_t i = 0; i < V; i++) { + std::cout << "distance(" << i << ")" + << " = " << distance[i] << std::endl; + } +} \ No newline at end of file diff --git a/examples/floydWarshallExample.cpp b/examples/floydWarshallExample.cpp new file mode 100644 index 0000000..025cd39 --- /dev/null +++ b/examples/floydWarshallExample.cpp @@ -0,0 +1,62 @@ +//====- floydWarshallExample.cpp =============================================// +// +// The graph.bfs operation will be compiled into an object file with the +// graph-opt tool. +// This file will be linked with the object file to generate the executable +// file. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include + + +int main() { + + int MAX_VERTICES = 20; + Graph sample_graph( + graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED, MAX_VERTICES); + // sample_graph.addEdge(0, 1, 4); + // sample_graph.addEdge(1, 2, 3); + // sample_graph.addEdge(2, 3, 3); + // sample_graph.addEdge(3, 0, 6); + // sample_graph.addEdge(0, 2, 2); + // sample_graph.addEdge(1, 3, 2); + + graph::generateRandomGraph(&sample_graph, MAX_VERTICES); + + // this will print the original graph. + std::cout << "Printing graph in format it was entered ( " + "GRAPH_ADJ_MARIX_UNDIRECTED_WEIGHTED )\n"; + sample_graph.printGraphOg(); + + auto x = sample_graph.get_Memref(); + + // this will print the linear 2d matrix in 2d form. + std::cout + << "Printing graph in form of 2d matrix after conversion to memref\n"; + sample_graph.printGraph(); + int vert = MAX_VERTICES; + intptr_t size[2]; + size[0] = vert; + size[1] = vert; + MemRef output = MemRef(size); + + graph::floyd_warshall(&x, &output); + auto y = output.getData(); + + std::cout<<"Floyd Warshall Output!"<<"\n"; + + for(int i=0; i, %cnz : memref, %cidx : memref, %parent : memref, %distance : memref) +{ + graph.bfs %weights, %cnz, %cidx, %parent, %distance : memref, memref, memref, memref, memref + return +} + +func.func @bellman_ford(%start : memref, %end : memref, %distance : memref, %output : memref) +{ + graph.bellman_ford %start, %end, %distance, %output : memref, memref, memref, memref + return +} + +func.func @floyd_warshall(%input : memref, %output : memref) +{ + graph.FloydWarshall %input, %output : memref, memref + return +} + diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index e6f347c..0ca0f41 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -1 +1 @@ -add_subdirectory(Dialect) \ No newline at end of file +add_subdirectory(Dialect) diff --git a/include/Dialect/Graph/GraphOps.td b/include/Dialect/Graph/GraphOps.td index 64f8170..531b29a 100644 --- a/include/Dialect/Graph/GraphOps.td +++ b/include/Dialect/Graph/GraphOps.td @@ -27,18 +27,59 @@ include "mlir/Interfaces/SideEffectInterfaces.td" def Graph_BFSOp : Graph_Op<"bfs"> { let summary = [{ - abcde + Breadth First Search on graph represented by CSR + }]; + + let arguments = (ins Arg:$memrefW, + Arg:$memrefCnz, + Arg:$memrefCidx, + Arg:$memrefP, + Arg:$memrefD); + + let assemblyFormat = [{ + $memrefW `,` $memrefCnz `,` $memrefCidx `,` $memrefP `,` $memrefD attr-dict `:` type($memrefW) `,` type($memrefCnz) `,` type($memrefCidx) `,` type($memrefP) `,` type($memrefD) + }]; +} + +def Graph_BellmanFordOp : Graph_Op<"bellman_ford"> +{ + let summary = [{ + Bellman Ford algorithm + }]; + + let arguments = (ins Arg:$memrefS, + Arg:$memrefE, + Arg:$memrefD, + Arg:$memrefO); + + let assemblyFormat = [{ + $memrefS `,` $memrefE `,` $memrefD `,` $memrefO attr-dict `:` type($memrefS) `,` type($memrefE) `,` type($memrefD) `,` type($memrefO) + }]; +} + +def Graph_FloydWarshallOp : Graph_Op<"FloydWarshall"> +{ + let summary = [{The Floyd Warshall Algorithm is for solving all pairs shortest path problems. + The problem is to find the shortest distances between every pair of vertices in a given + edge-weighted directed Graph. }]; let arguments = (ins Arg:$memrefI, - Arg:$memrefK, Arg:$memrefCO); let assemblyFormat = [{ - $memrefI `,` $memrefK `,` $memrefCO attr-dict `:` type($memrefI) `,` type($memrefK) `,` type($memrefCO) + $memrefI `,` $memrefCO attr-dict `:` type($memrefI) `,` type($memrefCO) }]; } diff --git a/include/Interface/Container.h b/include/Interface/Container.h new file mode 100644 index 0000000..fb1b2f1 --- /dev/null +++ b/include/Interface/Container.h @@ -0,0 +1,95 @@ +//===- Container.h --------------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// Container descriptor. +// +//===----------------------------------------------------------------------===// + +#ifndef INTERFACE_BUDDY_CORE_CONTAINER +#define INTERFACE_BUDDY_CORE_CONTAINER + +#include +#include +#include + +// MemRef descriptor. +// - T represents the type of the elements. +// - N represents the number of dimensions. +// - The storage order is NCHW. +template class MemRef { +public: + // Constructor from shape. + MemRef(intptr_t sizes[N], T init = T(0)); + // Constructor from data. + MemRef(const T *data, intptr_t sizes[N], intptr_t offset = 0); + // Constructor from a unique_ptr, taking over. + MemRef(std::unique_ptr &uptr, intptr_t sizes[N], intptr_t offset = 0); + // Constructor from a 1D vector + MemRef(std::vector data); + // Copy constructor. + MemRef(const MemRef &other); + // Copy assignment operator. + MemRef &operator=(const MemRef &other); + // Move constructor. + MemRef(MemRef &&other) noexcept; + // Move assignment operator. + MemRef &operator=(MemRef &&other) noexcept; + // Desctrutor. + ~MemRef(); + // Get the data pointer. + T *getData(); + // Get the sizes (shape). + const intptr_t *getSizes() { return sizes; } + // Get the strides. + const intptr_t *getStrides() { return strides; } + // Get the rank of the memref. + size_t getRank() const { return N; } + // Get the size (number of elements). + size_t getSize() const { return size; } + // Get the element at index. + const T &operator[](size_t index) const; + T &operator[](size_t index); + // release the pointer + T *release(); + +protected: + // Default constructor. + MemRef(){}; + // Set the strides. + // Computes the strides of the transposed tensor for transpose=true. + void setStrides(); + // Compute the product of array elements. + size_t product(intptr_t sizes[N]) const; + + // Data. + // The `aligned` and `allocated` members point to the same address, `aligned` + // member is responsible for handling data, and `allocated` member is + // resposible for handling the memory space. + T *allocated = nullptr; + T *aligned = nullptr; + // Offset. + intptr_t offset = 0; + // Shape. + intptr_t sizes[N]; + // Strides. + intptr_t strides[N]; + // Number of elements. + size_t size; +}; + +#include "Interface/Container.cpp" + +#endif // INTERFACE_BUDDY_CORE_CONTAINER diff --git a/include/Interface/GraphContainer.h b/include/Interface/GraphContainer.h new file mode 100644 index 0000000..361fc87 --- /dev/null +++ b/include/Interface/GraphContainer.h @@ -0,0 +1,78 @@ +//===- GraphContainer.h ---------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// Graph container descriptor. +// +//===----------------------------------------------------------------------===// + +#ifndef INTERFACE_GRAPHCONTAINER_H +#define INTERFACE_GRAPHCONTAINER_H + +#include "Interface/Container.h" +#include +#include +/** + * The Graph Class ; the object of this class will be used to call functions. + * + * @tparam T represents the datatype to be used. + * @tparam N represents the number of dimensions. + */ +template class Graph { +protected: + // the graph type and representation + uint16_t graph_type; + size_t size; + intptr_t sizes[N]; + MemRef *data = nullptr; + // the count of number of edges added in the graph. + int edgeCount = 0; + + // adjacency list representation of graph. + std::vector> adjList; + + // incidence matrix representation of graph. + std::vector> incMat; + + // adjacency matrix representation of graph + std::vector> adjMat; + + // weighted adjacency list representation of graph. + std::vector>> adjList_weighted; + +public: + // Constructor + Graph(uint16_t graph_type, size_t size); + + // Function to add edges in graph. + void addEdge(T a, T b); + void addEdge(T Node1, T Node2, T EdgeWeight); + + // Function to print the linear 2d graph. + void printGraphOg(); + + // converter from graph to MemRef_descriptor + void graph_to_MemRef_descriptor(); + MemRef &get_Memref() { + graph_to_MemRef_descriptor(); + return *data; + } + + // Function to print the linear 2d graph after conversion. + void printGraph(); +}; + +#include "Interface/GraphContainer.cpp" +#endif // INTERFACE_GRAPHCONTAINER_H diff --git a/include/Interface/graph.h b/include/Interface/graph.h index fbb860c..4e7d30f 100644 --- a/include/Interface/graph.h +++ b/include/Interface/graph.h @@ -1,5 +1,5 @@ //===- graph.h -//--------------------------------------------------------------===// +//-------------------------------------------------------------===// // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -22,22 +22,61 @@ #ifndef INCLUDE_INTERFACE_GRAPH_H #define INCLUDE_INTERFACE_GRAPH_H -#include +#include namespace graph { namespace detail { + +enum graph_type { + GRAPH_ADJ_LIST_UNDIRECTED_UNWEIGHTED, + GRAPH_ADJ_LIST_UNDIRECTED_WEIGHTED, + GRAPH_ADJ_LIST_DIRECTED_UNWEIGHTED, + GRAPH_ADJ_LIST_DIRECTED_WEIGHTED, + GRAPH_ADJ_MATRIX_UNDIRECTED_UNWEIGHTED, + GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED, + GRAPH_ADJ_MATRIX_DIRECTED_UNWEIGHTED, + GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED, + GRAPH_INC_MATRIX_UNDIRECTED_UNWEIGHTED, + GRAPH_INC_MATRIX_UNDIRECTED_WEIGHTED, + GRAPH_INC_MATRIX_DIRECTED_UNWEIGHTED, + GRAPH_INC_MATRIX_DIRECTED_WEIGHTED, +}; + // Functions present inside graph::detail are not meant to be called by users // directly. // Declare the BFS C interface. extern "C" { -void _mlir_ciface_bfs(MemRef_descriptor graph1, MemRef_descriptor graph2, - MemRef_descriptor graph3); +void _mlir_ciface_bfs(MemRef *weights, MemRef *cnz, + MemRef *cidx, MemRef *parent, + MemRef *distance); } + +extern "C" { +void _mlir_ciface_floyd_warshall(MemRef *graph1, + MemRef *graph2); +} + +extern "C" { +void _mlir_ciface_bellman_ford(MemRef *start, MemRef *end, + MemRef *distance, + MemRef *output); +} + } // namespace detail -void graph_bfs(MemRef_descriptor graph1, MemRef_descriptor graph2, - MemRef_descriptor graph3) { - detail::_mlir_ciface_bfs(graph1, graph2, graph3); +void inline graph_bfs(MemRef *weights, MemRef *cnz, + MemRef *cidx, MemRef *parent, + MemRef *distance) { + detail::_mlir_ciface_bfs(weights, cnz, cidx, parent, distance); +} + +void inline bellman_ford(MemRef *start, MemRef *end, + MemRef *distance, MemRef *output) { + detail::_mlir_ciface_bellman_ford(start, end, distance, output); +} + +void inline floyd_warshall(MemRef *input, MemRef *output) { + detail::_mlir_ciface_floyd_warshall(input, output); } } // namespace graph diff --git a/include/Interface/memref.h b/include/Interface/memref.h deleted file mode 100644 index 45ebbe6..0000000 --- a/include/Interface/memref.h +++ /dev/null @@ -1,53 +0,0 @@ -//===- memref.h -----------------------------------------------------------===// -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -//===----------------------------------------------------------------------===// -// -// Header file for MemRef specific entities. -// -//===----------------------------------------------------------------------===// - -#ifndef INCLUDE_INTERFACE_MEMREF_H -#define INCLUDE_INTERFACE_MEMREF_H - -#include -#include - -// Define Memref Descriptor. -typedef struct MemRef_descriptor_ *MemRef_descriptor; -typedef struct MemRef_descriptor_ { - float *allocation_pointer; - float *aligned; - intptr_t offset; - intptr_t sizes[2]; - intptr_t strides[2]; -} Memref; - -// Constructor -MemRef_descriptor MemRef_Descriptor(float *allocation_pointer, float *aligned, - intptr_t offset, intptr_t sizes[2], - intptr_t strides[2]) { - MemRef_descriptor n = (MemRef_descriptor)malloc(sizeof(*n)); - n->allocation_pointer = allocation_pointer; - n->aligned = aligned; - n->offset = offset; - for (int i = 0; i < 2; i++) - n->sizes[i] = sizes[i]; - for (int j = 0; j < 2; j++) - n->strides[j] = strides[j]; - - return n; -} - -#endif diff --git a/include/Utility/Utils.h b/include/Utility/Utils.h new file mode 100644 index 0000000..e70c31d --- /dev/null +++ b/include/Utility/Utils.h @@ -0,0 +1,38 @@ +//====- Utils.cpp ---------------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements generic utility functions. +// +//===----------------------------------------------------------------------===// + +#ifndef UTILS_UTILS +#define UTILS_UTILS + +#include +#include +#include +#include + +using namespace std; + +namespace graph { +void generateRandomGraph(Graph *graph, int vertices, int maxWeight = 900, int randomUpperLimit = 100, int randomLowerLimit = 2); +void generateRandomGraph(Graph *graph, int vertices, int maxWeight = 900, int randomUpperLimit = 100, int randomLowerLimit = 2); +void generateRandomGraph(vector &edge, vector &weight, int vertices, int maxWeight = 900, int randomUpperLimit = 100, int randomLowerLimit = 2); +} +#include + +#endif \ No newline at end of file diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 629c08a..b8fbcd6 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,2 +1,4 @@ add_subdirectory(Conversion) add_subdirectory(Dialect) +add_subdirectory(Interface) +add_subdirectory(Utility) diff --git a/lib/Conversion/LowerGraph/LowerGraphPass.cpp b/lib/Conversion/LowerGraph/LowerGraphPass.cpp index cd30ae8..8876ce5 100644 --- a/lib/Conversion/LowerGraph/LowerGraphPass.cpp +++ b/lib/Conversion/LowerGraph/LowerGraphPass.cpp @@ -35,6 +35,27 @@ using namespace graph; using namespace vector; using namespace mlir::arith; +// Size for visited and queue vector +#define MAXSIZE 1000 + +// Cast index to i32 +Value indexToI32(OpBuilder &builder, Location loc, Value v) { + return builder.create(loc, builder.getI32Type(), v); +} + +// Cast i32 to index +Value I32ToIndex(OpBuilder &builder, Location loc, Value v) { + return builder.create(loc, builder.getIndexType(), v); +} + +// Add to index +Value addIndex(OpBuilder &builder, Location loc, Value u, Value d) { + Value ans = indexToI32(builder, loc, u); + ans = builder.create(loc, ans, d); + + return I32ToIndex(builder, loc, ans); +} + //===----------------------------------------------------------------------===// // Rewrite Pattern //===----------------------------------------------------------------------===// @@ -54,14 +75,347 @@ class GraphBFSLowering : public OpRewritePattern { auto loc = op->getLoc(); auto ctx = op->getContext(); - // Create constant indices. + Value weights = op->getOperand(0); + Value cnz = op->getOperand(1); + Value cidx = op->getOperand(2); + Value parent = op->getOperand(3); + Value distance = op->getOperand(4); + + // Types + IndexType idxt = IndexType::get(ctx); + IntegerType it32 = IntegerType::get(ctx, 32); + VectorType vt32 = VectorType::get({MAXSIZE}, it32); + VectorType qt = VectorType::get({MAXSIZE}, idxt); + + // Constants + Value idx0 = rewriter.create(loc, 0); + Value idx1 = rewriter.create(loc, 1); + Value cnzsize = rewriter.create(loc, cnz, idx0); + Value zero = rewriter.create(loc, int(0), it32); + Value one = rewriter.create(loc, int(1), it32); + Value two = rewriter.create(loc, int(2), it32); + Value minusOne = rewriter.create(loc, int(-1), it32); + + // Number of vertices as index + Value V = indexToI32(rewriter, loc, cnzsize); + V = rewriter.create(loc, V, minusOne); + V = I32ToIndex(rewriter, loc, V); + + // Queue + Value queue = rewriter.create(loc, qt, idx0); + Value front = rewriter.create(loc, int(0), it32); + Value rear = rewriter.create(loc, int(0), it32); + + // Visited + // 0 = not discovered = white (not added to the queue) + // 1 = discovered but no explored = grey (added to the queue) + // 2 = discovered and explored = black (removed from the queue) + Value visited = rewriter.create(loc, vt32, zero); + + /* + queue[rear] = 0 + rear++ + visited[0] = 1 + distance[0] = 0 + parent[0] = -1 + */ + queue = rewriter.create(loc, idx0, queue, rear); + rear = rewriter.create(loc, rear, one); + visited = rewriter.create(loc, one, visited, idx0); + rewriter.create(loc, zero, distance, idx0); + rewriter.create(loc, minusOne, parent, idx0); + + // While loop + SmallVector operands = {queue, front, rear, visited}; + SmallVector types = {qt, it32, it32, vt32}; + SmallVector locations = {loc, loc, loc, loc}; + + auto whileOp = rewriter.create(loc, types, operands); + + Block *before = + rewriter.createBlock(&whileOp.getBefore(), {}, types, locations); + Block *after = + rewriter.createBlock(&whileOp.getAfter(), {}, types, locations); + + // Before block - Condition + // while(front != rear) + { + rewriter.setInsertionPointToStart(&whileOp.getBefore().front()); + + Value front = before->getArgument(1); + Value rear = before->getArgument(2); + + Value notEmpty = + rewriter.create(loc, CmpIPredicate::ne, front, rear); + + rewriter.create(loc, notEmpty, before->getArguments()); + } + + { + rewriter.setInsertionPointToStart(&whileOp.getAfter().front()); + + Value queue = after->getArgument(0); + Value front = after->getArgument(1); + Value rear = after->getArgument(2); + Value visited = after->getArgument(3); + + /* + u = queue[front] + z = u + 1 + front++ + visited[u] = 2 + */ + Value u = rewriter.create(loc, queue, front); + Value z = addIndex(rewriter, loc, u, one); + + front = rewriter.create(loc, front, one); + visited = rewriter.create(loc, two, visited, u); + + Value s = rewriter.create(loc, cnz, u); + Value e = rewriter.create(loc, cnz, z); + s = I32ToIndex(rewriter, loc, s); + e = I32ToIndex(rewriter, loc, e); + + // for(i = s; i < e; i++) + auto loop = rewriter.create( + loc, s, e, idx1, ValueRange{queue, front, rear, visited}, + [&](OpBuilder &builder, Location loc, Value i, ValueRange args) { + Value queue = args[0]; + Value front = args[1]; + Value rear = args[2]; + Value visited = args[3]; + + /* + v = cidx[i] + color = visited[v] + condition = (color == 0) + */ + Value v = rewriter.create(loc, cidx, i); + v = I32ToIndex(builder, loc, v); + Value color = + rewriter.create(loc, visited, v); + Value condition = + rewriter.create(loc, CmpIPredicate::eq, color, zero); + + scf::IfOp ifop = builder.create( + loc, TypeRange{qt, it32, it32, vt32}, condition, true); + + // Then block + { + builder.setInsertionPointToStart(ifop.thenBlock()); + /* + d = distance[u] + e = weights[i] + f = d + e + p = u + */ + Value d = rewriter.create(loc, distance, u); + Value e = rewriter.create(loc, weights, i); + Value f = rewriter.create(loc, d, e); + Value p = rewriter.create(loc, it32, u); + + /* + distance[v] = f + parent[v] = u + */ + rewriter.create(loc, f, distance, v); + rewriter.create(loc, p, parent, v); + + /* + visited[v] = 1 + queue[rear] = v + rear++ + */ + Value nvisited = + builder.create(loc, one, visited, v); + Value nqueue = + builder.create(loc, v, queue, rear); + Value nrear = builder.create(loc, rear, one); + + builder.create( + loc, ValueRange{nqueue, front, nrear, nvisited}); + } + + // Else block + { + builder.setInsertionPointToStart(ifop.elseBlock()); + builder.create( + loc, ValueRange{queue, front, rear, visited}); + } + + builder.setInsertionPointAfter(ifop); + ValueRange results = ifop.getResults(); + + builder.create(loc, results); + }); + + ValueRange lresults = loop.getResults(); + + rewriter.create(loc, lresults); + } + + rewriter.eraseOp(op); + return success(); + } + +private: + int64_t stride; +}; + +class GraphBellmanFordLowering : public OpRewritePattern { +public: + using OpRewritePattern::OpRewritePattern; + + explicit GraphBellmanFordLowering(MLIRContext *context, int64_t strideParam) + : OpRewritePattern(context) { + stride = strideParam; + } + + LogicalResult matchAndRewrite(graph::BellmanFordOp op, + PatternRewriter &rewriter) const override { + auto loc = op->getLoc(); + auto ctx = op->getContext(); + + Value start = op->getOperand(0); + Value end = op->getOperand(1); + Value distance = op->getOperand(2); + Value output = op->getOperand(3); + + // Types + IndexType idxt = IndexType::get(ctx); + IntegerType it32 = IntegerType::get(ctx, 32); + VectorType vt32 = VectorType::get({100}, it32); + VectorType qt = VectorType::get({100}, idxt); + + Value idx0 = rewriter.create(loc, 0); + Value idx1 = rewriter.create(loc, 1); + Value V = rewriter.create(loc, output, idx0); + Value E = rewriter.create(loc, start, idx0); + + Value zero = rewriter.create(loc, int(0), it32); + Value one = rewriter.create(loc, int(1), it32); + Value two = rewriter.create(loc, int(2), it32); + Value minusOne = rewriter.create(loc, int(-1), it32); + Value maxInt = rewriter.create(loc, output, idx0); + + SmallVector lowerBounds{idx1, idx0}; + SmallVector upperBounds{V, E}; + SmallVector steps{1, 1}; + + rewriter.create(loc, zero, output, idx0); + + buildAffineLoopNest( + rewriter, loc, lowerBounds, upperBounds, steps, + [&](OpBuilder &builder, Location loc, ValueRange ivs) { + Value u = + rewriter.create(loc, start, ValueRange{ivs[1]}); + Value v = + rewriter.create(loc, end, ValueRange{ivs[1]}); + Value d = rewriter.create(loc, distance, + ValueRange{ivs[1]}); + + Value uidx = I32ToIndex(builder, loc, u); + Value vidx = I32ToIndex(builder, loc, v); + + Value id = rewriter.create(loc, output, uidx); + // distance[u] + d + Value fd = rewriter.create(loc, id, d); + // distance[v] + Value vd = rewriter.create(loc, output, vidx); + + Value condition1 = + rewriter.create(loc, CmpIPredicate::ne, id, maxInt); + Value condition2 = + rewriter.create(loc, CmpIPredicate::slt, fd, vd); + Value condition = + rewriter.create(loc, condition1, condition2); + + builder.create( + loc, condition, [&](OpBuilder &builder, Location loc) { + builder.create(loc, fd, output, vidx); + builder.create(loc); + }); + }); + + rewriter.eraseOp(op); + return success(); + } + +private: + int64_t stride; +}; + +class GraphFloydWarshallLowering + : public OpRewritePattern { +public: + using OpRewritePattern::OpRewritePattern; + + explicit GraphFloydWarshallLowering(MLIRContext *context, int64_t strideParam) + : OpRewritePattern(context) { + stride = strideParam; + } + + LogicalResult matchAndRewrite(graph::FloydWarshallOp op, + PatternRewriter &rewriter) const override { + auto loc = op->getLoc(); + auto ctx = op->getContext(); + + // Register operand values. + Value input = op->getOperand(0); + Value output = op->getOperand(1); + Value c0 = rewriter.create(loc, 0); Value c1 = rewriter.create(loc, 1); + Value V = rewriter.create(loc, input, c0); - // Register operand values. - Value m1 = op->getOperand(0); - Value m2 = op->getOperand(1); - Value m3 = op->getOperand(2); + SmallVector step{1, 1}; + + buildAffineLoopNest( + rewriter, loc, ValueRange{c0, c0}, ValueRange{V, V}, step, + [&](OpBuilder &builder, Location loc, ValueRange ivs) { + Value x = builder.create(loc, input, + ValueRange{ivs[0], ivs[1]}); + builder.create(loc, x, output, + ValueRange{ivs[0], ivs[1]}); + }); + + SmallVector lowerBounds(3, c0); + SmallVector upperBounds(3, V); + SmallVector steps{1, 1, 4}; + + IntegerType i32 = IntegerType::get(ctx, 32); + FloatType f32 = FloatType::getF32(ctx); + VectorType vectorTy32 = VectorType::get({4}, f32); + VectorType vectorred = VectorType::get({2, 4}, f32); + Value one = rewriter.create(loc, APFloat(float(1)), f32); + Value mx = + rewriter.create(loc, APFloat(float(10000)), f32); + Value vecOne = rewriter.create(loc, vectorTy32, one); + Value vecMx = rewriter.create(loc, vectorTy32, mx); + Value temp = rewriter.create(loc, vectorred, one); + // rewriter.create(loc, vecOne); + buildAffineLoopNest( + rewriter, loc, lowerBounds, upperBounds, steps, + [&](OpBuilder &builder, Location loc, ValueRange ivs) { + Value x = builder.create(loc, output, + ValueRange{ivs[1], ivs[0]}); + Value y = builder.create(loc, output, + ValueRange{ivs[0], ivs[2]}); + Value z = builder.create(loc, output, + ValueRange{ivs[1], ivs[2]}); + + Value temp = builder.create(loc, x, y); + + Value checkCond = + builder.create(loc, CmpFPredicate::OLT, temp, z); + + builder.create( + loc, checkCond, [&](OpBuilder &builder, Location loc) { + builder.create(loc, temp, output, + ValueRange{ivs[1], ivs[2]}); + builder.create(loc); + }); + }); rewriter.eraseOp(op); return success(); @@ -70,11 +424,14 @@ class GraphBFSLowering : public OpRewritePattern { private: int64_t stride; }; + } // end anonymous namespace void populateLowerGraphConversionPatterns(RewritePatternSet &patterns, int64_t stride) { patterns.add(patterns.getContext(), stride); + patterns.add(patterns.getContext(), stride); + patterns.add(patterns.getContext(), stride); } //===----------------------------------------------------------------------===// diff --git a/lib/Interface/CMakeLists.txt b/lib/Interface/CMakeLists.txt new file mode 100644 index 0000000..ef9288f --- /dev/null +++ b/lib/Interface/CMakeLists.txt @@ -0,0 +1,2 @@ +add_library(Container Container.cpp) +add_library(GraphContainer GraphContainer.cpp) \ No newline at end of file diff --git a/lib/Interface/Container.cpp b/lib/Interface/Container.cpp new file mode 100644 index 0000000..527d88f --- /dev/null +++ b/lib/Interface/Container.cpp @@ -0,0 +1,294 @@ +//===- Container.cpp ------------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the container descriptor. +// +//===----------------------------------------------------------------------===// + +#ifndef CORE_CONTAINER_DEF +#define CORE_CONTAINER_DEF + +#include +#include +#include +#include +#include + +#include "Interface/Container.h" + +/** + * @brief MemRef Shape Constructor. Construct a MemRef object from the data + * shape and initial value. The default initial value is 0. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef::MemRef(intptr_t sizes[N], T init) { + for (size_t i = 0; i < N; i++) { + this->sizes[i] = sizes[i]; + } + setStrides(); + size = product(sizes); + allocated = new T[size]; + aligned = allocated; + std::fill(aligned, aligned + size, init); +} + +/** + * @brief MemRef Array Constructor. Construct a MemRef object from the data + * pointer, sizes, and offset. The default offset is 0. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef::MemRef(const T *data, intptr_t sizes[N], intptr_t offset) { + this->offset = offset; + for (size_t i = 0; i < N; i++) { + this->sizes[i] = sizes[i]; + } + setStrides(); + size = product(sizes); + allocated = new T[size]; + aligned = allocated; + std::copy(data, data + size, aligned); +} + +/** + * @brief MemRef Array Constructor. Construct a MemRef object from a unique_ptr, + * sizes, and offset. The default offset is 0. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef::MemRef(std::unique_ptr &uptr, intptr_t *sizes, + intptr_t offset) { + if (!uptr) + assert(0 && "Taking over an empty unique pointer."); + T *data = uptr.release(); + this->aligned = data; + this->allocated = data; + this->offset = offset; + for (size_t i = 0; i < N; i++) { + this->sizes[i] = sizes[i]; + } + setStrides(); + size = product(sizes); +} + +/** + * @bried MemRef Array Constructor. Construct a MemRef object from a vector. + * @tparam T represents the datatype to be used + */ +template MemRef::MemRef(std::vector data) { + this->sizes[0] = data.size(); + setStrides(); + size = product(sizes); + allocated = new T[size]; + aligned = allocated; + for (size_t i = 0; i < size; i++) + aligned[i] = data[i]; +} + +/** + * @brief Copy Constructor. This constructor is used to initialize a MemRef + object with another MemRef object. + - Copy `offset` and `size` directly. + * - Elementwise copy `sizes` array. + * - Calculate `strides`. + * - Allocate new space. + * - Deep copy the data from the original object. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef::MemRef(const MemRef &other) + : offset(other.offset), size(other.size) { + for (size_t i = 0; i < N; i++) { + this->sizes[i] = other.sizes[i]; + } + setStrides(); + allocated = new T[size]; + aligned = allocated; + std::copy(other.aligned, other.aligned + size, aligned); +} + +/** + * @brief Copy Assignment Operator.. + * - Check if they are the same object. + * - Copy `offset` and `size` directly. + * - Elementwise copy `sizes`. + * - Calculate the `strides`. + * - Free the data space of this object to avoid memory leaks. + * - Allocate new space and deep copy. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef &MemRef::operator=(const MemRef &other) { + this->offset = other.offset; + this->size = other.size; + for (size_t i = 0; i < N; i++) { + this->sizes[i] = other.sizes[i]; + } + setStrides(); + // Free the original aligned and allocated space. + delete[] allocated; + // Allocate new space and deep copy. + T *ptr = new T[size]; + std::copy(other.aligned, other.aligned + size, ptr); + aligned = ptr; + allocated = ptr; + return *this; +} + +/** + * @brief Move Constructor. This constructor is used to initialize a MemRef + * object from a rvalue. The move constructor steals the resources of the + * original object. Note that the original object no longer owns the members and + * spaces. + * - Steal members from the original object. + * - Assign the NULL pointer to the original aligned and allocated members to + * avoid the double free error. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef::MemRef(MemRef &&other) noexcept + : allocated(other.allocated), aligned(other.aligned), offset(other.offset), + size(other.size) { + std::swap(this->sizes, other.sizes); + std::swap(this->strides, other.strides); + // Assign the NULL pointer to the original aligned and allocated members to + // avoid the double free error. + other.allocated = other.aligned = nullptr; +} + +/** + * @brief Move Assignment Operator. Note that the original object no longer owns + * the members and spaces. + * - Check if they are the same object. + * - Free the data space of this object to avoid memory leaks. + * - Steal members from the original object. + * - Assign the NULL pointer to the original aligned and allocated members to + * avoid the double free error. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +MemRef &MemRef::operator=(MemRef &&other) noexcept { + // Free the original aligned and allocated space. + delete[] allocated; + // Copy members of the original object. + MemRef::MemRef(other); + return *this; +} + +/** + * @brief MemRef Destructor. Note that the original object no longer owns the + * members and spaces. Note that the `allocated` and `aligned` point to the same + * address, so it is enough to release the space of the `allocated` pointer in + * the destructor. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template MemRef::~MemRef() { + if (allocated) + delete allocated; +} + +/** + * @brief Get the data pointer. + * Return the `aligned` pointer if the container data size is greater than zero. + * If the data size is negative or zero, which means no space is allocated for + * the container data pointer, the function does not allow to return the data + * pointer. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template T *MemRef::getData() { + assert((size > 0) && "Invalid container data size."); + return aligned; +} +/** + * @brief Get the element at index. + * Return a const refrence of specific element if the container data size is + * greater than zero. If the data size is negative or zero, which means no space + * is allocated for the container data pointer, this operator does not allow to + * return the data element. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +const T &MemRef::operator[](size_t index) const { + assert((size > 0) && "Invalid container data size."); + return aligned[index + offset]; +} + +/** + * @brief Get the element at index. + * Return a non-const refrence of specific element if the container data size is + * greater than zero. If the data size is negative or zero, which means no space + * is allocated for the container data pointer, this operator does not allow to + * return the data element. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template T &MemRef::operator[](size_t index) { + assert((size > 0) && "Invalid container data size."); + return aligned[index + offset]; +} + +/** + * @brief Calculate the stride values for each dimension based on the sizes. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template void MemRef::setStrides() { + assert((N > 0) && "Invalid container number of dims"); + strides[N - 1] = 1; + if (N < 2) + return; + for (int i = N - 2; i >= 0; i--) { + strides[i] = strides[i + 1] * sizes[i + 1]; + } +} + +/** + * @brief Calculate the total number of elements in the MemRef container. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template +size_t MemRef::product(intptr_t sizes[N]) const { + size_t size = 1; + for (size_t i = 0; i < N; i++) + size *= sizes[i]; + return size; +} + +/** + * @brief Release the aligned and allocated field. + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + */ +template T *MemRef::release() { + T *temp = aligned; + aligned = nullptr; + allocated = nullptr; + return temp; +} + +#endif // CORE_CONTAINER_DEF diff --git a/lib/Interface/GraphContainer.cpp b/lib/Interface/GraphContainer.cpp new file mode 100644 index 0000000..f2d7beb --- /dev/null +++ b/lib/Interface/GraphContainer.cpp @@ -0,0 +1,522 @@ +//===- GraphContainer.cpp -------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Graph container descriptor. +// +//===----------------------------------------------------------------------===// + +#ifndef INTERFACE_GRAPH_CONTAINER_DEF +#define INTERFACE_GRAPH_CONTAINER_DEF + +#include "Interface/GraphContainer.h" +#include "Interface/Container.h" +#include "Interface/graph.h" +#include +#include + +/** + * @brief Construct a new Graph< T, N>:: Graph object + * + * @tparam T represents the datatype to be used + * @tparam N represents the number of dimensions + * @param graph_type represents the type of graph + * @param size represents the number of nodes in the graph + */ +template +Graph::Graph(uint16_t graph_type, size_t size) { + + // Assign the graph type. + this->graph_type = graph_type; + this->size = size; + this->sizes[0] = size; + this->sizes[1] = size; + + size_t maxEdges = ((this->size) * (this->size - 1)) / 2; + + // resize the adjacency list according to the number of nodes. + switch (graph_type) { + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_UNWEIGHTED: + this->adjList.resize(this->size); + break; + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_UNWEIGHTED: + this->adjList.resize(this->size); + break; + + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_WEIGHTED: + this->adjList_weighted.resize(this->size); + break; + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_WEIGHTED: + this->adjList_weighted.resize(this->size); + break; + + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_UNWEIGHTED: + this->incMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->incMat[i].resize(maxEdges); + } + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_UNWEIGHTED: + this->incMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->incMat[i].resize(maxEdges); + } + break; + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_WEIGHTED: + this->incMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->incMat[i].resize(maxEdges); + } + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_WEIGHTED: + this->incMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->incMat[i].resize(maxEdges); + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED: + this->adjMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->adjMat[i].resize(this->size); + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED: + this->adjMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->adjMat[i].resize(this->size); + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_UNWEIGHTED: + this->adjMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->adjMat[i].resize(this->size); + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_UNWEIGHTED: + this->adjMat.resize(this->size); + for (size_t i = 0; i < this->size; i++) { + this->adjMat[i].resize(this->size); + } + break; + + default: + std::cout << "Unknown graph container" << std::endl; + } +} +/** + * @brief This function provides the functionality to add edges to the graph + * + * @tparam T represnts the datatype used. + * @tparam N represnts the number of dimensions. + * @param Node1 The first node for inserting an edge + * @param Node2 The second node for inserting an edge. + */ + +template void Graph::addEdge(T Node1, T Node2) { + + switch (this->graph_type) { + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_UNWEIGHTED: + this->adjList[Node1].push_back(Node2); + this->adjList[Node2].push_back(Node1); + this->edgeCount++; + break; + + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_UNWEIGHTED: + this->adjList[Node1].push_back(Node2); + this->edgeCount++; + break; + + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_UNWEIGHTED: + this->incMat[Node1][edgeCount] = 1; + this->incMat[Node2][edgeCount] = 1; + this->edgeCount += 1; + break; + + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_UNWEIGHTED: + if (Node1 == Node2) { + this->incMat[Node1][edgeCount] = 2; + this->incMat[Node2][edgeCount] = 2; + this->edgeCount += 1; + } else { + this->incMat[Node1][edgeCount] = 1; + this->incMat[Node2][edgeCount] = -1; + this->edgeCount += 1; + } + break; + + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_UNWEIGHTED: + if (Node1 == Node2) { + this->adjMat[Node1][Node1] = 1; + this->edgeCount++; + } else { + this->adjMat[Node1][Node2] = 1; + this->adjMat[Node2][Node1] = 1; + this->edgeCount++; + } + break; + + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_UNWEIGHTED: + if (Node1 == Node2) { + this->adjMat[Node1][Node1] = 1; + this->edgeCount++; + } else { + this->adjMat[Node1][Node2] = 1; + this->edgeCount++; + } + break; + + default: + this->edgeCount++; + } +} + +/** + * @brief Overloading function for weighted graphs, currently assuming edges are + * of the same type as nodes + * + * @tparam T Represnts the datatype used + * @tparam N Represents the nnumber of dimensions + * @param Node1 First Node for creating an edge + * @param Node2 Second node for creating an edge + * @param EdgeWeight The edgeweight for the edge. + */ +template +void Graph::addEdge(T Node1, T Node2, T EdgeWeight) { + // Add an edge between any two nodes + switch (this->graph_type) { + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_WEIGHTED: + this->adjList_weighted[Node1].push_back(std::make_pair(Node2, EdgeWeight)); + break; + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_WEIGHTED: + this->adjList_weighted[Node1].push_back(std::make_pair(Node2, EdgeWeight)); + this->adjList_weighted[Node2].push_back(std::make_pair(Node1, EdgeWeight)); + break; + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_WEIGHTED: + this->edgeCount += 1; + this->incMat[Node1][edgeCount] = EdgeWeight; + this->incMat[Node2][edgeCount] = EdgeWeight; + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_WEIGHTED: + EdgeWeight = std::abs(sqrt(EdgeWeight)); + this->incMat[Node1][edgeCount] = EdgeWeight; + this->incMat[Node2][edgeCount] = -EdgeWeight; + this->edgeCount += 1; + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED: + this->edgeCount++; + this->adjMat[Node1][Node2] = EdgeWeight; + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED: + this->edgeCount++; + this->adjMat[Node1][Node2] = EdgeWeight; + this->adjMat[Node2][Node1] = EdgeWeight; + break; + } +} +/** + * @brief Prints the Graph in its original form before its conversion to a + * linear memref descriptor + * + * @tparam T represents the datatype used + * @tparam N represnts the number of dimensions. + */ +template void Graph::printGraphOg() { + std::cout << "Nodes -> Edges \n"; + for (size_t i = 0; i < this->size; i++) { + std::cout << i << " -> "; + switch (this->graph_type) { + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_UNWEIGHTED: + for (T x : this->adjList[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_UNWEIGHTED: + for (T x : this->adjList[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_WEIGHTED: + // for (std:vector : x : this->weighted_nodes.at(i)) { + for (size_t j = 0; j < this->adjList_weighted[i].size(); j++) { + std::cout << this->adjList_weighted[i].at(j).first; + std::cout << " Weight(" << this->adjList_weighted[i].at(j).second + << ") | "; + } + break; + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_WEIGHTED: + for (size_t j = 0; j < this->adjList_weighted[i].size(); j++) { + std::cout << this->adjList_weighted[i].at(j).first; + std::cout << " Weight(" << this->adjList_weighted[i].at(j).second + << ") | "; + } + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_UNWEIGHTED: + for (T x : this->incMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_UNWEIGHTED: + for (T x : this->incMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_WEIGHTED: + for (T x : this->incMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_WEIGHTED: + for (T x : this->incMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED: + for (T x : this->adjMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED: + for (T x : this->adjMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_UNWEIGHTED: + for (T x : this->adjMat[i]) { + std::cout << x << " "; + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_UNWEIGHTED: + for (T x : this->adjMat[i]) { + std::cout << x << " "; + } + break; + } + std::cout << std::endl; + } +}; +// /** +// * @brief Function to print the graph using the memref descriptor +// * +// * @tparam T Repesents the datatype used +// * @tparam N represents the number of dimensions. +// */ +template void Graph::printGraph() { + if (!this->data) { + std::cout << "Graph is not converted into memref! \n"; + return; + } + auto y = this->data->getData(); + for (int v = 0; v < this->sizes[0]; ++v) { + for (int w = 0; w < this->sizes[1]; ++w) { + std::cout << y[this->sizes[0] * v + w] << " "; + } + std::cout << "\n"; + } +} +/** + * @brief Converts the various Graph representations types to a linear memref + * descriptor + * + * @tparam T represents the datatype used + * @tparam N represents the number of dimensions. + * @return MemRef_descriptor returns a memref descriptor of the respective graph + * representation type after conversion. + */ + +template void Graph::graph_to_MemRef_descriptor() { + // Assign the memebers of MefRef. + intptr_t x = this->sizes[0]; + intptr_t y = this->sizes[1]; + T *linear = (T *)malloc(sizeof(T) * x * y); + size_t maxEdges = ((this->size) * (this->size - 1)) / 2; + T flag = -2; + + for (intptr_t i = 0; i < x; i++) { + for (intptr_t j = 0; j < y; j++) { + linear[i * x + j] = 0; + } + } + + switch (this->graph_type) { + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_UNWEIGHTED: + for (intptr_t i = 0; i < x; i++) { + intptr_t neighbour_count = this->adjList[i].size(); + for (intptr_t j = 0; j < neighbour_count; j++) { + + T n = this->adjList[i][j]; + linear[i * x + (int)n] = 1; + linear[(int)n * x + i] = 1; + } + } + break; + + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_UNWEIGHTED: + for (intptr_t i = 0; i < x; i++) { + intptr_t neighbour_count = this->adjList[i].size(); + for (intptr_t j = 0; j < neighbour_count; j++) { + + T n = this->adjList[i][j]; + linear[i * x + (int)n] = 1; + } + } + break; + + case graph::detail::GRAPH_ADJ_LIST_DIRECTED_WEIGHTED: + for (unsigned int i = 0; i < x; ++i) { + for (auto X : this->adjList_weighted[i]) { + linear[i * x + int(X.first)] = X.second; + } + } + break; + + case graph::detail::GRAPH_ADJ_LIST_UNDIRECTED_WEIGHTED: + for (unsigned int i = 0; i < x; ++i) { + for (auto X : this->adjList_weighted[i]) { + linear[i * x + int(X.first)] = X.second; + linear[i + x * int(X.first)] = X.second; + } + } + break; + + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_UNWEIGHTED: + for (size_t j = 0; j < maxEdges; j++) { + flag = -2; + for (size_t i = 0; i < this->incMat.size() && flag != -1; i++) { + if (this->incMat[i][j] == 1 && flag == -2) { + flag = i; + } else if (this->incMat[i][j] == 1 && flag != -2) { + linear[int(flag) * x + i] = 1; + linear[i * x + int(flag)] = 1; + flag = -1; + } + // covering corner case of self-loop + if (i == this->incMat.size() - 1 && (flag != -1 && flag != -2)) { + linear[int(flag) * x + int(flag)] = 1; + flag = -1; + } + } + } + break; + case graph::detail::GRAPH_INC_MATRIX_UNDIRECTED_WEIGHTED: + for (size_t j = 0; j < maxEdges; j++) { + flag = -2; + for (size_t i = 0; i < this->incMat.size() && flag != -1; i++) { + if (this->incMat[i][j] != 0 && flag == -2) { + flag = i; + } else if (this->incMat[i][j] != 0 && flag != -2) { + linear[int(flag) * x + i] = incMat[i][j]; + linear[i * x + int(flag)] = incMat[i][j]; + flag = -1; + } + // covering corner case of self-loop + if (i == this->incMat.size() - 1 && (flag != -1 && flag != -2)) { + linear[int(flag) * x + int(flag)] = incMat[int(flag)][j]; + flag = -1; + } + } + } + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_UNWEIGHTED: + for (size_t j = 0; j < maxEdges; j++) { + flag = -2; + for (size_t i = 0; i < this->incMat.size() && flag != -1; i++) { + if ((this->incMat[i][j] == 1 || this->incMat[i][j] == -1) && + flag == -2) { + flag = i; + } else if ((this->incMat[i][j] == 1 || this->incMat[i][j] == -1) && + flag != -2) { + if (this->incMat[i][j] == -1) + linear[int(flag) * x + i] = 1; + else + linear[i * x + int(flag)] = 1; + flag = -1; + } + // case for self loops + if (this->incMat[i][j] == 2) { + linear[i * x + i] = 1; + flag = -1; + } + } + } + break; + case graph::detail::GRAPH_INC_MATRIX_DIRECTED_WEIGHTED: + for (size_t j = 0; j < maxEdges; j++) { + flag = -2; + for (size_t i = 0; i < this->incMat.size() && flag != -1; i++) { + if ((this->incMat[i][j] != 0) && flag == -2) { + flag = i; + size_t k; + for (k = flag + 1; k < this->incMat.size() && flag != -2; k++) { + if ((this->incMat[k][j] != 0) && flag != -1) { + if (this->incMat[k][j] < this->incMat[int(flag)][j]) + linear[int(flag) * x + k] = pow(incMat[k][j], 2); + else + linear[k * x + int(flag)] = pow(incMat[k][j], 2); + flag = -1; + } + } + // case of self loop + if (k == incMat.size() && flag != -1) { + linear[i * x + i] = pow(incMat[i][j], 2); + } + } + } + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_UNWEIGHTED: + for (intptr_t i = 0; i < x; ++i) { + for (intptr_t j = 0; j < x; ++j) { + T n = adjMat[i][j]; + linear[i * x + j] = n; + } + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_DIRECTED_WEIGHTED: + for (intptr_t i = 0; i < x; ++i) { + for (intptr_t j = 0; j < x; ++j) { + T n = adjMat[i][j]; + linear[i * x + j] = n; + } + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_UNWEIGHTED: + for (intptr_t i = 0; i < x; ++i) { + for (intptr_t j = 0; j < x; ++j) { + T n = adjMat[i][j]; + linear[i * x + j] = n; + } + } + break; + case graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED: + for (intptr_t i = 0; i < x; ++i) { + for (intptr_t j = 0; j < x; ++j) { + T n = adjMat[i][j]; + linear[i * x + j] = n; + } + } + break; + + default: + std::cout << "Unknown graph type" << std::endl; + break; + } + + if (data) + delete data; + std::cout << "Inside the graph to memref descriptor! \n"; + data = new MemRef(linear, this->sizes); +} + +#endif // INTERFACE_GRAPH_CONTAINER_DEF diff --git a/lib/Utility/CMakeLists.txt b/lib/Utility/CMakeLists.txt new file mode 100644 index 0000000..c2a4c55 --- /dev/null +++ b/lib/Utility/CMakeLists.txt @@ -0,0 +1 @@ +add_library(Utils Utils.cpp) diff --git a/lib/Utility/Utils.cpp b/lib/Utility/Utils.cpp new file mode 100644 index 0000000..cc719bb --- /dev/null +++ b/lib/Utility/Utils.cpp @@ -0,0 +1,165 @@ +//====- Utils.cpp ---------------------------------------------------------===// +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//===----------------------------------------------------------------------===// +// +// This file implements generic utility functions for the buddy compiler +// ecosystem. +// +//===----------------------------------------------------------------------===// + +#ifndef UTILS_UTILS_DEF +#define UTILS_UTILS_DEF + +#include +#include +#include +#include +#include + +using namespace std; +namespace graph { +void inline generateRandomGraph(Graph *graph, int vertices, + int maxWeight, int randomUpperLimit, + int randomLowerLimit) { + // printf("Inside the function create_graph\n"); + std::set> container; + std::set>::iterator it; + // printf("Inside the function create_graph 1\n"); + srand(time(NULL)); + // printf("Inside the function create_graph 2\n"); + int NUM = vertices; // Number of Vertices + int MAX_EDGES = vertices * (vertices - 1) / 2; + int NUMEDGE = MAX_EDGES; // Number of Edges + + // Then print the edges of the form (a b) + // where 'a' is connected to 'b' + for (int j = 1; j <= NUMEDGE; j++) { + int a = rand() % NUM; + int b = rand() % NUM; + std::pair p = std::make_pair(a, b); + std::pair reverse_p = std::make_pair(b, a); + + while (container.find(p) != container.end() || + container.find(reverse_p) != container.end()) { + a = rand() % NUM; + b = rand() % NUM; + p = std::make_pair(a, b); + reverse_p = std::make_pair(b, a); + } + + container.insert(p); + // int wt = 1 + rand() % MAXWEIGHT; + + graph->addEdge(a, b, 1 + rand() % maxWeight); + } + // for (it=container.begin(); it!=container.end(); ++it) + // printf("%d %d\n", it->first, it->second); + + container.clear(); + printf("\n"); + // return graph; + // } +} + +void inline generateRandomGraph(Graph *graph, int vertices, + int maxWeight, int randomUpperLimit, + int randomLowerLimit) { + // printf("Inside the function create_graph\n"); + std::set> container; + std::set>::iterator it; + // printf("Inside the function create_graph 1\n"); + srand(time(NULL)); + // printf("Inside the function create_graph 2\n"); + int NUM = vertices; // Number of Vertices + int MAX_EDGES = vertices * (vertices - 1) / 2; + int NUMEDGE = MAX_EDGES; // Number of Edges + + // Then print the edges of the form (a b) + // where 'a' is connected to 'b' + for (int j = 1; j <= NUMEDGE; j++) { + int a = rand() % NUM; + int b = rand() % NUM; + std::pair p = std::make_pair(a, b); + std::pair reverse_p = std::make_pair(b, a); + + while (container.find(p) != container.end() || + container.find(reverse_p) != container.end()) { + a = rand() % NUM; + b = rand() % NUM; + p = std::make_pair(a, b); + reverse_p = std::make_pair(b, a); + } + + container.insert(p); + // int wt = 1 + rand() % MAXWEIGHT; + + graph->addEdge(a, b, 1 + rand() % maxWeight); + } + // for (it=container.begin(); it!=container.end(); ++it) + // printf("%d %d\n", it->first, it->second); + + container.clear(); + printf("\n"); + // return graph; + // } +} + +void inline generateRandomGraph(std::vector &edge, + std::vector &weight, int vertices, + int maxWeight, int randomUpperLimit, + int randomLowerLimit) { + // printf("Inside the function create_graph\n"); + std::set> container; + std::set>::iterator it; + // printf("Inside the function create_graph 1\n"); + srand(time(NULL)); + // printf("Inside the function create_graph 2\n"); + int NUM = vertices; // Number of Vertices + int MAX_EDGES = vertices * (vertices - 1) / 2; + int NUMEDGE = MAX_EDGES; // Number of Edges + + // Then print the edges of the form (a b) + // where 'a' is connected to 'b' + for (int j = 1; j <= NUMEDGE; j++) { + int a = 1 + rand() % NUM; + int b = 1 + rand() % NUM; + std::pair p = std::make_pair(a, b); + std::pair reverse_p = std::make_pair(b, a); + + while (container.find(p) != container.end() || + container.find(reverse_p) != container.end()) { + a = 1 + rand() % NUM; + b = 1 + rand() % NUM; + p = std::make_pair(a, b); + reverse_p = std::make_pair(b, a); + } + // cout<<"Inside here"<<"\n"; + container.insert(p); + int wt = 1 + rand() % maxWeight; + + edge.push_back(a); + edge.push_back(b); + weight.push_back(wt); + } + // for (it=container.begin(); it!=container.end(); ++it) + // printf("%d %d\n", it->first, it->second); + + container.clear(); + printf("\n"); + // return graph; + // } +} +} // namespace graph +#endif \ No newline at end of file diff --git a/llvm b/llvm index b1333f0..088f336 160000 --- a/llvm +++ b/llvm @@ -1 +1 @@ -Subproject commit b1333f03d94e4099c2bbffb19eeb6df293c61500 +Subproject commit 088f33605d8a61ff519c580a71b1dd57d16a03f8 diff --git a/tools/graph-opt/CMakeLists.txt b/tools/graph-opt/CMakeLists.txt index be54f11..b53c059 100644 --- a/tools/graph-opt/CMakeLists.txt +++ b/tools/graph-opt/CMakeLists.txt @@ -10,6 +10,8 @@ target_link_libraries(graph-opt ${dialect_libs} ${conversion_libs} MLIROptLib - + MLIRTestTransformDialect + MLIRVectorTestPasses + MLIRTestDialect LowerGraphPass ) diff --git a/tools/graph-opt/graph-opt.cpp b/tools/graph-opt/graph-opt.cpp index 006e846..6698e17 100644 --- a/tools/graph-opt/graph-opt.cpp +++ b/tools/graph-opt/graph-opt.cpp @@ -4,6 +4,7 @@ // //===----------------------------------------------------------------------===// +#include "mlir/IR/AsmState.h" #include "mlir/IR/Dialect.h" #include "mlir/IR/MLIRContext.h" #include "mlir/InitAllDialects.h" @@ -20,21 +21,33 @@ #include "Graph/GraphDialect.h" #include "Graph/GraphOps.h" +// using namespace llvm; +// using namespace mlir; + namespace mlir { namespace graph { void registerLowerGraphPass(); } // namespace graph +namespace test { + void registerTestVectorLowerings(); +} } // namespace mlir +namespace test { +void registerTestDialect(mlir::DialectRegistry &); +void registerTestTransformDialectExtension(mlir::DialectRegistry &); +} + int main(int argc, char **argv) { // Register all MLIR passes. mlir::registerAllPasses(); - mlir::graph::registerLowerGraphPass(); - + mlir::test::registerTestVectorLowerings(); mlir::DialectRegistry registry; // Register all MLIR core dialects. registerAllDialects(registry); + ::test::registerTestDialect(registry); + ::test::registerTestTransformDialectExtension(registry); // Register dialects in graph-mlir project. // clang-format off registry.insert();