From 58bc588c1994a07379c1bc5d68c233533c4c3e6d Mon Sep 17 00:00:00 2001 From: Alinson Xavier Date: Fri, 11 Aug 2017 11:39:49 -0400 Subject: [PATCH] Add linear algebra file --- CMakeLists.txt | 2 + cmake/FindLAPACKE.cmake | 11 ++++ multirow/CMakeLists.txt | 60 ++++++++++++--------- multirow/include/multirow/linalg.h | 40 ++++++++++++++ multirow/src/linalg.c | 53 +++++++++++++++++++ multirow/tests/linalg-test.cpp | 83 ++++++++++++++++++++++++++++++ 6 files changed, 224 insertions(+), 25 deletions(-) create mode 100644 cmake/FindLAPACKE.cmake create mode 100644 multirow/include/multirow/linalg.h create mode 100644 multirow/src/linalg.c create mode 100644 multirow/tests/linalg-test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 09908e4..043c180 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,8 @@ include_directories(${CPLEX_INCLUDE_DIR}) find_package(GMP REQUIRED) find_package(OpenMP REQUIRED) +find_package(BLAS REQUIRED) +find_package(LAPACKE REQUIRED) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror ${OpenMP_CXX_FLAGS} -O3") diff --git a/cmake/FindLAPACKE.cmake b/cmake/FindLAPACKE.cmake new file mode 100644 index 0000000..4e827cd --- /dev/null +++ b/cmake/FindLAPACKE.cmake @@ -0,0 +1,11 @@ +find_library(LAPACKE_LIBRARIES + NAMES lapacke) + +find_path(LAPACKE_INCLUDE_DIR NAMES lapacke.h) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LAPACKE + DEFAULT_MSG + LAPACKE_LIBRARIES + LAPACKE_INCLUDE_DIR) +mark_as_advanced(LAPACKE_LIBRARIES LAPACKE_INCLUDE_DIR) diff --git a/multirow/CMakeLists.txt b/multirow/CMakeLists.txt index ff7a311..d7314ea 100644 --- a/multirow/CMakeLists.txt +++ b/multirow/CMakeLists.txt @@ -1,33 +1,43 @@ set(COMMON_SOURCES - src/cg.c - src/double.c - src/geometry.c - src/lfree2d.c - src/lp.c - src/mir.c - src/util.c - src/rational.c - src/stats.c - include/multirow/cg.h - include/multirow/double.h - include/multirow/geometry.h - include/multirow/lfree2d.h - include/multirow/lp.h - include/multirow/mir.h - include/multirow/rational.h - include/multirow/stats.h - include/multirow/params.h - include/multirow/util.h) + src/cg.c + src/double.c + src/geometry.c + src/lfree2d.c + src/lp.c + src/mir.c + src/util.c + src/rational.c + src/stats.c + src/linalg.c + include/multirow/cg.h + include/multirow/double.h + include/multirow/geometry.h + include/multirow/lfree2d.h + include/multirow/lp.h + include/multirow/mir.h + include/multirow/rational.h + include/multirow/stats.h + include/multirow/params.h + include/multirow/util.h + include/multirow/linalg.h) set(TEST_SOURCES - tests/double-test.cpp - tests/cg-test.cpp - tests/geometry-test.cpp) + tests/double-test.cpp + tests/cg-test.cpp + tests/geometry-test.cpp + tests/linalg-test.cpp) add_library(multirow_static ${COMMON_SOURCES}) set_target_properties(multirow_static PROPERTIES OUTPUT_NAME lifting) -target_link_libraries(multirow_static ${CPLEX_LIBRARIES}) -target_include_directories (multirow_static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(multirow_static + ${CPLEX_LIBRARIES} + ${BLAS_LIBRARIES} + ${LAPACKE_LIBRARIES}) +target_include_directories(multirow_static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) add_executable(multirow-test.run ${COMMON_SOURCES} ${TEST_SOURCES}) -target_link_libraries(multirow-test.run ${CPLEX_LIBRARIES} gtest_main) +target_link_libraries(multirow-test.run + ${CPLEX_LIBRARIES} + ${BLAS_LIBRARIES} + ${LAPACKE_LIBRARIES} + gtest_main) diff --git a/multirow/include/multirow/linalg.h b/multirow/include/multirow/linalg.h new file mode 100644 index 0000000..142aca8 --- /dev/null +++ b/multirow/include/multirow/linalg.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2015-2017 Alinson Xavier + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +/** + * Receives an n-dimensional vector x, a scalar alpha and sets x <- alpha * x + */ +void LINALG_scale(int n, double *x, double alpha); + +/** + * Receives two n-dimensional vectors x and y and returns the dot product of x + * and y. + */ +double LINALG_dot(int n, double *x, double *y); + +/** + * Receives an n-dimensional vector x and returns the 1-norm of x. + */ +double LINALG_norm(int n, double *x); + +/** + * Given an invertible n-by-n matrix A and an n-dimensional vector b, this + * function set x to A^(-1) b. Returns zero if the operation is successful and + * non-zero otherwise. + */ +int LINALG_solve(int n, double *A, double *b, double *x); \ No newline at end of file diff --git a/multirow/src/linalg.c b/multirow/src/linalg.c new file mode 100644 index 0000000..21b34ee --- /dev/null +++ b/multirow/src/linalg.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include +#include +#include + +void LINALG_scale(int n, double *x, double alpha) +{ + cblas_dscal(n, alpha, x, 1); +} + +double LINALG_dot(int n, double *x, double *y) +{ + return cblas_ddot(n, x, 1, y, 1); +} + +double LINALG_norm(int n, double *x) +{ + return cblas_dasum(n, x, 1); +} + +int LINALG_solve(int n, double *A, double *b, double *x) +{ + int rval = 0; + int ignored[n]; + double A_copy[n * n]; + + memcpy(x, b, n * sizeof(double)); + memcpy(A_copy, A, n * n * sizeof(double)); + + rval = LAPACKE_dgesv(LAPACK_ROW_MAJOR, n, 1, A_copy, n, ignored, x, 1); + abort_if(rval, "LAPACKE_dgesv failed"); + +CLEANUP: + return rval; +} \ No newline at end of file diff --git a/multirow/tests/linalg-test.cpp b/multirow/tests/linalg-test.cpp new file mode 100644 index 0000000..2ddafec --- /dev/null +++ b/multirow/tests/linalg-test.cpp @@ -0,0 +1,83 @@ +/* Copyright (c) 2015-2017 Alinson Xavier + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +extern "C" { +#include +#include +} + +const double E = 1e-6; + +TEST(LinAlgTest, scale_test) +{ + double x[] = {1.0, 2.0, 3.0}; + LINALG_scale(3, x, 2.0); + EXPECT_NEAR(x[0], 2.0, E); + EXPECT_NEAR(x[1], 4.0, E); + EXPECT_NEAR(x[2], 6.0, E); +} + +TEST(LinAlgTest, dot_test) +{ + double x[] = { 1.0, 2.0, 3.0 }; + double y[] = { 3.0, 4.0, 5.0 }; + double dot = LINALG_dot(3, x, y); + EXPECT_NEAR(dot, 26.0, E); +} + +TEST(LinAlgTest, norm_test) +{ + double x[] = { 1.0, 2.0, -3.0 }; + double y[] = { 3.0, -4.0, -5.0 }; + double x_norm = LINALG_norm(3, x); + double y_norm = LINALG_norm(3, y); + EXPECT_NEAR(x_norm, 6.0, E); + EXPECT_NEAR(y_norm, 12.0, E); +} + +TEST(LinAlgTest, solve_test) +{ + int rval = 0; + + double A[] = { + 2.0, 1.0, 3.0, + 2.0, 6.0, 8.0, + 6.0, 8.0, 18.0, + }; + double b[] = { 1.0, 3.0, 5.0 }; + double x[] = { 0.0, 0.0, 0.0 }; + + rval = LINALG_solve(3, A, b, x); + abort_if(rval, "LINALG_solve failed"); + + // Should compute x correctly + EXPECT_NEAR(x[0], 0.3, E); + EXPECT_NEAR(x[1], 0.4, E); + EXPECT_NEAR(x[2], 0.0, E); + + // Should not modify A and b + EXPECT_EQ(A[0], 2.0); + EXPECT_EQ(A[1], 1.0); + EXPECT_EQ(A[2], 3.0); + EXPECT_EQ(b[0], 1.0); + EXPECT_EQ(b[1], 3.0); + EXPECT_EQ(b[2], 5.0); + +CLEANUP: + if(rval) FAIL(); +} \ No newline at end of file