Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Eigen3 as an optional alternative to Lapack #51

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .gitmodules
Empty file.
7 changes: 6 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ install:
script:
- source activate testenv
- nosetests --with-coverage --cover-package=prox_tv
- bash -x ./.travis/deploy.sh
# - bash -x ./.travis/deploy.sh
# Build C lib with CMake
- mkdir -p build && cd build
- cmake -DENABLE_TESTING:BOOL=ON ../
- cmake --build .
- ctest -VV
after_success:
- source activate testenv
- coveralls
Expand Down
1 change: 1 addition & 0 deletions .travis/installconda.sh
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export PATH="$HOME/miniconda3/bin:$PATH"
rm miniconda.sh
conda config --set always_yes yes --set changeps1 no
conda update -q conda
pip install cmake

# Create environment with specific python version
conda create -n testenv python=${TRAVIS_PYTHON_VERSION}
Expand Down
147 changes: 147 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
cmake_minimum_required(VERSION 3.12)

project(proxTV
VERSION 3.2.1
DESCRIPTION "Toolbox for fast Total Variation proximity operators"
)
message(STATUS "Configuring ${PROJECT_NAME}")
message(STATUS " version: ${proxTV_VERSION}")
message(STATUS " description: ${proxTV_DESCRIPTION}")

# Update CMake module path to lookup proxTV custom CMake modules
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/cmake)

# Add -fPIC
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

#------------------------------------------------------------------------------
if(NOT DEFINED proxTV_INSTALL_DEVELOPMENT)
option(proxTV_INSTALL_DEVELOPMENT "Install development files" ON)
endif()
if(NOT DEFINED proxTV_ENABLE_TESTING)
option(proxTV_ENABLE_TESTING "Compile tests" OFF)
endif()
if(NOT DEFINED proxTV_USE_LAPACK)
option(proxTV_USE_LAPACK "Use LAPACK and LAPACKE instead of EIGEN" ON)
endif()

#------------------------------------------------------------------------------
# Set a default build type if none was specified
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to 'Release' as none was specified.")
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE)
mark_as_advanced(CMAKE_BUILD_TYPE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

#------------------------------------------------------------------------------
# Install directories
if(NOT DEFINED proxTV_INSTALL_BIN_DIR)
set(proxTV_INSTALL_BIN_DIR bin)
endif()
if(NOT DEFINED proxTV_INSTALL_LIB_DIR)
set(proxTV_INSTALL_LIB_DIR lib)
endif()
if(NOT DEFINED proxTV_INSTALL_INCLUDE_DIR)
set(proxTV_INSTALL_INCLUDE_DIR include)
endif()
if(NOT DEFINED proxTV_INSTALL_CMAKE_DIR)
set(proxTV_INSTALL_CMAKE_DIR ${proxTV_INSTALL_LIB_DIR}/cmake/proxTV)
endif()

message(STATUS "proxTV_INSTALL_INCLUDE_DIR: ${proxTV_INSTALL_INCLUDE_DIR}")
message(STATUS "proxTV_INSTALL_LIB_DIR: ${proxTV_INSTALL_LIB_DIR}")
message(STATUS "proxTV_INSTALL_CMAKE_DIR: ${proxTV_INSTALL_CMAKE_DIR}")
#------------------------------------------------------------------------------
# External dependencies

if(proxTV_USE_LAPACK)
find_package(LAPACKE REQUIRED)
message(STATUS "Lapacke libraries: ${LAPACKE_LIBRARIES}")

find_package(LAPACK REQUIRED)
message(STATUS "Lapack libraries: ${LAPACK_LIBRARIES}")
else()
# No need to find Eigen3 if the Eigen3 target exists already.
# This happens when a project is fetching Eigen before fetching proxTV with add_subdirectory
# Particularly, this allows to build the module inside ITK when Module_TotalVariation is ON
if(NOT TARGET Eigen3::Eigen3)
find_package(Eigen3 REQUIRED)
endif()
get_target_property(EIGEN_INCLUDE_DIR Eigen3::Eigen
INTERFACE_INCLUDE_DIRECTORIES)
message(STATUS "Eigen Found: ${EIGEN_INCLUDE_DIR}")
endif()

set(THREADS_PREFER_PTHREAD_FLAG 1)
find_package(Threads)

find_package(OpenMP)
message(STATUS "OpenMP found: ${OpenMP_FOUND}")

#------------------------------------------------------------------------------
# Add libraries

add_subdirectory(src)

#------------------------------------------------------------------------------
# Testing
if(proxTV_ENABLE_TESTING)
enable_testing()
add_subdirectory(test)
endif()

#------------------------------------------------------------------------------
# Configure proxTVConfigVersion.cmake common to build and install tree
include(CMakePackageConfigHelpers)
set(config_version_file "${proxTV_BINARY_DIR}/proxTVConfigVersion.cmake")
write_basic_package_version_file(${config_version_file}
VERSION ${proxTV_VERSION}
COMPATIBILITY SameMajorVersion
)

#------------------------------------------------------------------------------
# Export 'proxTVTargets.cmake' for a build tree
export(TARGETS proxTV
FILE ${PROJECT_BINARY_DIR}/proxTVTargets.cmake
NAMESPACE proxTV::
)

# Configure 'proxTVConfig.cmake' for a build tree
include(CMakePackageConfigHelpers)
set(build_config ${PROJECT_BINARY_DIR}/proxTVConfig.cmake)
configure_package_config_file(
cmake/proxTVConfig.cmake.in
${build_config}
INSTALL_DESTINATION ${PROJECT_BINARY_DIR}
INSTALL_PREFIX ${PROJECT_BINARY_DIR}
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)

#------------------------------------------------------------------------------
# Configure 'proxTVConfig.cmake' for an install tree
if(proxTV_INSTALL_DEVELOPMENT)
set(install_config ${PROJECT_BINARY_DIR}/CMakeFiles/proxTVConfig.cmake)
configure_package_config_file(
cmake/proxTVConfig.cmake.in
${install_config}
INSTALL_DESTINATION ${proxTV_INSTALL_CMAKE_DIR}
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)

# Install 'proxTVTargets.cmake'
install(EXPORT proxTVTargets
FILE proxTVTargets.cmake
NAMESPACE proxTV::
DESTINATION ${proxTV_INSTALL_CMAKE_DIR}
COMPONENT Development
)

# Install config files
install(
FILES ${config_version_file} ${install_config}
DESTINATION ${proxTV_INSTALL_CMAKE_DIR}
COMPONENT Development
)
endif()
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,33 @@ More technically, the library provides efficient solvers for the following Total
| Anisotropic Total Variation on a 3-dimensional signal (video denoising) | ![alt tag](docs/img/TV3D.png) |
| Generalized N-dimensional Anisotropic Total Variation (tensor denoising) | ![alt tag](docs/img/TVND.png), with X(di) every possible 1-dimensional slice of X following dimension di.|

## C interface

You can generate a **c** static or dynamic library using **cmake**. If `libproxTV` is not provided by your package-manager, install it from source:

mkdir proxTV-dev ; cd proxTV-dev
git clone https://github.com/albarji/proxTV proxTV
mkdir build ; cd build
cmake ../proxTV
make -j4
make install

The required dependencies are `lapack` and `lapacke`, the c-interface for `lapack`, and optionally, but recommended: `OpenMP` with `pthreads` for multi-threading support.

You can provide extra options to `cmake` via the command line or a gui (i.e `ccmake`).

cmake ../proxTV -DBUILD_SHARED_LIBS:BOOL=ON -DCMAKE_INSTALL_PREFIX=/opt/ -DENABLE_TESTING:BOOL=ON

To use proxTV in your `cmake` project just write in your `CMakeLists.txt`:

find_package(proxTV)
add_executable(foo main.cpp)
target_link_libraries(foo PUBLIC proxTV::proxTV)

That will propagate all the dependencies of proxTV to your target. If you haven't installed proxTV in a system folder, you have to point to the installation directory when configuring your project with `cmake`.

cmake /path/my_project_source_folder -DproxTV_DIR:PATH="/proxTV_install_folder/lib/cmake/proxTV"

## Python interface

### Install
Expand Down
190 changes: 190 additions & 0 deletions cmake/FindLAPACKE.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
#.rst:
# FindLAPACKE
# -------------
#
# Find the LAPACKE library
#
# Using LAPACKE:
#
# ::
#
# find_package(LAPACKE REQUIRED)
# include_directories(${LAPACKE_INCLUDE_DIRS})
# add_executable(foo foo.cc)
# target_link_libraries(foo ${LAPACKE_LIBRARIES})
#
# This module sets the following variables:
#
# ::
#
# LAPACKE_FOUND - set to true if the library is found
# LAPACKE_INCLUDE_DIRS - list of required include directories
# LAPACKE_LIBRARIES - list of libraries to be linked
# LAPACKE_VERSION_MAJOR - major version number
# LAPACKE_VERSION_MINOR - minor version number
# LAPACKE_VERSION_PATCH - patch version number
# LAPACKE_VERSION_STRING - version number as a string (ex: "0.2.18")

#=============================================================================
# Copyright 2016 Hans J. Johnson <hans-johnson@uiowa.edu>
#
# Distributed under the OSI-approved BSD License (the "License")
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#=============================================================================
#
set(LAPACKE_SEARCH_PATHS
${LAPACKE_DIR}
$ENV{LAPACKE_DIR}
$ENV{CMAKE_PREFIX_PATH}
${CMAKE_PREFIX_PATH}
/usr
/usr/local
/usr/local/opt/lapack ## Mac Homebrew install path
/opt/LAPACKE
)
message(STATUS "LAPACKE_SEARCH_PATHS: ${LAPACKE_SEARCH_PATHS}")

set(CMAKE_PREFIX_PATH ${LAPACKE_SEARCH_PATHS})
list(REMOVE_DUPLICATES CMAKE_PREFIX_PATH)

## First try to find LAPACKE with NO_MODULE,
## As of 20160706 version 0.2.18 there is limited cmake support for LAPACKE
## that is not as complete as this version, if found, use it
## to identify the LAPACKE_VERSION_STRING and improve searching.
find_package(LAPACKE NO_MODULE QUIET)
if(LAPACKE_FOUND)
if(EXISTS ${LAPACKE_DIR}/lapacke-config-version.cmake)
include(${LAPACKE_DIR}/lapacke-config-version.cmake)
set(LAPACKE_VERSION_STRING ${PACKAGE_VERSION})
unset(PACKAGE_VERSION) # Use cmake conventional naming
endif()
find_package(LAPACK NO_MODULE QUIET) #Require matching versions here!
find_package(BLAS NO_MODULE QUIET) #Require matching versions here!
endif()

##################################################################################################
### First search for headers
find_path(LAPACKE_CBLAS_INCLUDE_DIR
NAMES cblas.h
PATHS ${LAPACKE_SEARCH_PATHS}
PATH_SUFFIXES include include/lapack)
find_path(LAPACKE_LAPACKE_INCLUDE_DIR
NAMES lapacke.h
PATHS ${LAPACKE_SEARCH_PATHS}
PATH_SUFFIXES include)

##################################################################################################
### Second, search for libraries
set(PATH_SUFFIXES_LIST
lib64
lib
)
find_library(LAPACKE_LIB
NAMES lapacke
PATHS ${LAPACKE_SEARCH_PATHS}
PATH_SUFFIXES ${PATH_SUFFIXES_LIST})
find_library(CBLAS_LIB
NAMES cblas
PATHS ${LAPACKE_SEARCH_PATHS}
PATH_SUFFIXES ${PATH_SUFFIXES_LIST})
find_library(LAPACK_LIB
NAMES lapack
PATHS ${LAPACKE_SEARCH_PATHS}
PATH_SUFFIXES ${PATH_SUFFIXES_LIST})
find_library(BLAS_LIB
NAMES blas
PATHS ${LAPACKE_SEARCH_PATHS}
PATH_SUFFIXES ${PATH_SUFFIXES_LIST})

## TODO: Get version components
# ------------------------------------------------------------------------
# Extract version information
# ------------------------------------------------------------------------

# WARNING: We may not be able to determine the version of some LAPACKE
set(LAPACKE_VERSION_MAJOR 0)
set(LAPACKE_VERSION_MINOR 0)
set(LAPACKE_VERSION_PATCH 0)
if(LAPACKE_VERSION_STRING)
string(REGEX REPLACE "([0-9]+).([0-9]+).([0-9]+)" "\\1" LAPACKE_VERSION_MAJOR "${LAPACKE_VERSION_STRING}")
string(REGEX REPLACE "([0-9]+).([0-9]+).([0-9]+)" "\\2" LAPACKE_VERSION_MINOR "${LAPACKE_VERSION_STRING}")
string(REGEX REPLACE "([0-9]+).([0-9]+).([0-9]+)" "\\3" LAPACKE_VERSION_PATCH "${LAPACKE_VERSION_STRING}")
endif()

#======================
# Checks 'REQUIRED', 'QUIET' and versions.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LAPACKE FOUND_VAR LAPACKE_FOUND
REQUIRED_VARS LAPACKE_CBLAS_INCLUDE_DIR
LAPACKE_LAPACKE_INCLUDE_DIR
LAPACKE_LIB
LAPACK_LIB
CBLAS_LIB
BLAS_LIB
VERSION_VAR LAPACKE_VERSION_STRING
)

if (LAPACKE_FOUND)
set(LAPACKE_INCLUDE_DIRS ${LAPACKE_CBLAS_INCLUDE_DIR} ${LAPACKE_CBLAS_INCLUDE_DIR})
list(REMOVE_DUPLICATES LAPACKE_INCLUDE_DIRS)
if("${CMAKE_C_COMPILER_ID}" MATCHES ".*Clang.*" OR
"${CMAKE_C_COMPILER_ID}" MATCHES ".*GNU.*" OR
"${CMAKE_C_COMPILER_ID}" MATCHES ".*Intel.*"
) #NOT MSVC
set(MATH_LIB m)
endif()
list(APPEND LAPACKE_LIBRARIES ${LAPACKE_LIB} ${LAPACK_LIB} ${BLAS_LIB} ${CBLAS_LIB})
# Check for a common combination, and find required gfortran support libraries

if(1)
if("${CMAKE_C_COMPILER_ID}" MATCHES ".*Clang.*" AND "${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")
message(STATUS "\n\n WARNING: ${CMAKE_C_COMPILER} identified as ${CMAKE_C_COMPILER_ID}\n"
"AND: ${CMAKE_Fortran_COMPILER} identified as ${CMAKE_Fortran_COMPILER_ID}\n"
"\n"
"may be require special configurations. The most common is the need to"
"explicitly link C programs against the gfortran support library.")

endif()
else()
## This code automated code is hard to determine if it is robust in many different environments.
# Check for a common combination, and find required gfortran support libraries
if("${CMAKE_C_COMPILER_ID}" MATCHES ".*Clang.*" AND "${CMAKE_Fortran_COMPILER_ID}" MATCHES "GNU")
include(FortranCInterface)
FortranCInterface_VERIFY()
if(NOT FortranCInterface_VERIFIED_C)
message(FATAL_ERROR "C and fortran compilers are not compatible:\n${CMAKE_Fortran_COMPILER}:${CMAKE_C_COMPILER}")
endif()

execute_process(COMMAND ${CMAKE_Fortran_COMPILER} -print-file-name=libgfortran.a OUTPUT_VARIABLE FORTRANSUPPORTLIB ERROR_QUIET)
string(STRIP ${FORTRANSUPPORTLIB} FORTRANSUPPORTLIB)
if(EXISTS "${FORTRANSUPPORTLIB}")
list(APPEND LAPACKE_LIBRARIES ${FORTRANSUPPORTLIB})
message(STATUS "Appending fortran support lib: ${FORTRANSUPPORTLIB}")
else()
message(FATAL_ERROR "COULD NOT FIND libgfortran.a support library:${FORTRANSUPPORTLIB}:")
endif()
endif()
endif()
list(APPEND LAPACKE_LIBRARIES ${MATH_LIB})
endif()

mark_as_advanced(
LAPACKE_FOUND
LAPACKE_INCLUDE_DIRS
LAPACKE_LIBRARIES
LAPACKE_VERSION_MAJOR
LAPACKE_VERSION_MINOR
LAPACKE_VERSION_PATCH
LAPACKE_VERSION_STRING
)

## For debugging
message(STATUS "LAPACKE_FOUND :${LAPACKE_FOUND}: - set to true if the library is found")
message(STATUS "LAPACKE_INCLUDE_DIRS :${LAPACKE_INCLUDE_DIRS}: - list of required include directories")
message(STATUS "LAPACKE_LIBRARIES :${LAPACKE_LIBRARIES}: - list of libraries to be linked")
message(STATUS "LAPACKE_VERSION_MAJOR :${LAPACKE_VERSION_MAJOR}: - major version number")
message(STATUS "LAPACKE_VERSION_MINOR :${LAPACKE_VERSION_MINOR}: - minor version number")
message(STATUS "LAPACKE_VERSION_PATCH :${LAPACKE_VERSION_PATCH}: - patch version number")
message(STATUS "LAPACKE_VERSION_STRING :${LAPACKE_VERSION_STRING}: - version number as a string")
Loading