Skip to content
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
23 changes: 16 additions & 7 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ endif ()

include (GNUInstallDirs)

set (NLOPT_R_BINDIR "" CACHE STRING "Directory containing the R executable")

# Offer the user the choice of overriding the installation directories
set (NLOPT_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING "Installation directory for libraries")
set (NLOPT_INSTALL_BINDIR ${CMAKE_INSTALL_BINDIR} CACHE STRING "Installation directory for executables")
Expand Down Expand Up @@ -239,8 +241,15 @@ if (NLOPT_LUKSAN)
target_include_directories(${nlopt_lib} PRIVATE src/algs/luksan)
target_compile_definitions (${nlopt_lib} PRIVATE NLOPT_LUKSAN)
endif ()

if (NOT "${NLOPT_R_BINDIR}" STREQUAL "")
find_package(R REQUIRED)
target_include_directories(${nlopt_lib} PRIVATE ${R_INCLUDE_DIR})
target_compile_definitions(${nlopt_lib} PRIVATE NLOPT_R)
endif ()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this link on Windows without an explicit reference to R.dll?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will double check but I am pretty sure I checked against win-builder machines. I will do it again to be sure.


if (M_LIBRARY)
target_link_libraries (${nlopt_lib} ${M_LIBRARY})
target_link_libraries (${nlopt_lib} ${M_LIBRARY})
endif ()
set_target_properties (${nlopt_lib} PROPERTIES SOVERSION ${SO_MAJOR})
set_target_properties (${nlopt_lib} PROPERTIES VERSION "${SO_MAJOR}.${SO_MINOR}.${SO_PATCH}")
Expand Down Expand Up @@ -310,12 +319,12 @@ if (UNIX)
endif ()

if (NLOPT_PYTHON)
option (NLOPT_PYTHON_SABI "Use Python stable ABI" OFF)
if (NLOPT_PYTHON_SABI AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.26)
find_package (Python 3.6 COMPONENTS Interpreter Development.SABIModule NumPy)
add_library (Python::Module ALIAS Python::SABIModule)
else ()
find_package (Python 3.6 COMPONENTS Interpreter Development.Module NumPy)
option (NLOPT_PYTHON_SABI "Use Python stable ABI" OFF)
if (NLOPT_PYTHON_SABI AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.26)
find_package (Python 3.6 COMPONENTS Interpreter Development.SABIModule NumPy)
add_library (Python::Module ALIAS Python::SABIModule)
else ()
find_package (Python 3.6 COMPONENTS Interpreter Development.Module NumPy)
endif ()
endif ()

Expand Down
99 changes: 99 additions & 0 deletions cmake/FindR.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Adapted from
# https://github.com/CoolProp/CoolProp/blob/master/dev/cmake/Modules/FindR.cmake
# which is MIT-licensed

# - Find R
# This module finds the libraries corresponding to the R program
# It is based on the code from http://github.com/usnistgov/REFPROP-wrappers
# which is in the public domain

# This code sets the following variables:
#
# R_LIBRARY - path to the R shared library
# R_INCLUDE_DIR - include directory(ies)
# R_BIN_DIR - directory that contains the R executable being used

include(FindPackageHandleStandardArgs)

SET(R_FOUND 0)

IF( "${NLOPT_R_BINDIR}" STREQUAL "")
MESSAGE(FATAL_ERROR "You must pass the CMake variable NLOPT_R_BINDIR pointing to the directory that contains your executable")
ENDIF()

find_program(R_EXEC
NAMES R
PATHS ${NLOPT_R_BINDIR}
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH
NO_DEFAULT_PATH
NO_CMAKE_PATH
)
IF( "${R_EXEC}" STREQUAL "R_EXEC-NOTFOUND")
MESSAGE(FATAL_ERROR "The executable R could not be found in the folder ${NLOPT_R_BINDIR}")
ENDIF()

MESSAGE(STATUS "R_EXEC= ${R_EXEC}")
# Parse the output of the R path command, removing whitespace
FUNCTION(chomp arg1 arg2)
string(REPLACE "\n" ";" arg1list ${arg1})
list(GET arg1list 1 arg1line)
string(LENGTH ${arg1line} len)
MATH(EXPR length ${len}-6)
string(SUBSTRING ${arg1line} 5 ${length} arg1path)
# see http://www.cmake.org/pipermail/cmake/2008-November/025423.html
set(${arg2} ${arg1path} PARENT_SCOPE)
ENDFUNCTION(chomp)

file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/get_home.R R.home())
execute_process(
COMMAND ${R_EXEC} --quiet -f ${CMAKE_CURRENT_BINARY_DIR}/get_home.R OUTPUT_VARIABLE R_HOME_TEXT RESULT_VARIABLE R_HOME_RESULT
)
file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/get_home.R)
chomp(${R_HOME_TEXT} R_HOME_TEXT)
MESSAGE(STATUS "R_HOME_TEXT = ${R_HOME_TEXT} w/ RESULT=${R_HOME_RESULT}")

file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/get_include.R R.home(component=\"include\"))
execute_process(
COMMAND ${R_EXEC} --quiet -f ${CMAKE_CURRENT_BINARY_DIR}/get_include.R OUTPUT_VARIABLE R_INCLUDE_TEXT RESULT_VARIABLE R_INCLUDE_RESULT
)
file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/get_include.R)
chomp(${R_INCLUDE_TEXT} R_INCLUDE_DIR)
MESSAGE(STATUS "R_INCLUDE = ${R_INCLUDE_DIR} w/ RESULT=${R_INCLUDE_RESULT}")

file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/get_bin.R R.home(component=\"bin\"))
execute_process(
COMMAND ${R_EXEC} --quiet -f ${CMAKE_CURRENT_BINARY_DIR}/get_bin.R OUTPUT_VARIABLE R_BIN_TEXT RESULT_VARIABLE R_BIN_RESULT
)
file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/get_bin.R)
chomp(${R_BIN_TEXT} R_BIN_DIR)
MESSAGE(STATUS "R_BIN_TEXT = ${R_BIN_DIR} w/ RESULT=${R_BIN_RESULT}")

if (WIN32)
# Bug in cmake 3.17, need to search for file rather than library
find_file(
R_LIBRARY
NAMES R.dll
PATHS ${R_BIN_DIR}
NO_DEFAULT_PATH
)
else()
set(R_PATH_LOC "${R_HOME_TEXT}/lib")
MESSAGE(STATUS "R_PATH_LOC = ${R_PATH_LOC}")
find_library(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At least on Linux, R defaults to --disable-R-shlib, so there won't be a libR.so in R.home('lib'). (But a distro-built R will usually be compiled with --enable-R-shlib because distros have a strong preference for dynamic linking.) This won't prevent you from linking and loading a shared library (because the dynamic loader will resolve the symbols from the ones exported by the R executable), but any example applications will fail to link.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this feedback. Do you know how I could improve the FindR.cmake file to circumvent this issue?

R_LIBRARY
NAMES R
PATHS ${R_PATH_LOC}
NO_DEFAULT_PATH
)
endif()
MESSAGE(STATUS "R_LIBRARY = ${R_LIBRARY}")

find_package_handle_standard_args(R DEFAULT_MSG
R_LIBRARY R_INCLUDE_DIR)

MARK_AS_ADVANCED(
R_BIN_DIR
R_LIBRARY
R_INCLUDE_DIR
)
63 changes: 45 additions & 18 deletions src/algs/auglag/auglag.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ static double auglag(unsigned n, const double *x, double *grad, void *data)
for (k = 0; k < d->h[i].m; ++k) {
double h = restmp[k] + lambda[ii++] / rho;
L += 0.5 * rho * h*h;
if (grad) for (j = 0; j < n; ++j)
if (grad) for (j = 0; j < n; ++j)
grad[j] += (rho * h) * gradtmp[k*n + j];
}
}
Expand All @@ -55,7 +55,7 @@ static double auglag(unsigned n, const double *x, double *grad, void *data)
double fc = restmp[k] + mu[ii++] / rho;
if (fc > 0) {
L += 0.5 * rho * fc*fc;
if (grad) for (j = 0; j < n; ++j)
if (grad) for (j = 0; j < n; ++j)
grad[j] += (rho * fc) * gradtmp[k*n + j];
}
}
Expand Down Expand Up @@ -109,7 +109,7 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data,
ret = nlopt_set_min_objective(sub_opt, auglag, &d); if (ret<0) return ret;
ret = nlopt_set_lower_bounds(sub_opt, lb); if (ret<0) return ret;
ret = nlopt_set_upper_bounds(sub_opt, ub); if (ret<0) return ret;
ret = nlopt_set_stopval(sub_opt,
ret = nlopt_set_stopval(sub_opt,
d.m==0 && d.p==0 ? stop->minf_max : -HUGE_VAL);
if (ret<0) return ret;
ret = nlopt_remove_inequality_constraints(sub_opt); if (ret<0) return ret;
Expand All @@ -120,7 +120,7 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data,
fc[i].f, fc[i].f_data,
fc[i].tol[0]);
else
ret = nlopt_add_inequality_mconstraint(sub_opt, fc[i].m,
ret = nlopt_add_inequality_mconstraint(sub_opt, fc[i].m,
fc[i].mf, fc[i].f_data,
fc[i].tol);
if (ret < 0) return ret;
Expand Down Expand Up @@ -180,31 +180,47 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data,
d.rho = 1; /* whatever, doesn't matter */

if (auglag_verbose) {
printf("auglag: initial rho=%g\nauglag initial lambda=", d.rho);
for (i = 0; i < d.pp; ++i) printf(" %g", d.lambda[i]);
printf("\nauglag initial mu = ");
for (i = 0; i < d.mm; ++i) printf(" %g", d.mu[i]);
printf("\n");
#ifndef NLOPT_R
printf("auglag: initial rho=%g\nauglag initial lambda=", d.rho);
for (i = 0; i < d.pp; ++i) printf(" %g", d.lambda[i]);
printf("\nauglag initial mu = ");
for (i = 0; i < d.mm; ++i) printf(" %g", d.mu[i]);
printf("\n");
#else
Rprintf("auglag: initial rho=%g\nauglag initial lambda=", d.rho);
for (i = 0; i < d.pp; ++i) Rprintf(" %g", d.lambda[i]);
Rprintf("\nauglag initial mu = ");
for (i = 0; i < d.mm; ++i) Rprintf(" %g", d.mu[i]);
Rprintf("\n");
#endif
}

do {
double prev_ICM = ICM;

ret = nlopt_optimize_limited(sub_opt, xcur, &fcur,
stop->maxeval - *(stop->nevals_p),
stop->maxtime - (nlopt_seconds()
stop->maxtime - (nlopt_seconds()
- stop->start));
if (auglag_verbose)
printf("auglag: subopt return code %d\n", ret);
#ifndef NLOPT_R
printf("auglag: subopt return code %d\n", ret);
#else
Rprintf("auglag: subopt return code %d\n", ret);
#endif
if (ret < 0) break;

++ *(d.stop->nevals_p);
fcur = f(n, xcur, NULL, f_data);
if (nlopt_stop_forced(stop)) {
ret = NLOPT_FORCED_STOP; goto done; }
if (auglag_verbose)
#ifndef NLOPT_R
printf("auglag: fcur = %g\n", fcur);

#else
Rprintf("auglag: fcur = %g\n", fcur);
#endif

ICM = 0;
penalty = 0;
feasible = 1;
Expand Down Expand Up @@ -239,7 +255,8 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data,
}

auglag_iters++;


#ifndef NLOPT_R
if (auglag_verbose) {
printf("auglag %d: ICM=%g (%sfeasible), rho=%g\nauglag lambda=",
auglag_iters, ICM, feasible ? "" : "not ", d.rho);
Expand All @@ -248,15 +265,25 @@ nlopt_result auglag_minimize(int n, nlopt_func f, void *f_data,
for (i = 0; i < d.mm; ++i) printf(" %g", d.mu[i]);
printf("\n");
}
#else
if (auglag_verbose) {
Rprintf("auglag %d: ICM=%g (%sfeasible), rho=%g\nauglag lambda=",
auglag_iters, ICM, feasible ? "" : "not ", d.rho);
for (i = 0; i < d.pp; ++i) Rprintf(" %g", d.lambda[i]);
Rprintf("\nauglag %d: mu = ", auglag_iters);
for (i = 0; i < d.mm; ++i) Rprintf(" %g", d.mu[i]);
Rprintf("\n");
}
#endif

if ((feasible && (!minf_feasible || penalty < minf_penalty
|| fcur < *minf)) ||
|| fcur < *minf)) ||
(!minf_feasible && penalty < minf_penalty)) {
ret = NLOPT_SUCCESS;
if (feasible) {
if (fcur < stop->minf_max)
if (fcur < stop->minf_max)
ret = NLOPT_MINF_MAX_REACHED;
else if (nlopt_stop_ftol(stop, fcur, *minf))
else if (nlopt_stop_ftol(stop, fcur, *minf))
ret = NLOPT_FTOL_REACHED;
else if (nlopt_stop_x(stop, xcur, x))
ret = NLOPT_XTOL_REACHED;
Expand Down
Loading