From b09daab202bf67d7c77327b04cd6afb3fae7aaaa Mon Sep 17 00:00:00 2001 From: Pankaj Khushalani <2182001pk@gmail.com> Date: Fri, 26 May 2023 00:38:01 +0530 Subject: [PATCH 1/6] feat(mst): initial implementation Signed-off-by: Pankaj Khushalani <2182001pk@gmail.com> --- examples/CMakeLists.txt | 11 +- examples/graph.mlir | 5 + examples/minSpanningTreeExample.cpp | 73 ++++++++++ examples/test.mlir | 23 ++++ include/Dialect/Graph/GraphOps.td | 22 +++ include/Interface/graph.h | 9 +- lib/Conversion/LowerGraph/LowerGraphPass.cpp | 133 +++++++++++++++++++ 7 files changed, 269 insertions(+), 7 deletions(-) create mode 100644 examples/minSpanningTreeExample.cpp create mode 100644 examples/test.mlir diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e22b345..bc265a9 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,11 +1,10 @@ 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 + -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 + -convert-memref-to-llvm + -convert-func-to-llvm='emit-c-wrappers=1' -reconcile-unrealized-casts | ${LLVM_MLIR_BINARY_DIR}/mlir-translate --mlir-to-llvmir @@ -28,3 +27,7 @@ target_link_libraries(bfsExample GRAPH) add_executable(floydWarshallExample floydWarshallExample.cpp) add_dependencies(floydWarshallExample graph-opt) target_link_libraries(floydWarshallExample GRAPH) + +add_executable(minSpanningTreeExample minSpanningTreeExample.cpp) +add_dependencies(minSpanningTreeExample graph-opt) +target_link_libraries(minSpanningTreeExample GRAPH) diff --git a/examples/graph.mlir b/examples/graph.mlir index d3ac578..3f5f992 100644 --- a/examples/graph.mlir +++ b/examples/graph.mlir @@ -11,3 +11,8 @@ func.func @floyd_warshall(%input : memref, %output : memref) return } +func.func @min_spanning_tree(%input : memref, %output : memref, %visited : memref, %cost : memref) +{ + graph.MinSpanningTree %input, %output, %visited, %cost : memref, memref, memref, memref + return +} \ No newline at end of file diff --git a/examples/minSpanningTreeExample.cpp b/examples/minSpanningTreeExample.cpp new file mode 100644 index 0000000..9982163 --- /dev/null +++ b/examples/minSpanningTreeExample.cpp @@ -0,0 +1,73 @@ +//====- 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 = 5; + Graph sample_graph( + graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED, MAX_VERTICES); + + sample_graph.addEdge(0, 2, 1); + sample_graph.addEdge(1, 3, 1); + sample_graph.addEdge(1, 4, 2); + sample_graph.addEdge(2, 1, 6); + sample_graph.addEdge(2, 3, 3); + sample_graph.addEdge(3, 4, 1); + sample_graph.addEdge(4, 0, 1); + + std::cout << "Printing graph in format it was entered ( " + "GRAPH_ADJ_MARIX_UNDIRECTED_WEIGHTED )\n"; + sample_graph.printGraphOg(); + std::cout + << "Printing graph in form of 2d matrix after conversion to memref\n"; + sample_graph.printGraph(); + + int V = MAX_VERTICES; + intptr_t size[1]; + size[0] = V; + + MemRef output = MemRef(size, -1); + + // visited tracks vertices that have been visited so far. 0 for unvisited, 1 for visited + MemRef visited = MemRef(size, 0); + // // key tracks the minimum weighted edge corresponding to each vertex, initially infinity (1000) + MemRef cost = MemRef(size, 1000); + + // source vertex cost is set to 0 so that it is picked first + cost[0] = 0; + + auto x = sample_graph.get_Memref(); + graph::min_spanning_tree(&x, &output, &visited, &cost); + + auto parent = output.getData(); + auto y = visited.getData(); + auto z = cost.getData(); + + // expected output - [0 3 0 4 0] + std::cout<<"\nMinimum Spanning Tree\n"; + for(int i=0; i = dense<[[0. , 0. , 1. , 0. , 1.], + [0., 0., 7., 1. , 2.], + [1., 7., 0., 3. , 0.], + [0., 1., 3., 0. , 1.], + [1., 2., 0., 1. , 0.]]> + + memref.global "private" @out : memref<5xi32> = dense<[-1, -1, -1, -1, -1]> + + +func.func @min_spanning_tree(%input : memref<5x5xf32>, %output : memref<5xi32>) +{ + graph.MinSpanningTree %input, %output : memref<5x5xf32>, memref<5xi32> + return +} + + + func.func @main() { + %input = memref.get_global @in : memref<5x5xf32> + %output = memref.get_global @out : memref<5xi32> + func.call @min_spanning_tree(%input, %output) : (memref<5x5xf32>, memref<5xi32>) -> () + func.return + } \ No newline at end of file diff --git a/include/Dialect/Graph/GraphOps.td b/include/Dialect/Graph/GraphOps.td index ccf7c0f..623bdf2 100644 --- a/include/Dialect/Graph/GraphOps.td +++ b/include/Dialect/Graph/GraphOps.td @@ -59,4 +59,26 @@ def Graph_FloydWarshallOp : Graph_Op<"FloydWarshall"> }]; } +def Graph_MinSpanningTreeOp: Graph_Op<"MinSpanningTree"> +{ + let summary = [{ + Minimum spanning tree (MST) is a subset of the edges of the graph that includes all vertices of the graph, + forming a tree such that it has the sum of edge weights is the minimum. + This implementation uses the Prim-Jarnik's algorithm for evaluating the MST. + }]; + + let arguments = (ins Arg:$memrefI, + Arg:$memrefO, + Arg:$memrefV, + Arg:$memrefC); + + let assemblyFormat = [{ + $memrefI `,` $memrefO `,` $memrefV `,` $memrefC attr-dict `:` type($memrefI) `,` type($memrefO) `,` type($memrefV) `,` type($memrefC) + }]; +} + #endif // Graph_GraphOPS_TD diff --git a/include/Interface/graph.h b/include/Interface/graph.h index 8d674a4..51e2f97 100644 --- a/include/Interface/graph.h +++ b/include/Interface/graph.h @@ -47,10 +47,8 @@ enum graph_type { extern "C" { void _mlir_ciface_bfs(MemRef graph1, MemRef graph2, MemRef graph3); -} - -extern "C" { void _mlir_ciface_floyd_warshall(MemRef *graph1, MemRef *graph2); +void _mlir_ciface_min_spanning_tree(MemRef *input, MemRef *output, MemRef *visited, MemRef *cost); } } // namespace detail @@ -63,6 +61,11 @@ void inline bfs(MemRef graph1, MemRef graph2, void inline floyd_warshall(MemRef *input, MemRef *output) { detail::_mlir_ciface_floyd_warshall(input, output); } + +void inline min_spanning_tree(MemRef *input, MemRef *output, MemRef *visited, MemRef *cost) { + detail::_mlir_ciface_min_spanning_tree(input, output, visited, cost); +} + } // namespace graph #endif diff --git a/lib/Conversion/LowerGraph/LowerGraphPass.cpp b/lib/Conversion/LowerGraph/LowerGraphPass.cpp index aa9fe85..711c5a7 100644 --- a/lib/Conversion/LowerGraph/LowerGraphPass.cpp +++ b/lib/Conversion/LowerGraph/LowerGraphPass.cpp @@ -26,6 +26,7 @@ #include "mlir/Dialect/MemRef/IR/MemRef.h" #include "mlir/Dialect/Vector/IR/VectorOps.h" #include "mlir/Pass/Pass.h" +#include "mlir/IR/ImplicitLocOpBuilder.h" #include "Graph/GraphDialect.h" #include "Graph/GraphOps.h" @@ -162,12 +163,144 @@ class GraphFloydWarshallLowering : public OpRewritePattern { +public: + using OpRewritePattern::OpRewritePattern; + + explicit GraphMinSpanningTreeLowering(MLIRContext *context, int64_t strideParam) + : OpRewritePattern(context) { + stride = strideParam; + } + + LogicalResult matchAndRewrite(graph::MinSpanningTreeOp op, + PatternRewriter &rewriter) const override { + auto loc = op->getLoc(); + auto ctx = op->getContext(); + // ImplicitLocOpBuilder rewriter(loc, rewriter); + + /* operands */ + Value input = op->getOperand(0); + Value output = op->getOperand(1); + Value visited = op->getOperand(2); + Value cost = op->getOperand(3); + + /* types */ + IndexType idx = IndexType::get(ctx); + IntegerType i32 = IntegerType::get(ctx, 32); + VectorType vi32 = VectorType::get({1000}, i32); + VectorType vidx = VectorType::get({1000}, idx); + + /* constants */ + Value c0 = rewriter.create(loc, 0); + Value c1 = rewriter.create(loc, 1); + Value zeroI = rewriter.create(loc, int(0), i32); + Value oneI = rewriter.create(loc, int(1), i32); + Value minusOneI = rewriter.create(loc, int(-1), i32); + Value minusTwoI = rewriter.create(loc, int(-2), i32); + Value maxI = rewriter.create(loc, int(1000), i32); + + /* loop bounds */ + Value V = rewriter.create(loc, input, c0); + Value vAsInt = rewriter.create(loc, i32, V); + // since MST has V-1 edges + Value eAsInt = rewriter.create(loc, vAsInt, minusOneI); + Value E = rewriter.create(loc, rewriter.getIndexType(), eAsInt); + + /* initial condition */ + // parent of root is root itself + rewriter.create(loc, zeroI, output, c0); + + // loop through V-1 times since MST will have at least V-1 edges + rewriter.create( + loc, c0, E, c1, ValueRange{}, + [&](OpBuilder &builder, Location loc, Value inductionVar, ValueRange iterArgs) { + Value minCost = maxI; + Value minIndex = minusTwoI; + + // finding the minimum weighted edge + scf::ForOp forOp = builder.create( + loc, c0, V, c1, ValueRange{cost, visited, minIndex, minCost}, + [&](OpBuilder &builder, Location loc, Value iv, ValueRange args) { + Value cost = args[0]; + Value visited = args[1]; + Value minIndex = args[2]; + Value minCost = args[3]; + + Value costArg = builder.create(loc, cost, iv); + Value visitedArg = builder.create(loc, visited, iv); + + // if vertex is unvisited and cost is lesser than current minimum cost + Value visitedCondition = builder.create(loc, arith::CmpIPredicate::eq, visitedArg, zeroI); + Value costCondition = builder.create(loc, arith::CmpIPredicate::ult, costArg, minCost); + Value condition = builder.create(loc, visitedCondition, costCondition); + + scf::IfOp ifOp = builder.create(loc, TypeRange{i32, i32}, condition, + [&](OpBuilder &builder, Location loc) { + Value temp = builder.create(loc, i32, iv); + builder.create(loc, ValueRange{temp, costArg}); + }, + // else block + [&](OpBuilder &builder, Location loc) { + builder.create(loc, ValueRange{minIndex, minCost}); + }); + minIndex = ifOp.getResult(0); + minCost = ifOp.getResult(1); + + builder.create(loc, ValueRange{cost, visited, minIndex, minCost}); + }); + Value minIndexFoundAsInt = forOp.getResult(2); + Value minIndexFound = builder.create(loc, builder.getIndexType(), minIndexFoundAsInt); + + // mark vertex as visited + builder.create(loc, oneI, visited, minIndexFound); + + // adding the edge to output and updating weights + builder.create( + loc, c0, V, c1, ValueRange{cost, visited, minIndexFound}, + [&](OpBuilder &builder, Location loc, Value iv, ValueRange args) { + Value costVal = args[0]; + Value visited = args[1]; + Value minIndex = args[2]; + + Value costArg = builder.create(loc, cost, iv); + Value visitedArg = builder.create(loc, visited, iv); + Value weight = builder.create(loc, input, ValueRange{minIndex, iv}); + + // if vertex is unvisited, edge between current vertex and minIndex vertex exists, and edge weight is lesser than current cost for that vertex + Value visitedCondition = builder.create(loc, arith::CmpIPredicate::eq, visitedArg, zeroI); + Value costCondition = builder.create(loc, arith::CmpIPredicate::ult, weight, costArg); + Value existsCondition = builder.create(loc, arith::CmpIPredicate::ne, weight, zeroI); + Value condition = builder.create(loc, existsCondition, builder.create(loc, visitedCondition, costCondition)); + + builder.create(loc, condition, + [&](OpBuilder &builder, Location loc) { + Value minIndexAsInt = builder.create(loc, i32, minIndex); + builder.create(loc, minIndexAsInt, output, iv); + builder.create(loc, weight, cost, iv); + builder.create(loc); + }); + + builder.create(loc, ValueRange{cost, visited, minIndex}); + }); + + builder.create(loc); + }); + + rewriter.eraseOp(op); + return success(); + } + +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); } //===----------------------------------------------------------------------===// From c530a2ce0f45235f94bd2eda6dbca2a63b693216 Mon Sep 17 00:00:00 2001 From: Pankaj Khushalani <2182001pk@gmail.com> Date: Fri, 26 May 2023 00:45:17 +0530 Subject: [PATCH 2/6] chore(mst): delete test.mlir Signed-off-by: Pankaj Khushalani <2182001pk@gmail.com> --- examples/graph.mlir | 2 +- examples/test.mlir | 23 ----------------------- 2 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 examples/test.mlir diff --git a/examples/graph.mlir b/examples/graph.mlir index 3f5f992..1585a7a 100644 --- a/examples/graph.mlir +++ b/examples/graph.mlir @@ -15,4 +15,4 @@ func.func @min_spanning_tree(%input : memref, %output : memref, { graph.MinSpanningTree %input, %output, %visited, %cost : memref, memref, memref, memref return -} \ No newline at end of file +} diff --git a/examples/test.mlir b/examples/test.mlir deleted file mode 100644 index efced06..0000000 --- a/examples/test.mlir +++ /dev/null @@ -1,23 +0,0 @@ - - memref.global "private" @in : memref<5x5xf32> = dense<[[0. , 0. , 1. , 0. , 1.], - [0., 0., 7., 1. , 2.], - [1., 7., 0., 3. , 0.], - [0., 1., 3., 0. , 1.], - [1., 2., 0., 1. , 0.]]> - - memref.global "private" @out : memref<5xi32> = dense<[-1, -1, -1, -1, -1]> - - -func.func @min_spanning_tree(%input : memref<5x5xf32>, %output : memref<5xi32>) -{ - graph.MinSpanningTree %input, %output : memref<5x5xf32>, memref<5xi32> - return -} - - - func.func @main() { - %input = memref.get_global @in : memref<5x5xf32> - %output = memref.get_global @out : memref<5xi32> - func.call @min_spanning_tree(%input, %output) : (memref<5x5xf32>, memref<5xi32>) -> () - func.return - } \ No newline at end of file From c6e64c7be3859bf1f52906530db1141948b749ab Mon Sep 17 00:00:00 2001 From: Pankaj Khushalani <2182001pk@gmail.com> Date: Sun, 28 May 2023 10:40:15 +0530 Subject: [PATCH 3/6] feat(mst): add benchmark Signed-off-by: Pankaj Khushalani <2182001pk@gmail.com> --- benchmarks/BoostMinSpanningTree.cpp | 94 ++++++++++++++++ benchmarks/CMakeLists.txt | 7 +- benchmarks/GraphMlirMinSpanningTree.cpp | 73 +++++++++++++ benchmarks/LemonMinSpanningTree.cpp | 90 ++++++++++++++++ benchmarks/Main.cpp | 17 +++ benchmarks/MinSpanningTree.cpp | 107 +++++++++++++++++++ lib/Conversion/LowerGraph/LowerGraphPass.cpp | 3 - lib/Utility/Utils.cpp | 45 +++++++- 8 files changed, 430 insertions(+), 6 deletions(-) create mode 100644 benchmarks/BoostMinSpanningTree.cpp create mode 100644 benchmarks/GraphMlirMinSpanningTree.cpp create mode 100644 benchmarks/LemonMinSpanningTree.cpp create mode 100644 benchmarks/MinSpanningTree.cpp diff --git a/benchmarks/BoostMinSpanningTree.cpp b/benchmarks/BoostMinSpanningTree.cpp new file mode 100644 index 0000000..abea793 --- /dev/null +++ b/benchmarks/BoostMinSpanningTree.cpp @@ -0,0 +1,94 @@ +//===- 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 Minimum Spanning Tree. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include +#include +#include +#include + +#define V 100 +#define MAX_WEIGHT 1000 + +using namespace std; + +namespace { +typedef int t_weight; + +// define the graph type +typedef boost::property EdgeWeightProperty; +typedef boost::adjacency_list + Graph; +typedef boost::graph_traits::vertex_descriptor VerticesMap; + +Graph g; +} // namespace + +void initializeBoostMinSpanningTree() { + + const int vertices = V; + int num_edges = V * (V -1) / 2; + + std::vector edges; + std::vector weight; + + graph::generateRandomGraph(edges, weight, vertices, MAX_WEIGHT); + + 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); + } + + // set the parent vector to receive the minimum spanning tree output + std::vector p(num_vertices(g)); +} + +// Benchmarking function. +static void BoostMinSpanningTree(benchmark::State &state) { + + for (auto _ : state) { + // set the parent vector to receive the minimum spanning tree output + std::vector p(num_vertices(g)); + + for (int i = 0; i < state.range(0); ++i) { + boost::prim_minimum_spanning_tree(g, &p[0]); + } + } +} + +// Register benchmarking function. +BENCHMARK(BoostMinSpanningTree)->Arg(1); + +void generateResultBoostMinSpanningTree() { + initializeBoostMinSpanningTree(); + + // set the parent vector to receive the minimum spanning tree output + std::vector p(num_vertices(g)); + std::cout << "-------------------------------------------------------\n"; + std::cout << "[ Boost Minimum Spanning Tree Result Information ]\n"; + boost::prim_minimum_spanning_tree(g, &p[0]); + for (int i = 0; i < p.size(); i++) { + std::cout << "p[" << i << "] = " << p[i] << ", "; + } + std::cout << "Boost Minimum Spanning Tree operation finished!\n"; +} diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 40d5c69..1d6e62c 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -19,8 +19,7 @@ COMMAND ${GraphMLIR_BINARY_DIR}/graph-opt ${GraphMLIR_EXAMPLES_DIR}/graph.mlir -test-vector-multi-reduction-lowering-patterns -convert-vector-to-llvm -convert-memref-to-llvm - -llvm-request-c-wrappers - -convert-func-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} @@ -39,6 +38,10 @@ add_executable(graph-processing-benchmark BoostFloydWarshall.cpp GraphMlirFloydWarshallBenchmark.cpp LemonBFS.cpp + MinSpanningTree.cpp + LemonMinSpanningTree.cpp + BoostMinSpanningTree.cpp + GraphMlirMinSpanningTree.cpp Main.cpp ) diff --git a/benchmarks/GraphMlirMinSpanningTree.cpp b/benchmarks/GraphMlirMinSpanningTree.cpp new file mode 100644 index 0000000..143355c --- /dev/null +++ b/benchmarks/GraphMlirMinSpanningTree.cpp @@ -0,0 +1,73 @@ +//===- 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 Minimum Spanning Tree. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +#define V 100 +#define MAX_WEIGHT 1000 + +using namespace std; + +namespace { +Graph g(graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED, V); +MemRef *input; +intptr_t size[1]; +} // namespace + +void initializeGraphMlirMinSpanningTree() { + graph::generateRandomGraphI(&g, V); + input = &g.get_Memref(); + size[0] = V; + + MemRef cost = MemRef(size, MAX_WEIGHT); + MemRef visited = MemRef(size, 0); + MemRef output = MemRef(size, -1); +} + +// Benchmarking function. +static void GraphMlirMinSpanningTree(benchmark::State &state) { + for (auto _ : state) { + MemRef output = MemRef(size, -1); + MemRef visited = MemRef(size, 0); + MemRef cost = MemRef(size, MAX_WEIGHT); + for (int i = 0; i < state.range(0); ++i) { + graph::min_spanning_tree(input, &output, &visited, &cost); + } + } +} + +// Register benchmarking function. +BENCHMARK(GraphMlirMinSpanningTree)->Arg(1); + +void generateResultGraphMlirMinSpanningTree() { + initializeGraphMlirMinSpanningTree(); + MemRef output(size, -1); + MemRef visited(size, 0); + MemRef cost(size, MAX_WEIGHT); + + std::cout << "-------------------------------------------------------\n"; + std::cout << "[ GraphMLIR Minimum Spanning Tree Result Information ]\n"; + graph::min_spanning_tree(input, &output, &visited, &cost); + std::cout << "GraphMLIR Minimum Spanning Tree operation finished!\n"; +} diff --git a/benchmarks/LemonMinSpanningTree.cpp b/benchmarks/LemonMinSpanningTree.cpp new file mode 100644 index 0000000..8a67ec8 --- /dev/null +++ b/benchmarks/LemonMinSpanningTree.cpp @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include + +using namespace std; +using namespace lemon; + +#define V 100 +#define MaxWeight 1000 +#define UpperLimit 100 +#define LowerLimit 2 + +typedef ListGraph::Node Node; +typedef ListGraph::Edge Edge; +typedef ListGraph::NodeIt NodeIt; +typedef ListGraph::EdgeIt EdgeIt; +typedef ListGraph::EdgeMap ECostMap; +typedef ListGraph::EdgeMap EBoolMap; + +namespace { +ListGraph g; +ListGraph::Node nodes[V]; +ECostMap edge_cost_map(g); +} // namespace + +void initializeLemonMinSpanningTree() { + for (int i = 0; i < V; i++) { + nodes[i] = g.addNode(); + } + 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==b) { + a = rand() % NUM; + b = rand() % NUM; + p = std::make_pair(a, b); + reverse_p = std::make_pair(b, a); + } + + container.insert(p); + container.insert(reverse_p); + edge_cost_map.set(g.addEdge(nodes[a], nodes[b]), 1 + rand() % MaxWeight); + } +} + +// Benchmarking function. +static void LemonMinSpanningTree(benchmark::State &state) { + for (auto _ : state) { + vector tree_edge_vec; + for (int i = 0; i < state.range(0); ++i) { + kruskal(g, edge_cost_map, std::back_inserter(tree_edge_vec)); + } + } +} + +BENCHMARK(LemonMinSpanningTree)->Arg(1); + +void generateResultLemonMinSpanningTree() { + initializeLemonMinSpanningTree(); + cout << "-------------------------------------------------------\n"; + cout << "[ LEMON Kruskal Result Information ]\n"; + + vector tree_edge_vec; + std::cout << "The weight of the minimum spanning tree is " + << kruskal(g, edge_cost_map, std::back_inserter(tree_edge_vec)) + << std::endl; + + std::cout << "The edges of the tree are: "; + for (int i = tree_edge_vec.size() - 1; i >= 0; i--) + std::cout << g.id(tree_edge_vec[i]) << ";"; + std::cout << std::endl; + std::cout << "The size of the tree is: " << tree_edge_vec.size() + << std::endl; + + cout << "Lemon Kruskal Operation Completed!\n"; +} \ No newline at end of file diff --git a/benchmarks/Main.cpp b/benchmarks/Main.cpp index 39cd8ed..0f17aea 100644 --- a/benchmarks/Main.cpp +++ b/benchmarks/Main.cpp @@ -24,11 +24,19 @@ void initializeGraphMLIRFloydWarshall(); void initializeFloydWarshall(); void initializeLemonBFS(); void initializeBoostFLoydWarshall(); +void initializeMinSpanningTree(); +void initializeBoostMinSpanningTree(); +void initializeLemonMinSpanningTree(); +void initializeGraphMlirMinSpanningTree(); void generateResultGraphMLIRFloydWarshall(); void generateResultFloydWarshall(); void generateResultLemonBFS(); void generateResultBoostFLoydWarshall(); +void generateResultMinSpanningTree(); +void generateResultBoostMinSpanningTree(); +void generateResultLemonMinSpanningTree(); +void generateResultGraphMlirMinSpanningTree(); int main(int argc, char **argv) { @@ -36,6 +44,10 @@ int main(int argc, char **argv) { initializeFloydWarshall(); initializeLemonBFS(); initializeBoostFLoydWarshall(); + initializeMinSpanningTree(); + initializeBoostMinSpanningTree(); + initializeLemonMinSpanningTree(); + initializeGraphMlirMinSpanningTree(); ::benchmark::Initialize(&argc, argv); ::benchmark::RunSpecifiedBenchmarks(); @@ -44,5 +56,10 @@ int main(int argc, char **argv) { generateResultFloydWarshall(); generateResultLemonBFS(); generateResultBoostFLoydWarshall(); + generateResultMinSpanningTree(); + generateResultBoostMinSpanningTree(); + generateResultLemonMinSpanningTree(); + generateResultGraphMlirMinSpanningTree(); + return 0; } diff --git a/benchmarks/MinSpanningTree.cpp b/benchmarks/MinSpanningTree.cpp new file mode 100644 index 0000000..7b5d3b3 --- /dev/null +++ b/benchmarks/MinSpanningTree.cpp @@ -0,0 +1,107 @@ +//===- 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 the naive implementation of Minimum Spanning Tree. +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +// #include + +using namespace std; + +#define V 100 +# define INF 1000 + +namespace { +int input[V][V]; +int output[V]; +} // namespace + +void minSpanningTree(int graph[][V], int parent[V]) { + float key[V]; + bool visited[V]; + + for (int i = 0; i < V; i++) { + key[i] = INF; + visited[i] = false; + } + + key[0] = 0; + parent[0] = 0; + + for (int count = 0; count < V-1; count++) { + int min_index = -1; + float min_cost = INF; + int min_index_temp = -1; + for (int i = 0; i < V; i++) { + min_index_temp = min_index; + if (visited[i] == false && key[i] < min_cost) { + min_cost = key[i]; + min_index = i; + } + else { + min_index = min_index_temp; + } + } + visited[min_index] = true; + + for (int v = 0; v < V; v++) { + if (graph[min_index][v] && visited[v] == false && graph[min_index][v] < key[v]) { + parent[v] = min_index; + key[v] = graph[min_index][v]; + } + } + } +} + +void initializeMinSpanningTree() { + 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() % 1000; + input[u][v] = d; + } + memset(output, 0, sizeof(output)); +} + +// Benchmarking function. +static void MinSpanningTree(benchmark::State &state) { + for (auto _ : state) { + for (int i = 0; i < state.range(0); ++i) { + minSpanningTree(input, output); + } + } +} + +// Register benchmarking function. +BENCHMARK(MinSpanningTree)->Arg(1); + +void generateResultMinSpanningTree() { + initializeMinSpanningTree(); + std::cout << "-------------------------------------------------------\n"; + std::cout << "[Minimum Spanning Tree Result Information ]\n"; + + minSpanningTree(input, output); + + for (int i = 0; i < V; i++) { + std::cout << output[i] << " "; + } + std::cout << "\nMinimum Spanning Tree operation finished!\n"; +} diff --git a/lib/Conversion/LowerGraph/LowerGraphPass.cpp b/lib/Conversion/LowerGraph/LowerGraphPass.cpp index 711c5a7..f058926 100644 --- a/lib/Conversion/LowerGraph/LowerGraphPass.cpp +++ b/lib/Conversion/LowerGraph/LowerGraphPass.cpp @@ -176,7 +176,6 @@ class GraphMinSpanningTreeLowering : public OpRewritePatterngetLoc(); auto ctx = op->getContext(); - // ImplicitLocOpBuilder rewriter(loc, rewriter); /* operands */ Value input = op->getOperand(0); @@ -187,8 +186,6 @@ class GraphMinSpanningTreeLowering : public OpRewritePattern(loc, 0); diff --git a/lib/Utility/Utils.cpp b/lib/Utility/Utils.cpp index 100e34d..55197e9 100644 --- a/lib/Utility/Utils.cpp +++ b/lib/Utility/Utils.cpp @@ -51,7 +51,7 @@ void inline generateRandomGraph(Graph *graph, int vertices, int maxWei 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()) + while (container.find(p) != container.end() || container.find(reverse_p) != container.end() || a==b) { a = rand() % NUM; b = rand() % NUM; @@ -73,6 +73,49 @@ void inline generateRandomGraph(Graph *graph, int vertices, int maxWei // } } +void inline generateRandomGraphI(Graph *graph, int vertices){ + // 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==b) + { + 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() % 1000); + } + // 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; From 69e2e81d517fbf998540c4e8b55c6682347e242b Mon Sep 17 00:00:00 2001 From: Pankaj Khushalani <2182001pk@gmail.com> Date: Sun, 28 May 2023 16:20:32 +0530 Subject: [PATCH 4/6] chore(mst): cleanup comments Signed-off-by: Pankaj Khushalani <2182001pk@gmail.com> --- benchmarks/BoostMinSpanningTree.cpp | 4 ++-- benchmarks/CMakeLists.txt | 1 - benchmarks/GraphMlirMinSpanningTree.cpp | 10 ++++++++-- benchmarks/LemonMinSpanningTree.cpp | 25 ++++++++++++++++++++++--- benchmarks/MinSpanningTree.cpp | 11 +++++------ examples/minSpanningTreeExample.cpp | 2 +- 6 files changed, 38 insertions(+), 15 deletions(-) diff --git a/benchmarks/BoostMinSpanningTree.cpp b/benchmarks/BoostMinSpanningTree.cpp index abea793..0faf595 100644 --- a/benchmarks/BoostMinSpanningTree.cpp +++ b/benchmarks/BoostMinSpanningTree.cpp @@ -1,4 +1,4 @@ -//===- BoostFloyWarshall.cpp +//===- BoostMinSpanningTree.cpp //-------------------------------------------------------===// // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,7 +27,7 @@ #include #include -#define V 100 +#define V 10 #define MAX_WEIGHT 1000 using namespace std; diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 1d6e62c..6a16c6f 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -43,7 +43,6 @@ add_executable(graph-processing-benchmark BoostMinSpanningTree.cpp GraphMlirMinSpanningTree.cpp Main.cpp - ) diff --git a/benchmarks/GraphMlirMinSpanningTree.cpp b/benchmarks/GraphMlirMinSpanningTree.cpp index 143355c..e3eca0e 100644 --- a/benchmarks/GraphMlirMinSpanningTree.cpp +++ b/benchmarks/GraphMlirMinSpanningTree.cpp @@ -1,4 +1,4 @@ -//===- GraphMlirFloydWarshallBenchmark.cpp +//===- GraphMlirMinSpanningTreeBenchmark.cpp //----------------------------------===// // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,7 @@ #include #include -#define V 100 +#define V 10 #define MAX_WEIGHT 1000 using namespace std; @@ -69,5 +69,11 @@ void generateResultGraphMlirMinSpanningTree() { std::cout << "-------------------------------------------------------\n"; std::cout << "[ GraphMLIR Minimum Spanning Tree Result Information ]\n"; graph::min_spanning_tree(input, &output, &visited, &cost); + + auto parent = output.getData(); + for (int i = 0; i < V; i++) { + std::cout << "p[" << i << "] = " << parent[i] << ", "; + } + std::cout << "GraphMLIR Minimum Spanning Tree operation finished!\n"; } diff --git a/benchmarks/LemonMinSpanningTree.cpp b/benchmarks/LemonMinSpanningTree.cpp index 8a67ec8..940df6f 100644 --- a/benchmarks/LemonMinSpanningTree.cpp +++ b/benchmarks/LemonMinSpanningTree.cpp @@ -1,3 +1,23 @@ +//===- LemonMinSpanningTree.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 LEMON Minimum Spanning Tree. +// +//===----------------------------------------------------------------------===// + #include #include #include @@ -7,7 +27,7 @@ using namespace std; using namespace lemon; -#define V 100 +#define V 10 #define MaxWeight 1000 #define UpperLimit 100 #define LowerLimit 2 @@ -17,7 +37,6 @@ typedef ListGraph::Edge Edge; typedef ListGraph::NodeIt NodeIt; typedef ListGraph::EdgeIt EdgeIt; typedef ListGraph::EdgeMap ECostMap; -typedef ListGraph::EdgeMap EBoolMap; namespace { ListGraph g; @@ -87,4 +106,4 @@ void generateResultLemonMinSpanningTree() { << std::endl; cout << "Lemon Kruskal Operation Completed!\n"; -} \ No newline at end of file +} diff --git a/benchmarks/MinSpanningTree.cpp b/benchmarks/MinSpanningTree.cpp index 7b5d3b3..fbc72c6 100644 --- a/benchmarks/MinSpanningTree.cpp +++ b/benchmarks/MinSpanningTree.cpp @@ -1,4 +1,4 @@ -//===- FloydWarshall.cpp --------------------------------------------------===// +//===- MinSpanningTree.cpp --------------------------------------------------===// // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -12,20 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. // -//===----------------------------------------------------------------------===// +//===-----------------------------------------------------------------------------------===// // // This file implements the benchmark for the naive implementation of Minimum Spanning Tree. // -//===----------------------------------------------------------------------===// +//===-----------------------------------------------------------------------------------===// #include #include #include -// #include using namespace std; -#define V 100 +#define V 10 # define INF 1000 namespace { @@ -101,7 +100,7 @@ void generateResultMinSpanningTree() { minSpanningTree(input, output); for (int i = 0; i < V; i++) { - std::cout << output[i] << " "; + std::cout << "p[" << i << "] = " << output[i] << ", "; } std::cout << "\nMinimum Spanning Tree operation finished!\n"; } diff --git a/examples/minSpanningTreeExample.cpp b/examples/minSpanningTreeExample.cpp index 9982163..f8263d0 100644 --- a/examples/minSpanningTreeExample.cpp +++ b/examples/minSpanningTreeExample.cpp @@ -1,4 +1,4 @@ -//====- floydWarshallExample.cpp =============================================// +//====- minSpanningTreeExample.cpp =============================================// // // The graph.bfs operation will be compiled into an object file with the // graph-opt tool. From 347a2dedd8bed688896280d9e48d5015314b5bbc Mon Sep 17 00:00:00 2001 From: Pankaj Khushalani <2182001pk@gmail.com> Date: Sun, 28 May 2023 16:22:09 +0530 Subject: [PATCH 5/6] fix(mst): max weight limit bug Signed-off-by: Pankaj Khushalani <2182001pk@gmail.com> --- lib/Conversion/LowerGraph/LowerGraphPass.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/Conversion/LowerGraph/LowerGraphPass.cpp b/lib/Conversion/LowerGraph/LowerGraphPass.cpp index f058926..a434cb7 100644 --- a/lib/Conversion/LowerGraph/LowerGraphPass.cpp +++ b/lib/Conversion/LowerGraph/LowerGraphPass.cpp @@ -194,7 +194,7 @@ class GraphMinSpanningTreeLowering : public OpRewritePattern(loc, int(1), i32); Value minusOneI = rewriter.create(loc, int(-1), i32); Value minusTwoI = rewriter.create(loc, int(-2), i32); - Value maxI = rewriter.create(loc, int(1000), i32); + Value maxI = rewriter.create(loc, int(1001), i32); /* loop bounds */ Value V = rewriter.create(loc, input, c0); @@ -228,7 +228,7 @@ class GraphMinSpanningTreeLowering : public OpRewritePattern(loc, arith::CmpIPredicate::eq, visitedArg, zeroI); - Value costCondition = builder.create(loc, arith::CmpIPredicate::ult, costArg, minCost); + Value costCondition = builder.create(loc, arith::CmpIPredicate::slt, costArg, minCost); Value condition = builder.create(loc, visitedCondition, costCondition); scf::IfOp ifOp = builder.create(loc, TypeRange{i32, i32}, condition, @@ -265,7 +265,7 @@ class GraphMinSpanningTreeLowering : public OpRewritePattern(loc, arith::CmpIPredicate::eq, visitedArg, zeroI); - Value costCondition = builder.create(loc, arith::CmpIPredicate::ult, weight, costArg); + Value costCondition = builder.create(loc, arith::CmpIPredicate::slt, weight, costArg); Value existsCondition = builder.create(loc, arith::CmpIPredicate::ne, weight, zeroI); Value condition = builder.create(loc, existsCondition, builder.create(loc, visitedCondition, costCondition)); From ca9825c488c5ac03949e38dc17c7d6cb9a77195e Mon Sep 17 00:00:00 2001 From: Pankaj Khushalani <2182001pk@gmail.com> Date: Sun, 31 Mar 2024 01:57:57 +0530 Subject: [PATCH 6/6] refactor: rename variables Signed-off-by: Pankaj Khushalani <2182001pk@gmail.com> --- benchmarks/BoostMinSpanningTree.cpp | 6 +++--- benchmarks/GraphMlirMinSpanningTree.cpp | 10 ++++----- benchmarks/LemonMinSpanningTree.cpp | 26 ++++++++++------------- benchmarks/MinSpanningTree.cpp | 28 ++++++++++++------------- 4 files changed, 33 insertions(+), 37 deletions(-) diff --git a/benchmarks/BoostMinSpanningTree.cpp b/benchmarks/BoostMinSpanningTree.cpp index 0faf595..52e975f 100644 --- a/benchmarks/BoostMinSpanningTree.cpp +++ b/benchmarks/BoostMinSpanningTree.cpp @@ -27,7 +27,7 @@ #include #include -#define V 10 +#define VERTICES 10 #define MAX_WEIGHT 1000 using namespace std; @@ -47,8 +47,8 @@ Graph g; void initializeBoostMinSpanningTree() { - const int vertices = V; - int num_edges = V * (V -1) / 2; + const int vertices = VERTICES; + int num_edges = VERTICES * (VERTICES - 1) / 2; std::vector edges; std::vector weight; diff --git a/benchmarks/GraphMlirMinSpanningTree.cpp b/benchmarks/GraphMlirMinSpanningTree.cpp index e3eca0e..2e16c93 100644 --- a/benchmarks/GraphMlirMinSpanningTree.cpp +++ b/benchmarks/GraphMlirMinSpanningTree.cpp @@ -24,21 +24,21 @@ #include #include -#define V 10 +#define VERTICES 10 #define MAX_WEIGHT 1000 using namespace std; namespace { -Graph g(graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED, V); +Graph g(graph::detail::GRAPH_ADJ_MATRIX_UNDIRECTED_WEIGHTED, VERTICES); MemRef *input; intptr_t size[1]; } // namespace void initializeGraphMlirMinSpanningTree() { - graph::generateRandomGraphI(&g, V); + graph::generateRandomGraphI(&g, VERTICES); input = &g.get_Memref(); - size[0] = V; + size[0] = VERTICES; MemRef cost = MemRef(size, MAX_WEIGHT); MemRef visited = MemRef(size, 0); @@ -71,7 +71,7 @@ void generateResultGraphMlirMinSpanningTree() { graph::min_spanning_tree(input, &output, &visited, &cost); auto parent = output.getData(); - for (int i = 0; i < V; i++) { + for (int i = 0; i < VERTICES; i++) { std::cout << "p[" << i << "] = " << parent[i] << ", "; } diff --git a/benchmarks/LemonMinSpanningTree.cpp b/benchmarks/LemonMinSpanningTree.cpp index 940df6f..732818b 100644 --- a/benchmarks/LemonMinSpanningTree.cpp +++ b/benchmarks/LemonMinSpanningTree.cpp @@ -27,10 +27,8 @@ using namespace std; using namespace lemon; -#define V 10 -#define MaxWeight 1000 -#define UpperLimit 100 -#define LowerLimit 2 +#define VERTICES 10 +#define MAX_WEIGHT 1000 typedef ListGraph::Node Node; typedef ListGraph::Edge Edge; @@ -40,39 +38,37 @@ typedef ListGraph::EdgeMap ECostMap; namespace { ListGraph g; -ListGraph::Node nodes[V]; +ListGraph::Node nodes[VERTICES]; ECostMap edge_cost_map(g); } // namespace void initializeLemonMinSpanningTree() { - for (int i = 0; i < V; i++) { + for (int i = 0; i < VERTICES; i++) { nodes[i] = g.addNode(); } 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; + int edges = VERTICES * (VERTICES - 1) / 2; + for (int j = 1; j <= edges; j++) { + int a = rand() % VERTICES; + int b = rand() % VERTICES; 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==b) { - a = rand() % NUM; - b = rand() % NUM; + a = rand() % VERTICES; + b = rand() % VERTICES; p = std::make_pair(a, b); reverse_p = std::make_pair(b, a); } container.insert(p); container.insert(reverse_p); - edge_cost_map.set(g.addEdge(nodes[a], nodes[b]), 1 + rand() % MaxWeight); + edge_cost_map.set(g.addEdge(nodes[a], nodes[b]), 1 + rand() % MAX_WEIGHT); } } diff --git a/benchmarks/MinSpanningTree.cpp b/benchmarks/MinSpanningTree.cpp index fbc72c6..a13c6ad 100644 --- a/benchmarks/MinSpanningTree.cpp +++ b/benchmarks/MinSpanningTree.cpp @@ -24,19 +24,19 @@ using namespace std; -#define V 10 +#define VERTICES 10 # define INF 1000 namespace { -int input[V][V]; -int output[V]; +int input[VERTICES][VERTICES]; +int output[VERTICES]; } // namespace -void minSpanningTree(int graph[][V], int parent[V]) { - float key[V]; - bool visited[V]; +void minSpanningTree(int graph[][VERTICES], int parent[VERTICES]) { + float key[VERTICES]; + bool visited[VERTICES]; - for (int i = 0; i < V; i++) { + for (int i = 0; i < VERTICES; i++) { key[i] = INF; visited[i] = false; } @@ -44,11 +44,11 @@ void minSpanningTree(int graph[][V], int parent[V]) { key[0] = 0; parent[0] = 0; - for (int count = 0; count < V-1; count++) { + for (int count = 0; count < VERTICES-1; count++) { int min_index = -1; float min_cost = INF; int min_index_temp = -1; - for (int i = 0; i < V; i++) { + for (int i = 0; i < VERTICES; i++) { min_index_temp = min_index; if (visited[i] == false && key[i] < min_cost) { min_cost = key[i]; @@ -60,7 +60,7 @@ void minSpanningTree(int graph[][V], int parent[V]) { } visited[min_index] = true; - for (int v = 0; v < V; v++) { + for (int v = 0; v < VERTICES; v++) { if (graph[min_index][v] && visited[v] == false && graph[min_index][v] < key[v]) { parent[v] = min_index; key[v] = graph[min_index][v]; @@ -70,10 +70,10 @@ void minSpanningTree(int graph[][V], int parent[V]) { } void initializeMinSpanningTree() { - int MAX_EDGES = V * (V - 1) / 2; + int MAX_EDGES = VERTICES * (VERTICES - 1) / 2; for (int i = 0; i < MAX_EDGES; i++) { - int u = rand() % V; - int v = rand() % V; + int u = rand() % VERTICES; + int v = rand() % VERTICES; int d = rand() % 1000; input[u][v] = d; } @@ -99,7 +99,7 @@ void generateResultMinSpanningTree() { minSpanningTree(input, output); - for (int i = 0; i < V; i++) { + for (int i = 0; i < VERTICES; i++) { std::cout << "p[" << i << "] = " << output[i] << ", "; } std::cout << "\nMinimum Spanning Tree operation finished!\n";