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

Fix https://github.com/libprima/prima/issues/193 #196

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
a1b7f19
240430.174247.HKT try `prima_internal.h`
zaikunzhang Apr 30, 2024
c5a7a62
240430.184425.HKT fix prima.c
zaikunzhang Apr 30, 2024
5d39bb8
240430.192839.HKT fix stress.c
zaikunzhang Apr 30, 2024
cd4ed08
240430.194937.HKT remove `get_random_seed` from prima_internal.h
zaikunzhang Apr 30, 2024
4053ef5
240430.195955.HKT add `static` to the definition of `get_random_seed`
zaikunzhang Apr 30, 2024
dcc1d27
240430.202701.HKT get back `prima_is_success`
zaikunzhang Apr 30, 2024
43abd5f
240430.211322.HKT fix warning C4133: 'function': incompatible types …
zaikunzhang Apr 30, 2024
03213fe
240430.212121.HKT try fixing "conversion to non-scalar type requested"
zaikunzhang Apr 30, 2024
dd02831
240430.212905.HKT fix warning C4133: 'function': incompatible types …
zaikunzhang Apr 30, 2024
5934728
240430.233715.HKT fix "enumerator PRIMA_RESULT_INITIALIZED in switch …
zaikunzhang Apr 30, 2024
268839b
240430.234014.HKT fix prima.c
zaikunzhang Apr 30, 2024
b033b73
240501.000846.HKT disable warning C4820 with cl
zaikunzhang Apr 30, 2024
9e92847
240501.002620.HKT disable warning C4464 with cl
zaikunzhang Apr 30, 2024
07fe9f3
240501.003935.HKT disable warning C4710 with cl
zaikunzhang Apr 30, 2024
77aed25
240501.004958.HKT fix "conversion from size_t to int, possible loss o…
zaikunzhang Apr 30, 2024
3fd5f24
240501.005643.HKT fix a typo in cmake.yml
zaikunzhang Apr 30, 2024
c8c671b
240501.010755.HKT revise comments in cmake.yml
zaikunzhang Apr 30, 2024
e2dc712
240501.012332.HKT comment on `localtime_s` and `localtime_r`
zaikunzhang Apr 30, 2024
7af5319
240501.012624.HKT revise comments in cmake.yml
zaikunzhang Apr 30, 2024
635c675
240501.014609.HKT fix a typo in cmake.yml
zaikunzhang Apr 30, 2024
e3e414c
240501.112439.HKT C: make `prima_get_rc_string`, `prima_check_problem…
zaikunzhang May 1, 2024
8e801c2
Merge branch 'main' into fix_issue_193
zaikunzhang May 5, 2024
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
1 change: 1 addition & 0 deletions .github/actions/spelling/allow.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2259,5 +2259,6 @@ nuj
PARKCH
TESTQUAD
WAITALL
timeinfo
xcodebuild
ICX
8 changes: 6 additions & 2 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,26 @@ jobs:
# 2. On windows-latest, we want to use '-Wall -W5 -Werror-all' as what we do for the intel-classic
# compiler, but the (new) intel c compiler does not recognize '-W5 -Werror-all', even though the
# official documentation of the compiler mentions them. Why?
# Comments on flags of `cl`:
# -wd4820 disables the warning about "... bytes padding added after data member"
# -wd4464 disables the warning about "relative include path contains '..'"
# -wd4710 disables the warning about "... function is not inlined"
- os: windows-latest
toolchain: {compiler: intel, version: '2023.2', cflags: '-Wall -Werror', fflags: '/warn:all /debug:extended /Z7 /fimplicit-none /standard-semantics'}
- os: windows-latest
toolchain: {compiler: intel, version: '2024.0', cflags: '-Wall -Werror', fflags: '/warn:all /debug:extended /Z7 /fimplicit-none /standard-semantics'}
- os: windows-latest
toolchain: {compiler: intel, version: '2024.1', cflags: '-Wall -Werror', fflags: '/warn:all /debug:extended /Z7 /fimplicit-none /standard-semantics'}
- os: windows-latest
toolchain: {compiler: intel, version: '2024.1', cflags: '-Wall -W4 -WX', fflags: '/warn:all /debug:extended /Z7 /fimplicit-none /standard-semantics', cc: cl}
toolchain: {compiler: intel, version: '2024.1', cflags: '-wd4820 -wd4464 -wd4710 -Wall -W4 -WX', fflags: '/warn:all /debug:extended /Z7 /fimplicit-none /standard-semantics /assume:recursion', cc: cl}
# N.B.: As of 20240401, setup-fortran fails constantly with windows-latest and intel-classic
# 2021.8. Thus this combination is not included.
- os: windows-latest
toolchain: {compiler: intel-classic, version: '2021.9', cflags: '-Qdiag-disable:10441 -Wall -W5 -Werror-all', fflags: '/warn:all /debug:extended /Z7 /fimplicit-none /standard-semantics'}
- os: windows-latest
toolchain: {compiler: intel-classic, version: '2021.10', cflags: '-Qdiag-disable:10441 -Wall -W5 -Werror-all', fflags: '/warn:all /debug:extended /Z7 /fimplicit-none /standard-semantics'}
- os: windows-latest
toolchain: {compiler: intel-classic, version: '2021.10', cflags: '-Wall -W4 -WX', fflags: '/warn:all /debug:extended /Z7 /fimplicit-none /standard-semantics', cc: cl}
toolchain: {compiler: intel-classic, version: '2021.10', cflags: '-wd4820 -wd4464 -wd4710 -Wall -W4 -WX', fflags: '/warn:all /debug:extended /Z7 /fimplicit-none /standard-semantics /assume:recursion', cc: cl}

steps:

Expand Down
5 changes: 0 additions & 5 deletions c/include/prima/prima.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,6 @@ typedef enum {
} prima_rc_t;


// Function to get the message string corresponding to a return code
PRIMAC_API
const char *prima_get_rc_string(const prima_rc_t rc);


/*
* Objective function required by UOBYQA, NEWUOA, BOBYQA, and LINCOA
* x : on input, the vector of variables (should not be modified)
Expand Down
30 changes: 30 additions & 0 deletions c/include/prima/prima_internal.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef PRIMA_INTERNAL_H
#define PRIMA_INTERNAL_H

#include "prima/prima.h"

// Functions implemented in Fortran (*_c.f90)
int cobyla_c(const int m_nlcon, const prima_objcon_t calcfc, const void *data, const int n, double x[], double *const f, double *const cstrv, double nlconstr[],
const int m_ineq, const double Aineq[], const double bineq[],
const int m_eq, const double Aeq[], const double beq[],
const double xl[], const double xu[],
const double f0, const double nlconstr0[],
int *const nf, const double rhobeg, const double rhoend, const double ftarget, const int maxfun, const int iprint, const double ctol,
const prima_callback_t callback, int *const info);

int bobyqa_c(prima_obj_t calfun, const void *data, const int n, double x[], double *const f, const double xl[], const double xu[],
int *const nf, const double rhobeg, const double rhoend, const double ftarget, const int maxfun, const int npt, const int iprint, const prima_callback_t callback, int *const info);

int newuoa_c(prima_obj_t calfun, const void *data, const int n, double x[], double *const f,
int *const nf, const double rhobeg, const double rhoend, const double ftarget, const int maxfun, const int npt, const int iprint, const prima_callback_t callback, int *const info);

int uobyqa_c(prima_obj_t calfun, const void *data, const int n, double x[], double *const f,
int *const nf, const double rhobeg, const double rhoend, const double ftarget, const int maxfun, const int iprint, const prima_callback_t callback, int *const info);

int lincoa_c(prima_obj_t calfun, const void *data, const int n, double x[], double *const f,
double *const cstrv, const int m_ineq, const double Aineq[], const double bineq[],
const int m_eq, const double Aeq[], const double beq[], const double xl[], const double xu[],
int *const nf, const double rhobeg, const double rhoend, const double ftarget, const int maxfun, const int npt, const int iprint, const double ctol,
const prima_callback_t callback, int *const info);

#endif
157 changes: 68 additions & 89 deletions c/prima.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Dedicated to the late Professor M. J. D. Powell FRS (1936--2015).


#include "prima/prima.h"
#include <float.h>
#include "prima/prima_internal.h"
#include <float.h> // This provides DBL_EPSILON, which will be removed once ctol is introduced
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -63,7 +63,7 @@ prima_rc_t prima_init_options(prima_options_t *const options)


// Function to check whether the problem matches the algorithm
prima_rc_t prima_check_problem(const prima_problem_t problem, const prima_algorithm_t algorithm)
static prima_rc_t prima_check_problem(const prima_problem_t problem, const prima_algorithm_t algorithm)
{
if (!problem.x0)
return PRIMA_NULL_X0;
Expand All @@ -75,8 +75,62 @@ prima_rc_t prima_check_problem(const prima_problem_t problem, const prima_algori
}


// Function to get the string corresponding to the return code
static const char *prima_get_rc_string(const prima_rc_t rc)
{
switch (rc) {
case PRIMA_SMALL_TR_RADIUS:
return "Trust region radius reaches its lower bound";
case PRIMA_FTARGET_ACHIEVED:
return "The target function value is reached";
case PRIMA_TRSUBP_FAILED:
return "A trust region step failed to reduce the model";
case PRIMA_MAXFUN_REACHED:
return "Maximum number of function evaluations reached";
case PRIMA_MAXTR_REACHED:
return "Maximum number of trust region iterations reached";
case PRIMA_NAN_INF_X:
return "The input X contains NaN of Inf";
case PRIMA_NAN_INF_F:
return "The objective or constraint functions return NaN or +Inf";
case PRIMA_NAN_INF_MODEL:
return "NaN or Inf occurs in the model";
case PRIMA_NO_SPACE_BETWEEN_BOUNDS:
return "No space between bounds";
case PRIMA_DAMAGING_ROUNDING:
return "Rounding errors are becoming damaging";
case PRIMA_ZERO_LINEAR_CONSTRAINT:
return "One of the linear constraints has a zero gradient";
case PRIMA_CALLBACK_TERMINATE:
return "Callback function requested termination of optimization";
case PRIMA_INVALID_INPUT:
return "Invalid input";
case PRIMA_ASSERTION_FAILS:
return "Assertion fails";
case PRIMA_VALIDATION_FAILS:
return "Validation fails";
case PRIMA_MEMORY_ALLOCATION_FAILS:
return "Memory allocation fails";
case PRIMA_NULL_OPTIONS:
return "NULL options";
case PRIMA_NULL_PROBLEM:
return "NULL problem";
case PRIMA_NULL_X0:
return "NULL x0";
case PRIMA_NULL_RESULT:
return "NULL result";
case PRIMA_NULL_FUNCTION:
return "NULL function";
case PRIMA_RESULT_INITIALIZED:
return "Result is initialized but not properly set";
default:
return "Invalid return code";
}
}


// Function to initialize the result
prima_rc_t prima_init_result(prima_result_t *const result, const prima_problem_t problem)
static prima_rc_t prima_init_result(prima_result_t *const result, const prima_problem_t problem)
{
if (!result)
return PRIMA_NULL_RESULT;
Expand All @@ -96,7 +150,7 @@ prima_rc_t prima_init_result(prima_result_t *const result, const prima_problem_t
result->status = PRIMA_RESULT_INITIALIZED;

// message: exit message
result->message = NULL;
result->message = prima_get_rc_string(result->status);

// x: returned point
result->x = (double*)malloc(problem.n * sizeof(double));
Expand Down Expand Up @@ -136,94 +190,17 @@ prima_rc_t prima_free_result(prima_result_t *const result)
}


// Function to get the string corresponding to the return code
const char *prima_get_rc_string(const prima_rc_t rc)
{
switch (rc) {
case PRIMA_SMALL_TR_RADIUS:
return "Trust region radius reaches its lower bound";
case PRIMA_FTARGET_ACHIEVED:
return "The target function value is reached";
case PRIMA_TRSUBP_FAILED:
return "A trust region step failed to reduce the model";
case PRIMA_MAXFUN_REACHED:
return "Maximum number of function evaluations reached";
case PRIMA_MAXTR_REACHED:
return "Maximum number of trust region iterations reached";
case PRIMA_NAN_INF_X:
return "The input X contains NaN of Inf";
case PRIMA_NAN_INF_F:
return "The objective or constraint functions return NaN or +Inf";
case PRIMA_NAN_INF_MODEL:
return "NaN or Inf occurs in the model";
case PRIMA_NO_SPACE_BETWEEN_BOUNDS:
return "No space between bounds";
case PRIMA_DAMAGING_ROUNDING:
return "Rounding errors are becoming damaging";
case PRIMA_ZERO_LINEAR_CONSTRAINT:
return "One of the linear constraints has a zero gradient";
case PRIMA_CALLBACK_TERMINATE:
return "Callback function requested termination of optimization";
case PRIMA_INVALID_INPUT:
return "Invalid input";
case PRIMA_ASSERTION_FAILS:
return "Assertion fails";
case PRIMA_VALIDATION_FAILS:
return "Validation fails";
case PRIMA_MEMORY_ALLOCATION_FAILS:
return "Memory allocation fails";
case PRIMA_NULL_OPTIONS:
return "NULL options";
case PRIMA_NULL_PROBLEM:
return "NULL problem";
case PRIMA_NULL_X0:
return "NULL x0";
case PRIMA_NULL_RESULT:
return "NULL result";
case PRIMA_NULL_FUNCTION:
return "NULL function";
default:
return "Invalid return code";
}
}


// Functions implemented in Fortran (*_c.f90)
int cobyla_c(const int m_nlcon, const prima_objcon_t calcfc, const void *data, const int n, double x[], double *const f, double *const cstrv, double nlconstr[],
const int m_ineq, const double Aineq[], const double bineq[],
const int m_eq, const double Aeq[], const double beq[],
const double xl[], const double xu[],
const double f0, const double nlconstr0[],
int *const nf, const double rhobeg, const double rhoend, const double ftarget, const int maxfun, const int iprint, const double ctol,
const prima_callback_t callback, int *const info);

int bobyqa_c(prima_obj_t calfun, const void *data, const int n, double x[], double *const f, const double xl[], const double xu[],
int *const nf, const double rhobeg, const double rhoend, const double ftarget, const int maxfun, const int npt, const int iprint, const prima_callback_t callback, int *const info);

int newuoa_c(prima_obj_t calfun, const void *data, const int n, double x[], double *const f,
int *const nf, const double rhobeg, const double rhoend, const double ftarget, const int maxfun, const int npt, const int iprint, const prima_callback_t callback, int *const info);

int uobyqa_c(prima_obj_t calfun, const void *data, const int n, double x[], double *const f,
int *const nf, const double rhobeg, const double rhoend, const double ftarget, const int maxfun, const int iprint, const prima_callback_t callback, int *const info);

int lincoa_c(prima_obj_t calfun, const void *data, const int n, double x[], double *const f,
double *const cstrv, const int m_ineq, const double Aineq[], const double bineq[],
const int m_eq, const double Aeq[], const double beq[], const double xl[], const double xu[],
int *const nf, const double rhobeg, const double rhoend, const double ftarget, const int maxfun, const int npt, const int iprint, const double ctol,
const prima_callback_t callback, int *const info);


// The function that does the minimization using a PRIMA solver
prima_rc_t prima_minimize(const prima_algorithm_t algorithm, const prima_problem_t problem, const prima_options_t options, prima_result_t *const result)
{
prima_rc_t info = prima_init_result(result, problem);
int info = (int) prima_init_result(result, problem);

if (info == PRIMA_RC_DFT)
info = prima_check_problem(problem, algorithm);
info = (int) prima_check_problem(problem, algorithm);

if (info == PRIMA_RC_DFT) {
// We copy x0 into result->x only after prima_check_problem has succeeded,
// so that if prima_check_problem failed, result->x will not contained a
// so that if prima_check_problem failed, result->x will not contain a
// seemingly valid value.
for (int i = 0; i < problem.n; i++) {
result->x[i] = problem.x0[i];
Expand Down Expand Up @@ -258,16 +235,18 @@ prima_rc_t prima_minimize(const prima_algorithm_t algorithm, const prima_problem
break;

default:
return PRIMA_INVALID_INPUT;
info = (int) PRIMA_INVALID_INPUT;
}
}

result->status = info;
result->message = prima_get_rc_string(info);
result->status = (prima_rc_t) info;
result->message = prima_get_rc_string(result->status);

return info;
return result->status;
}


// The function that checks whether the result is "successful"
bool prima_is_success(const prima_result_t result)
{
return (result.status == PRIMA_SMALL_TR_RADIUS ||
Expand Down
19 changes: 15 additions & 4 deletions c/tests/stress.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@
#define M_INEQ_MAX 1000
#define M_NLCON 200

// Thread-safe version of localtime
// N.B.: localtime_s is typically associated with Microsoft's C runtime library while localtime_r
// is typically associated with POSIX-compliant systems; they have different argument orders.
#ifdef _WIN32
#define localtime_safe(a, b) localtime_s(a, b)
#else
#define localtime_safe(a, b) localtime_r(b, a)
#endif

int n = 0;
int m_ineq = 0;
const double alpha = 4.0;
Expand Down Expand Up @@ -61,12 +70,14 @@ static void fun_con(const double x[], double *const f, double constr[], const vo
}

// A function generating a seed that alters weekly
unsigned int get_random_seed(void) {
static unsigned int get_random_seed(void)
{
// Set the random seed to year/week
char buf[10] = {0};
time_t t = time(NULL);
struct tm *tmp = localtime(&t);
int rc = strftime(buf, 10, "%y%W", tmp);
struct tm timeinfo;
localtime_safe(&timeinfo, &t);
size_t rc = strftime(buf, 10, "%y%W", &timeinfo);
if (!rc)
return 42;
else
Expand All @@ -87,7 +98,7 @@ int main(int argc, char * argv[])
printf("Debug = %d\n", debug);

unsigned int seed = get_random_seed();
printf("Random seed = %d\n", seed);
printf("Random seed = %u\n", seed);
srand(seed);

// Set up the options
Expand Down
Loading