fnchk checks a user-provided R function, ffn.

fnchk(xpar, ffn, trace=0, ... )

Arguments

xpar

the (double) vector of parameters to the objective funcion

ffn

a user-provided function to compute the objective function

trace

set >0 to provide output from fnchk to the console, 0 otherwise

...

optional arguments passed to the objective function.

Details

fnchk attempts to discover various errors in function setup in user-supplied functions primarily intended for use in optimization calculations. There are always more conditions that could be tested!

Value

The output is a list consisting of list(fval=fval, infeasible=infeasible, excode=excode, msg=msg)

fval

The calculated value of the function at parameters xpar if the function can be evaluated.

infeasible

FALSE if the function can be evaluated, TRUE if not.

excode

An exit code, which has a relationship to

msg

A text string giving information about the result of the function check: Messages and the corresponding values of excode are:

fnchk OK;

excode = 0; infeasible = FALSE

Function returns INADMISSIBLE;

excode = -1; infeasible = TRUE

Function returns a vector not a scalar;

excode = -4; infeasible = TRUE

Function returns a list not a scalar;

excode = -4; infeasible = TRUE

Function returns a matrix list not a scalar;

excode = -4; infeasible = TRUE

Function returns an array not a scalar;

excode = -4; infeasible = TRUE

Function returned not length 1, despite not vector, matrix or array;

excode = -4; infeasible = TRUE

Function returned non-numeric value; excode = 0;

excode = -1; infeasible = TRUE

Function returned Inf or NA (non-computable);

excode = -1; infeasible = TRUE

Author

John C. Nash <profjcnash@gmail.com>

Examples

# Want to illustrate each case.
# Ben Bolker idea for a function that is NOT scalar
# rm(list=ls())
# library(optimx)
sessionInfo()
#> R version 4.4.1 (2024-06-14)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 22.04.5 LTS
#> 
#> Matrix products: default
#> BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
#> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.20.so;  LAPACK version 3.10.0
#> 
#> locale:
#>  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
#>  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=C              
#>  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
#>  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
#>  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
#> 
#> time zone: Etc/UTC
#> tzcode source: system (glibc)
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] numDeriv_2016.8-1.1 optimx_2025-4.9    
#> 
#> loaded via a namespace (and not attached):
#>  [1] ucminf_1.2.2      compiler_4.4.1    marqLevAlg_2.0.8  Rcpp_1.1.0       
#>  [5] xml2_1.4.0        parallel_4.4.1    dfoptim_2023.1.0  systemfonts_1.2.3
#>  [9] textshaping_1.0.1 yaml_2.3.10       fastmap_1.2.0     R6_2.6.1         
#> [13] curl_7.0.0        httr2_1.2.1       knitr_1.50        iterators_1.0.14 
#> [17] subplex_1.9       tibble_3.3.0      nloptr_2.2.1      desc_1.4.3       
#> [21] minqa_1.2.8       pillar_1.11.0     rlang_1.1.6       cachem_1.1.0     
#> [25] BB_2019.10-1      xfun_0.53         fs_1.6.6          quadprog_1.5-8   
#> [29] doParallel_1.0.17 memoise_2.0.1     cli_3.6.5         pkgdown_2.1.3    
#> [33] withr_3.0.2       magrittr_2.0.3    lbfgs_1.2.1.2     foreach_1.5.2    
#> [37] digest_0.6.37     rappdirs_0.3.3    lbfgsb3c_2024-3.5 lifecycle_1.0.4  
#> [41] vctrs_0.6.5       downlit_0.4.4     evaluate_1.0.4    pracma_2.4.4     
#> [45] glue_1.8.0        whisker_0.4.1     codetools_0.2-20  ragg_1.4.0       
#> [49] fansi_1.0.6       rmarkdown_2.29    purrr_1.1.0       tools_4.4.1      
#> [53] pkgconfig_2.0.3   htmltools_0.5.8.1
benbad<-function(x, y){
  # y may be provided with different structures
  f<-(x-y)^2
} # very simple, but ...

y<-1:10
x<-c(1)
cat("fc01: test benbad() with y=1:10, x=c(1)\n")
#> fc01: test benbad() with y=1:10, x=c(1)
fc01<-fnchk(x, benbad, trace=4, y)
#> fnchk: ffn =
#> function (x, y) 
#> {
#>     f <- (x - y)^2
#> }
#> <environment: 0x5577aa5b1280>
#> fnchk: xpar:[1] 1
#> fnchk: dots:[[1]]
#>  [1]  1  2  3  4  5  6  7  8  9 10
#> 
#> about to call ffn(xpar, ...)
#> ffn:function (x, y) 
#> {
#>     f <- (x - y)^2
#> }
#> <environment: 0x5577aa5b1280>
#> xpar & dots:[1] 1
#> [[1]]
#>  [1]  1  2  3  4  5  6  7  8  9 10
#> 
#> test in fnchk: [1]  0  1  4  9 16 25 36 49 64 81
#> Function value at supplied parameters = [1]  0  1  4  9 16 25 36 49 64 81
#>  num [1:10] 0 1 4 9 16 25 36 49 64 81
#> NULL
#> [1] TRUE
#> Function evaluation returns a vector not a scalar 
#> Function evaluation returned non-numeric value 
#> Function evaluation returned Inf or NA (non-computable) 
#> Function at given point= NA 
print(fc01)
#> $fval
#> [1] NA
#> 
#> $infeasible
#> [1] TRUE
#> 
#> $excode
#> [1] -1
#> 
#> $msg
#> [1] "Function evaluation returned Inf or NA (non-computable)"
#> 

y<-as.vector(y)
cat("fc02: test benbad() with y=as.vector(1:10), x=c(1)\n")
#> fc02: test benbad() with y=as.vector(1:10), x=c(1)
fc02<-fnchk(x, benbad, trace=1, y)
#> Function value at supplied parameters = [1]  0  1  4  9 16 25 36 49 64 81
#>  num [1:10] 0 1 4 9 16 25 36 49 64 81
#> NULL
#> [1] TRUE
#> Function evaluation returns a vector not a scalar 
#> Function evaluation returned non-numeric value 
#> Function evaluation returned Inf or NA (non-computable) 
#> Function at given point= NA 
print(fc02)
#> $fval
#> [1] NA
#> 
#> $infeasible
#> [1] TRUE
#> 
#> $excode
#> [1] -1
#> 
#> $msg
#> [1] "Function evaluation returned Inf or NA (non-computable)"
#> 

y<-as.matrix(y)
cat("fc03: test benbad() with y=as.matrix(1:10), x=c(1)\n")
#> fc03: test benbad() with y=as.matrix(1:10), x=c(1)
fc03<-fnchk(x, benbad, trace=1, y)
#> Function value at supplied parameters =      [,1]
#>  [1,]    0
#>  [2,]    1
#>  [3,]    4
#>  [4,]    9
#>  [5,]   16
#>  [6,]   25
#>  [7,]   36
#>  [8,]   49
#>  [9,]   64
#> [10,]   81
#>  num [1:10, 1] 0 1 4 9 16 25 36 49 64 81
#> NULL
#> [1] FALSE
#> Function evaluation returns a matrix list not a scalar 
#> Function evaluation returned non-numeric value 
#> Function evaluation returned Inf or NA (non-computable) 
#> Function at given point= NA 
print(fc03)
#> $fval
#> [1] NA
#> 
#> $infeasible
#> [1] TRUE
#> 
#> $excode
#> [1] -1
#> 
#> $msg
#> [1] "Function evaluation returned Inf or NA (non-computable)"
#> 

y<-as.array(y)
cat("fc04: test benbad() with y=as.array(1:10), x=c(1)\n")
#> fc04: test benbad() with y=as.array(1:10), x=c(1)
fc04<-fnchk(x, benbad, trace=1, y)
#> Function value at supplied parameters =      [,1]
#>  [1,]    0
#>  [2,]    1
#>  [3,]    4
#>  [4,]    9
#>  [5,]   16
#>  [6,]   25
#>  [7,]   36
#>  [8,]   49
#>  [9,]   64
#> [10,]   81
#>  num [1:10, 1] 0 1 4 9 16 25 36 49 64 81
#> NULL
#> [1] FALSE
#> Function evaluation returns a matrix list not a scalar 
#> Function evaluation returned non-numeric value 
#> Function evaluation returned Inf or NA (non-computable) 
#> Function at given point= NA 
print(fc04)
#> $fval
#> [1] NA
#> 
#> $infeasible
#> [1] TRUE
#> 
#> $excode
#> [1] -1
#> 
#> $msg
#> [1] "Function evaluation returned Inf or NA (non-computable)"
#> 

y<-"This is a string"
cat("test benbad() with y a string, x=c(1)\n")
#> test benbad() with y a string, x=c(1)
fc05<-fnchk(x, benbad, trace=1, y)
#> Error in x - y : non-numeric argument to binary operator
#> Function value at supplied parameters =[1] NA
#> attr(,"inadmissible")
#> [1] TRUE
#>  logi NA
#>  - attr(*, "inadmissible")= logi TRUE
#> NULL
#> [1] FALSE
#> Function evaluation returns INADMISSIBLE 
#> Function evaluation returned non-numeric value 
#> Function evaluation returned Inf or NA (non-computable) 
#> Function at given point= NA 
print(fc05)
#> $fval
#> [1] NA
#> 
#> $infeasible
#> [1] TRUE
#> 
#> $excode
#> [1] -1
#> 
#> $msg
#> [1] "Function evaluation returned Inf or NA (non-computable)"
#> 

cat("fnchk with Rosenbrock\n")
#> fnchk with Rosenbrock
fr <- function(x) {   ## Rosenbrock Banana function
  x1 <- x[1]
  x2 <- x[2]
  100 * (x2 - x1 * x1)^2 + (1 - x1)^2
}
xtrad<-c(-1.2,1)
ros1<-fnchk(xtrad, fr, trace=1)
#> Function value at supplied parameters =[1] 24.2
#>  num 24.2
#> NULL
#> [1] TRUE
#> Function at given point= 24.2 
print(ros1)
#> $fval
#> [1] 24.2
#> 
#> $infeasible
#> [1] FALSE
#> 
#> $excode
#> [1] 0
#> 
#> $msg
#> [1] "fnchk OK"
#> 
npar<-2
opros<-list2env(list(fn=fr, gr=NULL, hess=NULL, MAXIMIZE=FALSE, PARSCALE=rep(1,npar), FNSCALE=1,
                     KFN=0, KGR=0, KHESS=0, dots=NULL))
uros1<-fnchk(xtrad, fr, trace=1)
#> Function value at supplied parameters =[1] 24.2
#>  num 24.2
#> NULL
#> [1] TRUE
#> Function at given point= 24.2 
print(uros1)
#> $fval
#> [1] 24.2
#> 
#> $infeasible
#> [1] FALSE
#> 
#> $excode
#> [1] 0
#> 
#> $msg
#> [1] "fnchk OK"
#>