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

Adapt virtually everything else in mlpack to header-only #3233

Merged
merged 31 commits into from
Jul 31, 2022
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b892828
Adapt several files to header-only.
rcurtin Jun 20, 2022
19f4b22
Move PrefixedOutStream implementations to be inline.
rcurtin Jun 20, 2022
9208a60
Make program_doc.cpp header-only. (This required a little include ju…
rcurtin Jun 20, 2022
6c6a50b
Adapt log.cpp and io.cpp.
rcurtin Jun 21, 2022
1f732a1
Adapt a last few files to header-only.
rcurtin Jun 21, 2022
1d69d83
Remove unused function: it turned out to be unnecessary.
rcurtin Jun 21, 2022
6a1d77c
singletons.hpp is now inlined in log.hpp.
rcurtin Jun 21, 2022
0af56d2
Propagate MLPACK_TEST_SRCS to the parent directory.
rcurtin Jun 22, 2022
107a985
Adapt include ordering for header-only.
rcurtin Jun 23, 2022
45b9a9a
Add forward declaration of IO.
rcurtin Jun 23, 2022
b9f7c1f
Header include ordering cleanup: fix IO/Timers mutual dependency.
rcurtin Jun 23, 2022
2309727
Add new file to R build.
rcurtin Jun 24, 2022
31e9236
Update src/mlpack/core/util/forward.hpp
rcurtin Jun 27, 2022
c2c898d
Update src/mlpack/core/data/check_categorical_param.hpp
rcurtin Jun 27, 2022
d7e705d
Try a few inclusion changes to make the static analysis checker happier.
rcurtin Jun 27, 2022
fe73ae2
Remove wayward definition.
rcurtin Jun 27, 2022
0c5e001
force_inline -> mlpack_force_inline
rcurtin Jun 27, 2022
33fa901
Oops, missed one.
rcurtin Jun 27, 2022
c02eba2
ANY -> MLPACK_ANY
rcurtin Jun 27, 2022
66923e8
Remove FORCE_CXX11 option (it is assumed that the user has a C++11 co…
rcurtin Jun 27, 2022
2fcec24
Bump standard requirement to C++14.
rcurtin Jun 27, 2022
849aaae
An extra little sanity check.
rcurtin Jun 27, 2022
092c9c9
Use MLPACK_USE_OPENMP instead.
rcurtin Jun 27, 2022
ab73cd6
Merge remote-tracking branch 'origin/master' into util-header-only
rcurtin Jul 7, 2022
707e2b0
Fix typo.
rcurtin Jul 7, 2022
b6b6123
Remove outdated comment.
rcurtin Jul 7, 2022
91b493f
Pass the argument directly to an MLPACK_ANY, instead of wrapping it.
rcurtin Jul 8, 2022
5268f55
Clean up OpenMP detection.
rcurtin Jul 11, 2022
d21439b
Bump minimum requirement for bindings to C++14.
rcurtin Jul 12, 2022
ab7fd48
Some reordering to help the static analysis job (hopefully!).
rcurtin Jul 30, 2022
8e8b7fd
Update standard to C++14.
rcurtin Jul 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 6 additions & 18 deletions CMakeLists.txt
Expand Up @@ -104,13 +104,11 @@ option(BUILD_MARKDOWN_BINDINGS "Build Markdown bindings for website documentatio

option(MATHJAX
"Use MathJax for HTML Doxygen output (disabled by default)." OFF)
option(FORCE_CXX11
"Don't check that the compiler supports C++11, just assume it. Make sure to specify any necessary flag to enable C++11 as part of CXXFLAGS." OFF)
option(USE_OPENMP "If available, use OpenMP for parallelization." ON)
enable_testing()

# Set required standard to C++11.
set(CMAKE_CXX_STANDARD 11)
# Set required standard to C++14.
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Ensure that GCC is new enough, if the compiler is GCC.
Expand Down Expand Up @@ -375,26 +373,16 @@ endif()
set(MLPACK_INCLUDE_DIRS ${MLPACK_INCLUDE_DIRS} ${CEREAL_INCLUDE_DIR})

# Detect OpenMP support in a compiler. If the compiler supports OpenMP, flags
# to compile with OpenMP are returned and added and the HAS_OPENMP definition
# is added for compilation.
#
# This way we can skip calls to functions defined in omp.h with code like:
# #ifdef HAS_OPENMP
# {
# ... openMP code here ...
# }
# #endif
# to compile with OpenMP are returned and added. Note that MSVC does not
# support a new-enough version of OpenMP to be useful.
if (USE_OPENMP)
find_package(OpenMP)
endif ()

if (OPENMP_FOUND)
add_definitions(-DHAS_OPENMP)
if (OpenMP_FOUND AND OpenMP_CXX_VERSION VERSION_GREATER_EQUAL 3.0.0)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}")
if (OpenMP_CXX_FOUND)
set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${OpenMP_CXX_LIBRARIES})
endif ()
set(MLPACK_LIBRARIES ${MLPACK_LIBRARIES} ${OpenMP_CXX_LIBRARIES})
else ()
# Disable warnings for all the unknown OpenMP pragmas.
if (NOT MSVC)
Expand Down
2 changes: 2 additions & 0 deletions HISTORY.md
@@ -1,5 +1,7 @@
### mlpack ?.?.?
###### ????-??-??
* Bump C++ standard requirement to C++14 (#3233).

* Fix `Perceptron` to work with cross-validation framework (#3190).

* Migrate from boost tests to Catch2 framework (#2523), (#2584).
Expand Down
3 changes: 0 additions & 3 deletions doc/guide/build.hpp
Expand Up @@ -199,9 +199,6 @@ The full list of options mlpack allows:
(default ON)
- MATHJAX=(ON/OFF): use MathJax for generated Doxygen documentation (default
OFF)
- FORCE_CXX11=(ON/OFF): assume that the compiler supports C++11 instead of
checking; be sure to specify any necessary flag to enable C++11 as part
of CXXFLAGS (default OFF)
- USE_OPENMP=(ON/OFF): if ON, then use OpenMP if the compiler supports it; if
OFF, OpenMP support is manually disabled (default ON)

Expand Down
32 changes: 14 additions & 18 deletions src/mlpack/CMakeLists.txt
Expand Up @@ -21,24 +21,20 @@ endforeach()
# are set in the root CMakeLists.txt.
add_library(mlpack ${MLPACK_SRCS})

# If we are not forcing C++11 support, check that the compiler supports C++11
# and enable it.
if (NOT FORCE_CXX11)
target_compile_features(mlpack PUBLIC
cxx_decltype
cxx_alias_templates
cxx_auto_type
cxx_lambdas
cxx_constexpr
cxx_rvalue_references
cxx_static_assert
cxx_template_template_parameters
cxx_delegating_constructors
cxx_variadic_templates
cxx_nullptr
cxx_noexcept
)
endif ()
target_compile_features(mlpack PUBLIC
cxx_decltype
cxx_alias_templates
cxx_auto_type
cxx_lambdas
cxx_constexpr
cxx_rvalue_references
cxx_static_assert
cxx_template_template_parameters
cxx_delegating_constructors
cxx_variadic_templates
cxx_nullptr
cxx_noexcept
)

# Generate export symbols for Windows, instead of adding __declspec(dllimport)
# and __declspec(dllexport) everywhere. However, those modifiers are still
Expand Down
111 changes: 111 additions & 0 deletions src/mlpack/base.hpp
@@ -0,0 +1,111 @@
/**
* @file base.hpp
*
* The most basic core includes that mlpack expects; standard C++ includes and
* Armadillo only
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_BASE_HPP
#define MLPACK_BASE_HPP

// First, check if Armadillo was included before, warning if so.
#ifdef ARMA_INCLUDES
#pragma message "Armadillo was included before mlpack; this can sometimes cause\
problems. It should only be necessary to include <mlpack/core.hpp> and not \
<armadillo>."
#endif

// Defining _USE_MATH_DEFINES should set M_PI.
#define _USE_MATH_DEFINES
#include <cmath>

// Next, standard includes.
#include <cctype>
#include <cfloat>
#include <climits>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <tuple>
#include <utility>
#include <numeric>
#include <vector>
#include <queue>

// But if it's not defined, we'll do it.
#ifndef M_PI
#define M_PI 3.141592653589793238462643383279
#endif

// MLPACK_COUT_STREAM is used to change the default stream for printing
// purpose.
#if !defined(MLPACK_COUT_STREAM)
#define MLPACK_COUT_STREAM std::cout
#endif

// MLPACK_CERR_STREAM is used to change the stream for printing warnings
// and errors.
#if !defined(MLPACK_CERR_STREAM)
#define MLPACK_CERR_STREAM std::cerr
#endif

// Give ourselves a nice way to force functions to be inline if we need.
#undef mlpack_force_inline
#define mlpack_force_inline
#if defined(__GNUG__) && !defined(DEBUG)
#undef mlpack_force_inline
#define mlpack_force_inline __attribute__((always_inline))
#elif defined(_MSC_VER) && !defined(DEBUG)
#undef mlpack_force_inline
#define mlpack_force_inline __forceinline
#endif

// Backport std::any from C+17 to C++11 to replace boost::any.
// Use mnmlstc backport implementation only if compiler does not
// support C++17.
#if __cplusplus < 201703L
#include <mlpack/core/std_backport/any.hpp>
#include <mlpack/core/std_backport/string_view.hpp>
#define MLPACK_ANY core::v2::any
#define MLPACK_ANY_CAST core::v2::any_cast
#define MLPACK_STRING_VIEW core::v2::string_view
#else
#include <any>
#include <string_view>
#define MLPACK_ANY std::any
#define MLPACK_ANY_CAST std::any_cast
#define MLPACK_STRING_VIEW std::string_view
#endif

// Now include Armadillo through the special mlpack extensions.
#include <mlpack/core/arma_extend/arma_extend.hpp>
#include <mlpack/core/util/arma_traits.hpp>

// On Visual Studio, disable C4519 (default arguments for function templates)
// since it's by default an error, which doesn't even make any sense because
// it's part of the C++11 standard.
#ifdef _MSC_VER
#pragma warning(disable : 4519)
#endif

// Ensure that the user isn't doing something stupid with their Armadillo
// defines.
#include <mlpack/core/util/arma_config_check.hpp>

// This can be removed when Visual Studio supports an OpenMP version with
// unsigned loop variables.
#if (defined(_OPENMP) && (_OPENMP >= 201107))
#undef MLPACK_USE_OPENMP
#define MLPACK_USE_OPENMP
#endif

conradsnicta marked this conversation as resolved.
Show resolved Hide resolved
// We need to be able to mark functions deprecated.
#include <mlpack/core/util/deprecated.hpp>

#endif
1 change: 1 addition & 0 deletions src/mlpack/bindings/CMakeLists.txt
Expand Up @@ -15,6 +15,7 @@ endforeach()

set(MARKDOWN_CATEGORIES ${MARKDOWN_CATEGORIES} PARENT_SCOPE)
set(MLPACK_SRCS ${MLPACK_SRCS} PARENT_SCOPE)
set(MLPACK_TEST_SRCS ${MLPACK_TEST_SRCS} PARENT_SCOPE)
set(MLPACK_PYXS ${MLPACK_PYXS} PARENT_SCOPE)
set(DISABLE_CFLAGS ${DISABLE_CFLAGS} PARENT_SCOPE)
set(BUILDING_PYTHON_BINDINGS ${BUILDING_PYTHON_BINDINGS} PARENT_SCOPE)
Expand Down
1 change: 1 addition & 0 deletions src/mlpack/bindings/R/CMakeLists.txt
Expand Up @@ -414,6 +414,7 @@ macro (post_r_setup)
# Then copy each of the header and source files over to that directory.
set(MLPACK_SOURCES
"${CMAKE_BINARY_DIR}/src/mlpack/mlpack_export.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/base.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/prereqs.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/core.hpp"
)
Expand Down
2 changes: 1 addition & 1 deletion src/mlpack/bindings/R/R_option.hpp
Expand Up @@ -73,7 +73,7 @@ class ROption
data.cppType = cppName;

// Every parameter we'll get from R will have the correct type.
data.value = ANY(defaultValue);
data.value = defaultValue;

// Set the function pointers that we'll need. All of these function
// pointers will be used by both the program that generates the R, and
Expand Down
6 changes: 3 additions & 3 deletions src/mlpack/bindings/R/default_param_impl.hpp
Expand Up @@ -36,7 +36,7 @@ std::string DefaultParamImpl(
if (std::is_same<T, bool>::value)
oss << "FALSE";
else
oss << ANY_CAST<T>(data.value);
oss << MLPACK_ANY_CAST<T>(data.value);

return oss.str();
}
Expand All @@ -51,7 +51,7 @@ std::string DefaultParamImpl(
{
// Print each element in an array delimited by square brackets.
std::ostringstream oss;
const T& vector = ANY_CAST<T>(data.value);
const T& vector = MLPACK_ANY_CAST<T>(data.value);
oss << "c(";
if (std::is_same<T, std::vector<std::string>>::value)
{
Expand Down Expand Up @@ -92,7 +92,7 @@ std::string DefaultParamImpl(
util::ParamData& data,
const typename std::enable_if<std::is_same<T, std::string>::value>::type*)
{
const std::string& s = *ANY_CAST<std::string>(&data.value);
const std::string& s = *MLPACK_ANY_CAST<std::string>(&data.value);
return "\"" + s + "\"";
}

Expand Down
2 changes: 1 addition & 1 deletion src/mlpack/bindings/R/get_param.hpp
Expand Up @@ -27,7 +27,7 @@ void GetParam(util::ParamData& d,
const void* /* input */,
void* output)
{
*((T**) output) = const_cast<T*>(ANY_CAST<T>(&d.value));
*((T**) output) = const_cast<T*>(MLPACK_ANY_CAST<T>(&d.value));
}

} // namespace r
Expand Down
10 changes: 5 additions & 5 deletions src/mlpack/bindings/R/get_printable_param.hpp
Expand Up @@ -32,7 +32,7 @@ std::string GetPrintableParam(
std::tuple<data::DatasetInfo, arma::mat>>::value>::type* = 0)
{
std::ostringstream oss;
oss << ANY_CAST<T>(data.value);
oss << MLPACK_ANY_CAST<T>(data.value);
return oss.str();
}

Expand All @@ -44,7 +44,7 @@ std::string GetPrintableParam(
util::ParamData& data,
const typename std::enable_if<util::IsStdVector<T>::value>::type* = 0)
{
const T& t = ANY_CAST<T>(data.value);
const T& t = MLPACK_ANY_CAST<T>(data.value);

std::ostringstream oss;
for (size_t i = 0; i < t.size(); ++i)
Expand All @@ -61,7 +61,7 @@ std::string GetPrintableParam(
const typename std::enable_if<arma::is_arma_type<T>::value>::type* = 0)
{
// Get the matrix.
const T& matrix = ANY_CAST<T>(data.value);
const T& matrix = MLPACK_ANY_CAST<T>(data.value);

std::ostringstream oss;
oss << matrix.n_rows << "x" << matrix.n_cols << " matrix";
Expand All @@ -78,7 +78,7 @@ std::string GetPrintableParam(
const typename std::enable_if<data::HasSerialize<T>::value>::type* = 0)
{
std::ostringstream oss;
oss << data.cppType << " model at " << ANY_CAST<T*>(data.value);
oss << data.cppType << " model at " << MLPACK_ANY_CAST<T*>(data.value);
return oss.str();
}

Expand All @@ -92,7 +92,7 @@ std::string GetPrintableParam(
std::tuple<data::DatasetInfo, arma::mat>>::value>::type* = 0)
{
// Get the matrix.
const T& tuple = ANY_CAST<T>(data.value);
const T& tuple = MLPACK_ANY_CAST<T>(data.value);
const arma::mat& matrix = std::get<1>(tuple);

std::ostringstream oss;
Expand Down
3 changes: 1 addition & 2 deletions src/mlpack/bindings/R/mlpack/DESCRIPTION.in
Expand Up @@ -7,8 +7,7 @@ Description: A fast, flexible machine learning library, written in C++, that
aims to provide fast, extensible implementations of cutting-edge
machine learning algorithms. See also Curtin et al. (2018)
<doi:10.21105/joss.00726>.
SystemRequirements: A C++11 compiler. Versions 4.8.*, 4.9.* or later of GCC
will be fine.
SystemRequirements: A C++14 compiler. Version 5 or later of GCC will be fine.
License: BSD_3_clause + file LICENSE
Depends: R (>= 4.0.0)
Imports: Rcpp (>= 0.12.12)
Expand Down
8 changes: 4 additions & 4 deletions src/mlpack/bindings/R/print_doc.hpp
Expand Up @@ -55,19 +55,19 @@ void PrintDoc(util::ParamData& d,
oss << ". Default value \"";
if (d.cppType == "std::string")
{
oss << ANY_CAST<std::string>(d.value);
oss << MLPACK_ANY_CAST<std::string>(d.value);
}
else if (d.cppType == "double")
{
oss << ANY_CAST<double>(d.value);
oss << MLPACK_ANY_CAST<double>(d.value);
}
else if (d.cppType == "int")
{
oss << ANY_CAST<int>(d.value);
oss << MLPACK_ANY_CAST<int>(d.value);
}
else if (d.cppType == "bool")
{
oss << (ANY_CAST<bool>(d.value) ? "TRUE" : "FALSE");
oss << (MLPACK_ANY_CAST<bool>(d.value) ? "TRUE" : "FALSE");
}
oss << "\"";
}
Expand Down
12 changes: 6 additions & 6 deletions src/mlpack/bindings/cli/add_to_cli11.hpp
Expand Up @@ -47,8 +47,8 @@ void AddToCLI11(const std::string& cliName,
[&param](const std::string& value)
{
using TupleType = std::tuple<T, typename ParameterType<T>::type>;
TupleType& tuple = *ANY_CAST<TupleType>(&param.value);
std::get<0>(std::get<1>(tuple)) = ANY_CAST<std::string>(value);
TupleType& tuple = *MLPACK_ANY_CAST<TupleType>(&param.value);
std::get<0>(std::get<1>(tuple)) = MLPACK_ANY_CAST<std::string>(value);
param.wasPassed = true;
},
param.desc.c_str());
Expand Down Expand Up @@ -79,8 +79,8 @@ void AddToCLI11(const std::string& cliName,
[&param](const std::string& value)
{
using TupleType = std::tuple<T*, typename ParameterType<T>::type>;
TupleType& tuple = *ANY_CAST<TupleType>(&param.value);
std::get<1>(tuple) = ANY_CAST<std::string>(value);
TupleType& tuple = *MLPACK_ANY_CAST<TupleType>(&param.value);
std::get<1>(tuple) = MLPACK_ANY_CAST<std::string>(value);
param.wasPassed = true;
},
param.desc.c_str());
Expand Down Expand Up @@ -109,8 +109,8 @@ void AddToCLI11(const std::string& cliName,
[&param](const std::string& value)
{
using TupleType = std::tuple<T, typename ParameterType<T>::type>;
TupleType& tuple = *ANY_CAST<TupleType>(&param.value);
std::get<0>(std::get<1>(tuple)) = ANY_CAST<std::string>(value);
TupleType& tuple = *MLPACK_ANY_CAST<TupleType>(&param.value);
std::get<0>(std::get<1>(tuple)) = MLPACK_ANY_CAST<std::string>(value);
param.wasPassed = true;
},
param.desc.c_str());
Expand Down