Skip to content

Commit dba9fa8

Browse files
init
0 parents  commit dba9fa8

26 files changed

Lines changed: 2397 additions & 0 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
build/
2+
examples/*.perm

CMakeLists.txt

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
cmake_minimum_required(VERSION 3.22)
2+
project(ParAMD VERSION 1.0 LANGUAGES C CXX)
3+
4+
# Default to Release build
5+
if(NOT CMAKE_BUILD_TYPE)
6+
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
7+
endif()
8+
9+
# Set C++ standard
10+
set(CMAKE_CXX_STANDARD 17)
11+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
12+
13+
# Set the installation path SuiteSparse is installed
14+
set(SUITESPARSE_ROOT "" CACHE PATH "Path to the SuiteSparse installation")
15+
16+
# Add preprocessor macro if SuiteSparse is installed
17+
if (SUITESPARSE_ROOT)
18+
message(STATUS "SuiteSparse root directory: ${SUITESPARSE_ROOT}")
19+
20+
# Define a preprocessor macro USE_SUITESPARSE to indicate that SuiteSparse is being used
21+
add_definitions(-DUSE_SUITESPARSE)
22+
23+
# Set SuiteSparse include and library paths based on SUITESPARSE_ROOT
24+
set(SUITESPARSE_INCLUDE_DIR "${SUITESPARSE_ROOT}/include")
25+
set(SUITESPARSE_LIB_DIR_64 "${SUITESPARSE_ROOT}/lib64")
26+
set(SUITESPARSE_LIB_DIR "${SUITESPARSE_ROOT}/lib")
27+
28+
29+
# Check that the necessary directories exist
30+
if (NOT EXISTS "${SUITESPARSE_INCLUDE_DIR}/suitesparse/amd.h")
31+
message(FATAL_ERROR "SuiteSparse AMD (suitesparse/amd.h) not found!")
32+
endif()
33+
34+
if (NOT EXISTS "${SUITESPARSE_LIB_DIR_64}/libamd.so" AND NOT EXISTS "${SUITESPARSE_LIB_DIR_64}/libamd.a")
35+
if (NOT EXISTS "${SUITESPARSE_LIB_DIR}/libamd.so" AND NOT EXISTS "${SUITESPARSE_LIB_DIR}/libamd.a")
36+
message(FATAL_ERROR "SuiteSparse library (libamd) not found!")
37+
endif()
38+
endif()
39+
40+
# Find the SuiteSparse AMD library
41+
find_library(SUITESPARSE_AMD_LIB NAMES amd
42+
PATHS ${SUITESPARSE_LIB_DIR_64} ${SUITESPARSE_LIB_DIR}
43+
NO_DEFAULT_PATH
44+
)
45+
46+
if (NOT SUITESPARSE_AMD_LIB)
47+
message(FATAL_ERROR "Could not find SuiteSparse AMD library!")
48+
endif()
49+
50+
# Include the SuiteSparse headers
51+
include_directories(${SUITESPARSE_INCLUDE_DIR})
52+
53+
else()
54+
message(STATUS "SUITESPARSE_ROOT not specified, SuiteSparse will not be used.")
55+
endif()
56+
57+
include_directories(include)
58+
59+
set(SOURCES
60+
src/config.cpp
61+
src/matrix.cpp
62+
src/paramd.cpp
63+
src/utils.cpp
64+
)
65+
66+
add_library(paramd_lib SHARED ${SOURCES})
67+
68+
set_target_properties(paramd_lib PROPERTIES
69+
OUTPUT_NAME paramd
70+
VERSION ${PROJECT_VERSION}
71+
SOVERSION 1
72+
PUBLIC_HEADER include/paramd/paramd.h
73+
)
74+
75+
add_executable(paramd bin/main.cpp)
76+
77+
target_link_libraries(paramd PRIVATE paramd_lib)
78+
79+
if (SUITESPARSE_AMD_LIB)
80+
target_link_libraries(paramd PRIVATE ${SUITESPARSE_AMD_LIB})
81+
endif()
82+
83+
find_package(OpenMP REQUIRED)
84+
if(OpenMP_CXX_FOUND)
85+
target_link_libraries(paramd_lib PRIVATE OpenMP::OpenMP_CXX)
86+
target_link_libraries(paramd PRIVATE OpenMP::OpenMP_CXX)
87+
endif()
88+
89+
install(TARGETS paramd_lib
90+
LIBRARY DESTINATION lib
91+
PUBLIC_HEADER DESTINATION include/paramd
92+
)
93+
94+
install(TARGETS paramd
95+
RUNTIME DESTINATION bin
96+
)

LICENSE

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
BSD 3-Clause License
2+
3+
Copyright (c) 2025, The Regents of the University of California, through Lawrence Berkeley National Laboratory (subject to receipt of any required approvals from the U.S. Dept. of Energy). All rights reserved.
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
1. Redistributions of source code must retain the above copyright notice, this
9+
list of conditions and the following disclaimer.
10+
11+
2. Redistributions in binary form must reproduce the above copyright notice,
12+
this list of conditions and the following disclaimer in the documentation
13+
and/or other materials provided with the distribution.
14+
15+
3. Neither the name of the copyright holder nor the names of its
16+
contributors may be used to endorse or promote products derived from
17+
this software without specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

README.md

Lines changed: 267 additions & 0 deletions
Large diffs are not rendered by default.

bin/main.cpp

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
#include <chrono>
2+
#include <iostream>
3+
#include <omp.h>
4+
#include <string>
5+
6+
#ifdef USE_SUITESPARSE
7+
#include "suitesparse/amd.h"
8+
#endif
9+
10+
#include "paramd/paramd.h"
11+
12+
// Display help information
13+
static void show_help() {
14+
std::cout << "Usage: paramd [OPTIONS]\n"
15+
<< "Options:\n"
16+
<< " -h, --help Show this help message\n"
17+
<< " --matrix <path> Path to the input matrix in mtx format (required)\n"
18+
<< " --algo <paramd, amd (if available)> Algorithm to benchmark (default: paramd) \n"
19+
<< " --mult <double> Multiplicative relaxation factor (default: 1.1)\n"
20+
<< " --lim <double> Limitation factor (default: 8192), will be divided by #threads\n"
21+
<< " --mem <double> Extra memory factor (default: 1.5)\n"
22+
<< " --seed <64-bit integer> Seed used to randomly permute the matrix (default: 1)\n"
23+
<< " --breakdown Enable time breakdown (default: false)\n"
24+
<< " --stat Enable statistics (default: false)\n"
25+
<< " --sym Specify sym if the matrix is known to be symmetric (default: false)\n";
26+
}
27+
28+
int main(int argc, char* argv[]) {
29+
paramd::config config;
30+
std::string matrix = "", algo = "paramd";
31+
32+
// Parse arguments
33+
for (int i = 1; i < argc; i++) {
34+
std::string arg = argv[i];
35+
if (arg == "-h" || arg == "--help") {
36+
show_help();
37+
return 0;
38+
} else if (arg == "--matrix" && i + 1 < argc) {
39+
matrix = std::string(argv[++i]);
40+
} else if (arg == "--algo" && i + 1 < argc) {
41+
algo = std::string(argv[++i]);
42+
if (algo != "amd" && algo != "paramd") {
43+
std::cerr << algo << " is not in the algo list!" << std::endl;
44+
show_help();
45+
exit(1);
46+
}
47+
} else if (arg == "--mult" && i + 1 < argc) {
48+
config.mult = std::stod(argv[++i]);
49+
} else if (arg == "--lim" && i + 1 < argc) {
50+
config.lim = std::stod(argv[++i]);
51+
} else if (arg == "--mem" && i + 1 < argc) {
52+
config.mem = std::stod(argv[++i]);
53+
} else if (arg == "--seed" && i + 1 < argc) {
54+
config.seed = std::stoull(argv[++i]);
55+
} else if (arg == "--breakdown") {
56+
config.breakdown = true;
57+
} else if (arg == "--stat") {
58+
config.stat = true;
59+
} else if (arg == "--sym") {
60+
config.sym = true;
61+
} else {
62+
std::cerr << "Unknown option: " << arg << std::endl;
63+
show_help();
64+
exit(1);
65+
}
66+
}
67+
68+
if (matrix == "") {
69+
std::cerr << "Please specify the input matrix!" << std::endl;
70+
show_help();
71+
exit(1);
72+
}
73+
74+
std::cout << "Reading matrix market file: " << matrix << std::endl;
75+
paramd::matrix A(matrix);
76+
77+
std::cout << "Applying random inverse permutation with seed: " << config.seed << std::endl;
78+
std::vector<paramd::vtype> rand_iperm = paramd::random_inverse_permutation(A.n, config.seed);
79+
A.apply_inverse_permutation(rand_iperm);
80+
std::vector<paramd::vtype> perm(A.n);
81+
82+
std::cout << "Ordering using algorithm: " << algo << std::endl;
83+
84+
uint64_t fill = 0;
85+
double start = 0, end = 0;
86+
87+
if (algo == "paramd") {
88+
start = omp_get_wtime();
89+
fill = paramd::paramd(A.n, A.rowptr.data(), A.colidx.data(), perm.data(), config);
90+
end = omp_get_wtime();
91+
} else {
92+
#ifdef USE_SUITESPARSE
93+
double info[AMD_INFO];
94+
start = omp_get_wtime();
95+
amd_order(A.n, A.rowptr.data(), A.colidx.data(), perm.data(), NULL, info);
96+
end = omp_get_wtime();
97+
if (info[AMD_STATUS] != AMD_OK) {
98+
std::cout << "AMD returns errors. Fall back to 64-bit mode" << std::endl;
99+
int64_t n64 = A.n;
100+
std::vector<int64_t> rowptr64(A.rowptr.size());
101+
std::vector<int64_t> colidx64(A.colidx.size());
102+
std::vector<int64_t> perm64(perm.size());
103+
#pragma omp parallel for
104+
for (size_t i = 0; i < rowptr64.size(); ++i)
105+
rowptr64[i] = A.rowptr[i];
106+
#pragma omp parallel for
107+
for (size_t i = 0; i < colidx64.size(); ++i)
108+
colidx64[i] = A.colidx[i];
109+
std::cout << "Ordering using algorithm: amd_l" << std::endl;
110+
start = omp_get_wtime();
111+
amd_l_order(n64, rowptr64.data(), colidx64.data(), perm64.data(), NULL, info);
112+
end = omp_get_wtime();
113+
if (info[AMD_STATUS] != AMD_OK) {
114+
std::cerr << "AMD returns error code: " << info[AMD_STATUS] << std::endl;
115+
exit(1);
116+
}
117+
#pragma omp parallel for
118+
for (size_t i = 0; i < A.n; ++i)
119+
perm[i] = perm64[i];
120+
}
121+
fill = uint64_t(info[AMD_LNZ]);
122+
#else
123+
std::cerr << "AMD not found. Please specify the AMD installation path via CMake!" << std::endl;
124+
exit(1);
125+
#endif
126+
}
127+
128+
std::cout << "#Fill = " << fill << std::endl;
129+
std::cout << "Ordering Time = " << end - start << " seconds" << std::endl;
130+
std::cout << "Reverting random inverse permutation with seed: " << config.seed << std::endl;
131+
std::vector<paramd::vtype> rand_perm = paramd::inverse_permutation(rand_iperm);
132+
perm = paramd::apply_function(perm, rand_perm);
133+
std::string out_perm_fp = matrix + ".perm";
134+
std::cout << "Writing permutation to: " << out_perm_fp << std::endl;
135+
paramd::write_perm(out_perm_fp, perm);
136+
137+
return 0;
138+
}

environment.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name: paramd-benchmarks
2+
channels:
3+
- conda-forge
4+
dependencies:
5+
- cmake>=3.22
6+
- python>=3.13
7+
- matplotlib>=3.10.1
8+
- numpy>=2.2.5
9+
- pandas>=2.2.3
10+
- seaborn>=0.13.2

examples/dumbbell.mtx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
%%MatrixMarket matrix coordinate real symmetric
2+
10 10 25
3+
1 1 4
4+
2 1 -1
5+
3 1 -1
6+
4 1 -1
7+
2 2 4
8+
3 2 -1
9+
4 2 -1
10+
3 3 4
11+
4 3 -1
12+
4 4 5
13+
5 4 -1
14+
5 5 3
15+
6 5 -1
16+
6 6 3
17+
7 6 -1
18+
7 7 5
19+
8 7 -1
20+
9 7 -1
21+
10 7 -1
22+
8 8 4
23+
9 8 -1
24+
10 8 -1
25+
9 9 4
26+
10 9 -1
27+
10 10 4

examples/test.mtx

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
%%MatrixMarket matrix coordinate real general
2+
10 10 46
3+
1 1 3
4+
4 1 -1
5+
6 1 -1
6+
2 2 4
7+
5 2 -1
8+
6 2 -1
9+
9 2 -1
10+
3 3 4
11+
5 3 -1
12+
6 3 -1
13+
7 3 -1
14+
1 4 -1
15+
4 4 4
16+
7 4 -1
17+
8 4 -1
18+
2 5 -1
19+
3 5 -1
20+
5 5 5
21+
7 5 -1
22+
9 5 -1
23+
1 6 -1
24+
2 6 -1
25+
3 6 -1
26+
6 6 4
27+
3 7 -1
28+
4 7 -1
29+
5 7 -1
30+
7 7 7
31+
8 7 -1
32+
9 7 -1
33+
10 7 -1
34+
4 8 -1
35+
7 8 -1
36+
8 8 5
37+
9 8 -1
38+
10 8 -1
39+
2 9 -1
40+
5 9 -1
41+
7 9 -1
42+
8 9 -1
43+
9 9 5
44+
10 9 -1
45+
7 10 -1
46+
8 10 -1
47+
9 10 -1
48+
10 10 5

0 commit comments

Comments
 (0)